@@ -106,8 +106,8 @@ pub use crate::types::type_alias::TypeAliasType;
106106pub use crate::types::type_form::TypeFormType;
107107pub(crate) use crate::types::typed_dict::TypedDictType;
108108pub(crate) use crate::types::typevar::{
109- BindingContext, BoundTypeVarIdentity, ParamSpecAttrKind, TypeVarBoundOrConstraints ,
110- TypeVarNonce,
109+ BindingContext, BoundTypeVarIdentity, ParamSpecAttrKind, SelfTypeVarOrigin ,
110+ TypeVarBoundOrConstraints, TypeVarNonce,
111111};
112112pub use crate::types::typevar::{BoundTypeVarInstance, TypeVarKind};
113113use crate::types::typevar::{TypeVarInstance, TypeVarSet};
@@ -10000,7 +10000,9 @@ impl<'db> Type<'db> {
1000010000 ) {
1000110001 let matching_typevar = |bound_typevar: &BoundTypeVarInstance<'db>| {
1000210002 match bound_typevar.typevar(db).kind(db) {
10003- TypeVarKind::LegacyTypeVar | TypeVarKind::Pep613Alias | TypeVarKind::TypingSelf
10003+ TypeVarKind::LegacyTypeVar
10004+ | TypeVarKind::Pep613Alias
10005+ | TypeVarKind::TypingSelf { .. }
1000410006 if binding_context.is_none_or(|binding_context| {
1000510007 bound_typevar.binding_context(db)
1000610008 == BindingContext::Definition(binding_context)
@@ -11146,17 +11148,17 @@ pub enum PromotionKind {
1114611148 SingletonsOnly,
1114711149}
1114811150
11149- /// Returns the [`ClassLiteral`] that "owns" a `Self` typevar (i.e., the class from its upper bound) .
11150- fn self_typevar_owner_class_literal <'db>(
11151+ /// Returns the class recorded in a `Self` typevar's origin .
11152+ fn self_typevar_origin_class_literal <'db>(
1115111153 db: &'db dyn Db,
11152- env: &ProgramEnvironment<'db>,
1115311154 bound_typevar: BoundTypeVarInstance<'db>,
1115411155) -> Option<ClassLiteral<'db>> {
11155- bound_typevar
11156- .typevar(db)
11157- .upper_bound(db, env)
11158- .and_then(|ty| ty.nominal_class(db, env))
11159- .map(|class| class.class_literal(db))
11156+ match bound_typevar.kind(db) {
11157+ TypeVarKind::TypingSelf {
11158+ origin: SelfTypeVarOrigin::Class(class),
11159+ } => Some(class),
11160+ _ => None,
11161+ }
1116011162}
1116111163
1116211164#[salsa::tracked(returns(ref), heap_size=ruff_memory_usage::heap_size)]
@@ -11173,8 +11175,8 @@ fn class_mro_literals<'db>(
1117311175
1117411176/// Information needed to bind `Self` typevars to a concrete type.
1117511177///
11176- /// Uses MRO-based matching: a `Self` typevar is bound only if its owner class
11177- /// is in the MRO of the self type 's class .
11178+ /// Uses the binding context and MRO-based matching against the class recorded in a `Self`
11179+ /// typevar 's origin .
1117811180#[derive(Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
1117911181pub struct SelfBinding<'db> {
1118011182 ty: Type<'db>,
@@ -11201,7 +11203,7 @@ impl<'db> SelfBinding<'db> {
1120111203 ) -> Self {
1120211204 let class_literal = match self_type {
1120311205 Type::TypeVar(typevar) if typevar.typevar(db).is_self(db) => {
11204- self_typevar_owner_class_literal (db, env , typevar)
11206+ self_typevar_origin_class_literal (db, typevar)
1120511207 }
1120611208 _ => self_type
1120711209 .nominal_class(db, env)
@@ -11216,12 +11218,7 @@ impl<'db> SelfBinding<'db> {
1121611218 }
1121711219
1121811220 /// Returns whether `bound_typevar` should be replaced by this binding's concrete self type.
11219- fn should_bind(
11220- &self,
11221- db: &'db dyn Db,
11222- env: &ProgramEnvironment<'db>,
11223- bound_typevar: BoundTypeVarInstance<'db>,
11224- ) -> bool {
11221+ fn should_bind(&self, db: &'db dyn Db, bound_typevar: BoundTypeVarInstance<'db>) -> bool {
1122511222 if !bound_typevar.typevar(db).is_self(db) {
1122611223 return false;
1122711224 }
@@ -11232,12 +11229,12 @@ impl<'db> SelfBinding<'db> {
1123211229 return true;
1123311230 }
1123411231
11235- // Check that the Self typevar 's owner class is in the MRO of the self type 's class.
11236- // If we can't determine either class, conservatively don't bind .
11232+ // Check that Self's originating class is in the receiver 's MRO. Receiver placeholders
11233+ // and synthesized TypedDict schemas have no class to restrict matching .
1123711234 self.class_literal.is_some_and(|class_literal| {
1123811235 let class_mro = class_mro_literals(db, class_literal);
11239- self_typevar_owner_class_literal (db, env , bound_typevar)
11240- .is_none_or(|owner_class | class_mro.contains(&owner_class ))
11236+ self_typevar_origin_class_literal (db, bound_typevar)
11237+ .is_none_or(|origin_class | class_mro.contains(&origin_class ))
1124111238 })
1124211239 }
1124311240}
@@ -11274,8 +11271,11 @@ pub enum TypeMapping<'a, 'db> {
1127411271 },
1127511272 /// Binds any `typing.Self` typevar with a particular `self` class.
1127611273 BindSelf(SelfBinding<'db>),
11277- /// Replaces occurrences of `typing.Self` with a new `Self` type variable with the given upper bound.
11278- ReplaceSelf { new_upper_bound: Type<'db> },
11274+ /// Replaces `typing.Self` when adapting a synthesized method to another class or schema.
11275+ ReplaceSelf {
11276+ new_origin: SelfTypeVarOrigin<'db>,
11277+ new_upper_bound: Type<'db>,
11278+ },
1127911279 /// Create the top or bottom materialization of a type.
1128011280 Materialize(MaterializationKind),
1128111281 /// Replace default types in parameters of callables with `Unknown`. This is used to avoid infinite
@@ -11358,23 +11358,25 @@ impl<'db> TypeMapping<'_, 'db> {
1135811358 Some(context)
1135911359 }
1136011360 }
11361- TypeMapping::ReplaceSelf { new_upper_bound } => {
11362- Some(GenericContext::from_typevar_instances(
11363- db,
11364- env,
11365- context.variables(db).map(|typevar| {
11366- if typevar.typevar(db).is_self(db) {
11367- BoundTypeVarInstance::synthetic_self(
11368- db,
11369- *new_upper_bound,
11370- typevar.binding_context(db),
11371- )
11372- } else {
11373- typevar
11374- }
11375- }),
11376- ))
11377- }
11361+ TypeMapping::ReplaceSelf {
11362+ new_origin,
11363+ new_upper_bound,
11364+ } => Some(GenericContext::from_typevar_instances(
11365+ db,
11366+ env,
11367+ context.variables(db).map(|typevar| {
11368+ if typevar.typevar(db).is_self(db) {
11369+ BoundTypeVarInstance::synthetic_self(
11370+ db,
11371+ *new_origin,
11372+ *new_upper_bound,
11373+ typevar.binding_context(db),
11374+ )
11375+ } else {
11376+ typevar
11377+ }
11378+ }),
11379+ )),
1137811380 }
1137911381 }
1138011382
@@ -12652,24 +12654,21 @@ impl<'db> TypeGuardLike<'db> for TypeGuardType<'db> {
1265212654}
1265312655
1265412656/// Walk the MRO of this class and return the last class just before the specified known base.
12655- /// This can be used to determine upper bounds for `Self` type variables on methods that are
12656- /// being added to the given class.
12657+ /// This determines the owner and upper bound of `Self` on synthesized fallback methods.
1265712658///
1265812659/// Preserve the class's specialization so that a method on `Child[int]` has a bound such as
1265912660/// `Base[int]`, rather than retaining the type variable in `Base[T@Child]`.
12660- pub(super) fn determine_upper_bound <'db>(
12661+ pub(super) fn determine_self_class <'db>(
1266112662 db: &'db dyn Db,
12662- env: &ProgramEnvironment<'db>,
1266312663 class: ClassType<'db>,
1266412664 is_known_base: impl Fn(ClassBase<'db>) -> bool,
12665- ) -> Type <'db> {
12666- let upper_bound = class
12665+ ) -> ClassType <'db> {
12666+ class
1266712667 .iter_mro(db)
1266812668 .take_while(|base| !is_known_base(*base))
1266912669 .filter_map(ClassBase::into_class)
1267012670 .last()
12671- .unwrap_or(class);
12672- Type::instance(db, env, upper_bound)
12671+ .unwrap_or(class)
1267312672}
1267412673
1267512674// Make sure that the `Type` enum does not grow unexpectedly.
0 commit comments