mirror of https://github.com/astral-sh/ruff
Store binding context
This commit is contained in:
parent
8ed96b04e4
commit
54c88b599d
|
|
@ -442,8 +442,6 @@ def _(
|
|||
Generic implicit type aliases can be partially specialized:
|
||||
|
||||
```py
|
||||
U = TypeVar("U")
|
||||
|
||||
DictStrTo = MyDict[str, U]
|
||||
|
||||
reveal_type(DictStrTo) # revealed: <class 'dict[str, U@DictStrTo]'>
|
||||
|
|
|
|||
|
|
@ -6599,7 +6599,7 @@ impl<'db> Type<'db> {
|
|||
.map(|specialization| {
|
||||
Type::instance(
|
||||
db,
|
||||
generic_origin.apply_specialization(db, |_| specialization),
|
||||
generic_origin.apply_specialization(db, |_| specialization, None),
|
||||
)
|
||||
})
|
||||
.unwrap_or(instance_ty);
|
||||
|
|
@ -7111,7 +7111,11 @@ impl<'db> Type<'db> {
|
|||
pub(crate) fn dunder_class(self, db: &'db dyn Db) -> Type<'db> {
|
||||
if self.is_typed_dict() {
|
||||
return KnownClass::Dict
|
||||
.to_specialized_class_type(db, [KnownClass::Str.to_instance(db), Type::object()])
|
||||
.to_specialized_class_type(
|
||||
db,
|
||||
[KnownClass::Str.to_instance(db), Type::object()],
|
||||
None,
|
||||
)
|
||||
.map(Type::from)
|
||||
// Guard against user-customized typesheds with a broken `dict` class
|
||||
.unwrap_or_else(Type::unknown);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ fn try_mro_cycle_initial<'db>(
|
|||
) -> Result<Mro<'db>, MroError<'db>> {
|
||||
Err(MroError::cycle(
|
||||
db,
|
||||
self_.apply_optional_specialization(db, specialization),
|
||||
self_.apply_optional_specialization(db, specialization, None),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +233,8 @@ impl<'db> CodeGeneratorKind<'db> {
|
|||
pub struct GenericAlias<'db> {
|
||||
pub(crate) origin: ClassLiteral<'db>,
|
||||
pub(crate) specialization: Specialization<'db>,
|
||||
|
||||
pub(crate) binding_context: Option<Definition<'db>>,
|
||||
}
|
||||
|
||||
pub(super) fn walk_generic_alias<'db, V: super::visitor::TypeVisitor<'db> + ?Sized>(
|
||||
|
|
@ -252,6 +254,7 @@ impl<'db> GenericAlias<'db> {
|
|||
db,
|
||||
self.origin(db),
|
||||
self.specialization(db).normalized_impl(db, visitor),
|
||||
self.binding_context(db),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -277,6 +280,7 @@ impl<'db> GenericAlias<'db> {
|
|||
self.origin(db),
|
||||
self.specialization(db)
|
||||
.apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||
self.binding_context(db),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1529,6 +1533,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
self,
|
||||
db: &'db dyn Db,
|
||||
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
match self.generic_context(db) {
|
||||
None => ClassType::NonGeneric(self),
|
||||
|
|
@ -1545,7 +1550,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
ClassType::Generic(GenericAlias::new(db, self, specialization))
|
||||
ClassType::Generic(GenericAlias::new(db, self, specialization, binding_context))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1554,48 +1559,63 @@ impl<'db> ClassLiteral<'db> {
|
|||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: Option<Specialization<'db>>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
specialization
|
||||
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
||||
})
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
specialization
|
||||
.unwrap_or_else(|| generic_context.default_specialization(db, self.known(db)))
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn top_materialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context
|
||||
.default_specialization(db, self.known(db))
|
||||
.materialize_impl(
|
||||
db,
|
||||
MaterializationKind::Top,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
})
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
generic_context
|
||||
.default_specialization(db, self.known(db))
|
||||
.materialize_impl(
|
||||
db,
|
||||
MaterializationKind::Top,
|
||||
&ApplyTypeMappingVisitor::default(),
|
||||
)
|
||||
},
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the default specialization of this class. For non-generic classes, the class is
|
||||
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||
/// applies the default specialization to the class's typevars.
|
||||
pub(crate) fn default_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.default_specialization(db, self.known(db))
|
||||
})
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.default_specialization(db, self.known(db)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the unknown specialization of this class. For non-generic classes, the class is
|
||||
/// returned unchanged. For a non-specialized generic class, we return a generic alias that
|
||||
/// maps each of the class's typevars to `Unknown`.
|
||||
pub(crate) fn unknown_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.unknown_specialization(db)
|
||||
})
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.unknown_specialization(db),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a specialization of this class where each typevar is mapped to itself.
|
||||
pub(crate) fn identity_specialization(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
self.apply_specialization(db, |generic_context| {
|
||||
generic_context.identity_specialization(db)
|
||||
})
|
||||
self.apply_specialization(
|
||||
db,
|
||||
|generic_context| generic_context.identity_specialization(db),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return an iterator over the inferred types of this class's *explicit* bases.
|
||||
|
|
@ -1626,7 +1646,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
|
||||
Box::new([
|
||||
definition_expression_type(db, class_definition, &class_stmt.bases()[0]),
|
||||
Type::from(tuple_type.to_class_type(db)),
|
||||
Type::from(tuple_type.to_class_type(db, None)),
|
||||
])
|
||||
} else {
|
||||
class_stmt
|
||||
|
|
@ -2271,8 +2291,10 @@ impl<'db> ClassLiteral<'db> {
|
|||
|| transformer_params.is_some_and(|params| params.flags(db).contains(param))
|
||||
};
|
||||
|
||||
let instance_ty =
|
||||
Type::instance(db, self.apply_optional_specialization(db, specialization));
|
||||
let instance_ty = Type::instance(
|
||||
db,
|
||||
self.apply_optional_specialization(db, specialization, None),
|
||||
);
|
||||
|
||||
let signature_from_fields = |mut parameters: Vec<_>, return_ty: Option<Type<'db>>| {
|
||||
for (field_name, field) in self.fields(db, specialization, field_policy) {
|
||||
|
|
@ -4787,6 +4809,7 @@ impl KnownClass {
|
|||
self,
|
||||
db: &'db dyn Db,
|
||||
specialization: impl IntoIterator<Item = Type<'db>>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> Option<ClassType<'db>> {
|
||||
let Type::ClassLiteral(class_literal) = self.to_class_literal(db) else {
|
||||
return None;
|
||||
|
|
@ -4808,7 +4831,11 @@ impl KnownClass {
|
|||
return Some(class_literal.default_specialization(db));
|
||||
}
|
||||
|
||||
Some(class_literal.apply_specialization(db, |_| generic_context.specialize(db, types)))
|
||||
Some(class_literal.apply_specialization(
|
||||
db,
|
||||
|_| generic_context.specialize(db, types),
|
||||
binding_context,
|
||||
))
|
||||
}
|
||||
|
||||
/// Lookup a [`KnownClass`] in typeshed and return a [`Type`]
|
||||
|
|
@ -4827,7 +4854,7 @@ impl KnownClass {
|
|||
KnownClass::Tuple,
|
||||
"Use `Type::heterogeneous_tuple` or `Type::homogeneous_tuple` to create `tuple` instances"
|
||||
);
|
||||
self.to_specialized_class_type(db, specialization)
|
||||
self.to_specialized_class_type(db, specialization, None)
|
||||
.and_then(|class_type| Type::from(class_type).to_instance(db))
|
||||
.unwrap_or_else(Type::unknown)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ impl<'db> ClassBase<'db> {
|
|||
db,
|
||||
fields.values().map(|field| field.declared_ty),
|
||||
)?
|
||||
.to_class_type(db)
|
||||
.to_class_type(db, None)
|
||||
.into(),
|
||||
subclass,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4740,8 +4740,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
TargetKind::Single => {
|
||||
// This could be an implicit type alias (OptionalList = list[T] | None). Use the definition
|
||||
// of `OptionalList` as the typevar binding context while inferring the RHS (`list[T] | None`),
|
||||
// in order to bind `T@OptionalList`.
|
||||
// of `OptionalList` as the binding context while inferring the RHS (`list[T] | None`), in
|
||||
// order to bind `T` to `OptionalList`.
|
||||
let previous_typevar_binding_context =
|
||||
self.typevar_binding_context.replace(definition);
|
||||
|
||||
|
|
@ -5531,8 +5531,10 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
self.deferred_state = DeferredExpressionState::Deferred;
|
||||
}
|
||||
|
||||
let previous_typevar_binding_context = self.typevar_binding_context;
|
||||
self.typevar_binding_context = Some(definition);
|
||||
// This might be a PEP-613 type alias (`OptionalList: TypeAlias = list[T] | None`). Use
|
||||
// the definition of `OptionalList` as the binding context while inferring the
|
||||
// RHS (`list[T] | None`), in order to bind `T` to `OptionalList`.
|
||||
let previous_typevar_binding_context = self.typevar_binding_context.replace(definition);
|
||||
|
||||
let inferred_ty = self.infer_maybe_standalone_expression(
|
||||
value,
|
||||
|
|
@ -7498,7 +7500,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
|
||||
let class_type =
|
||||
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context));
|
||||
class_literal.apply_specialization(self.db(), |_| builder.build(generic_context), None);
|
||||
|
||||
Type::from(class_type).to_instance(self.db())
|
||||
}
|
||||
|
|
@ -10808,13 +10810,18 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
fn infer_subscript_load(&mut self, subscript: &ast::ExprSubscript) -> Type<'db> {
|
||||
let value_ty = self.infer_expression(&subscript.value, TypeContext::default());
|
||||
|
||||
// If we have an implicit type alias like `MyList = list[T]`, and if `MyList` is being
|
||||
// used in another implicit type alias like `Numbers = MyList[int]`, then we infer the
|
||||
// right hand side as a value expression, and need to handle the specialization here.
|
||||
if let Some(alias) = value_ty.as_generic_alias() {
|
||||
return self.infer_explicitly_specialized_type_alias(
|
||||
let return_ty = self.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
Some(alias.definition(self.db())),
|
||||
alias.binding_context(self.db()),
|
||||
false,
|
||||
);
|
||||
|
||||
return return_ty;
|
||||
}
|
||||
|
||||
self.infer_subscript_load_impl(value_ty, subscript)
|
||||
|
|
@ -10853,9 +10860,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
let tuple_generic_alias = |db: &'db dyn Db, tuple: Option<TupleType<'db>>| {
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let tuple_generic_alias = |tuple: Option<TupleType<'db>>| {
|
||||
let tuple = tuple.unwrap_or_else(|| TupleType::homogeneous(db, Type::unknown()));
|
||||
Type::from(tuple.to_class_type(db))
|
||||
Type::from(tuple.to_class_type(db, typevar_binding_context))
|
||||
};
|
||||
|
||||
match value_ty {
|
||||
|
|
@ -10867,7 +10876,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
// updating all of the subscript logic below to use custom callables for all of the _other_
|
||||
// special cases, too.
|
||||
if class.is_tuple(self.db()) {
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
return tuple_generic_alias(self.infer_tuple_type_expression(slice));
|
||||
} else if class.is_known(self.db(), KnownClass::Type) {
|
||||
let argument_ty = self.infer_type_expression(slice);
|
||||
return Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||
|
|
@ -10895,7 +10904,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Tuple) => {
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
return tuple_generic_alias(self.infer_tuple_type_expression(slice));
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Literal) => {
|
||||
match self.infer_literal_parameter_type(slice) {
|
||||
|
|
@ -11061,7 +11070,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
.expect("A known stdlib class is available");
|
||||
|
||||
return class
|
||||
.to_specialized_class_type(self.db(), [element_ty])
|
||||
.to_specialized_class_type(
|
||||
self.db(),
|
||||
[element_ty],
|
||||
self.typevar_binding_context,
|
||||
)
|
||||
.map(Type::from)
|
||||
.unwrap_or_else(Type::unknown);
|
||||
}
|
||||
|
|
@ -11119,7 +11132,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
.expect("Stdlib class available");
|
||||
|
||||
return class
|
||||
.to_specialized_class_type(self.db(), [first_ty, second_ty])
|
||||
.to_specialized_class_type(
|
||||
self.db(),
|
||||
[first_ty, second_ty],
|
||||
self.typevar_binding_context,
|
||||
)
|
||||
.map(Type::from)
|
||||
.unwrap_or_else(Type::unknown);
|
||||
}
|
||||
|
|
@ -11166,10 +11183,13 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
generic_context: GenericContext<'db>,
|
||||
) -> Type<'db> {
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let specialize = |types: &[Option<Type<'db>>]| {
|
||||
Type::from(generic_class.apply_specialization(db, |_| {
|
||||
generic_context.specialize_partial(db, types.iter().copied())
|
||||
}))
|
||||
Type::from(generic_class.apply_specialization(
|
||||
db,
|
||||
|_| generic_context.specialize_partial(db, types.iter().copied()),
|
||||
typevar_binding_context,
|
||||
))
|
||||
};
|
||||
|
||||
self.infer_explicit_callable_specialization(
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ use crate::types::string_annotation::parse_string_annotation;
|
|||
use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
||||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||
Type, TypeAliasType, TypeContext, TypeIsType, TypeMapping, UnionBuilder, UnionType, todo_type,
|
||||
BindingContext, CallableType, DynamicType, GenericAlias, GenericContext, IntersectionBuilder,
|
||||
KnownClass, KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType,
|
||||
SubclassOfType, Type, TypeAliasType, TypeContext, TypeInContext, TypeIsType, TypeMapping,
|
||||
UnionBuilder, UnionType, todo_type,
|
||||
};
|
||||
|
||||
/// Type expressions
|
||||
|
|
@ -712,13 +713,20 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
match class_literal.generic_context(self.db()) {
|
||||
Some(generic_context) => {
|
||||
let db = self.db();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let specialize = |types: &[Option<Type<'db>>]| {
|
||||
SubclassOfType::from(
|
||||
db,
|
||||
class_literal.apply_specialization(db, |_| {
|
||||
generic_context
|
||||
.specialize_partial(db, types.iter().copied())
|
||||
}),
|
||||
class_literal.apply_specialization(
|
||||
db,
|
||||
|_| {
|
||||
generic_context.specialize_partial(
|
||||
db,
|
||||
types.iter().copied(),
|
||||
)
|
||||
},
|
||||
typevar_binding_context,
|
||||
),
|
||||
)
|
||||
};
|
||||
self.infer_explicit_callable_specialization(
|
||||
|
|
@ -756,7 +764,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
pub(crate) fn infer_explicitly_specialized_type_alias(
|
||||
&mut self,
|
||||
subscript: &ast::ExprSubscript,
|
||||
value_ty: Type<'db>,
|
||||
mut value_ty: Type<'db>,
|
||||
typevar_binding_context: Option<Definition<'db>>,
|
||||
in_type_expression: bool,
|
||||
) -> Type<'db> {
|
||||
|
|
@ -773,30 +781,52 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
return Type::unknown();
|
||||
};
|
||||
|
||||
let generic_type_alias = value_ty.apply_type_mapping(
|
||||
db,
|
||||
&TypeMapping::BindLegacyTypevars(BindingContext::Definition(typevar_binding_context)),
|
||||
TypeContext::default(),
|
||||
);
|
||||
if let Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) = value_ty
|
||||
&& let Some(definition) = typevar.definition(db)
|
||||
{
|
||||
value_ty = value_ty.apply_type_mapping(
|
||||
db,
|
||||
&TypeMapping::BindLegacyTypevars(BindingContext::Definition(definition)),
|
||||
TypeContext::default(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut variables = FxOrderSet::default();
|
||||
generic_type_alias.find_legacy_typevars(db, None, &mut variables);
|
||||
value_ty.find_legacy_typevars(db, Some(typevar_binding_context), &mut variables);
|
||||
let generic_context = GenericContext::from_typevar_instances(db, variables);
|
||||
|
||||
let scope_id = self.scope();
|
||||
let typevar_binding_context = self.typevar_binding_context;
|
||||
let current_typevar_binding_context = self.typevar_binding_context;
|
||||
let specialize = |types: &[Option<Type<'db>>]| {
|
||||
let specialized = generic_type_alias.apply_specialization(
|
||||
let specialized = value_ty.apply_specialization(
|
||||
db,
|
||||
generic_context.specialize_partial(db, types.iter().copied()),
|
||||
);
|
||||
|
||||
if in_type_expression {
|
||||
specialized
|
||||
.in_type_expression(db, scope_id, typevar_binding_context)
|
||||
.in_type_expression(db, scope_id, current_typevar_binding_context)
|
||||
.unwrap_or_else(|_| Type::unknown())
|
||||
} else {
|
||||
specialized
|
||||
// Update the binding context
|
||||
match specialized {
|
||||
Type::GenericAlias(alias) => Type::GenericAlias(GenericAlias::new(
|
||||
db,
|
||||
alias.origin(db),
|
||||
alias.specialization(db),
|
||||
current_typevar_binding_context,
|
||||
)),
|
||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(instance)) => {
|
||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||
TypeInContext::new(
|
||||
db,
|
||||
instance.inner(db),
|
||||
current_typevar_binding_context,
|
||||
),
|
||||
))
|
||||
}
|
||||
_ => specialized,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1022,7 +1052,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
Type::GenericAlias(alias) => self.infer_explicitly_specialized_type_alias(
|
||||
subscript,
|
||||
value_ty,
|
||||
Some(alias.definition(self.db())),
|
||||
alias.binding_context(self.db()),
|
||||
true,
|
||||
),
|
||||
Type::StringLiteral(_) => {
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ pub(super) fn walk_nominal_instance_type<'db, V: super::visitor::TypeVisitor<'db
|
|||
impl<'db> NominalInstanceType<'db> {
|
||||
pub(super) fn class(&self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
match self.0 {
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db),
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db, None),
|
||||
NominalInstanceInner::NonTuple(class) => class,
|
||||
NominalInstanceInner::Object => KnownClass::Object
|
||||
.try_to_class_literal(db)
|
||||
|
|
@ -224,7 +224,7 @@ impl<'db> NominalInstanceType<'db> {
|
|||
|
||||
pub(super) fn class_literal(&self, db: &'db dyn Db) -> ClassLiteral<'db> {
|
||||
let class = match self.0 {
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db),
|
||||
NominalInstanceInner::ExactTuple(tuple) => tuple.to_class_type(db, None),
|
||||
NominalInstanceInner::NonTuple(class) => class,
|
||||
NominalInstanceInner::Object => {
|
||||
return KnownClass::Object
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ impl<'db> Mro<'db> {
|
|||
class_literal: ClassLiteral<'db>,
|
||||
specialization: Option<Specialization<'db>>,
|
||||
) -> Result<Self, MroError<'db>> {
|
||||
let class = class_literal.apply_optional_specialization(db, specialization);
|
||||
let class = class_literal.apply_optional_specialization(db, specialization, None);
|
||||
// Special-case `NotImplementedType`: typeshed says that it inherits from `Any`,
|
||||
// but this causes more problems than it fixes.
|
||||
if class_literal.is_known(db, KnownClass::NotImplementedType) {
|
||||
|
|
@ -412,10 +412,11 @@ impl<'db> Iterator for MroIterator<'db> {
|
|||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if !self.first_element_yielded {
|
||||
self.first_element_yielded = true;
|
||||
return Some(ClassBase::Class(
|
||||
self.class
|
||||
.apply_optional_specialization(self.db, self.specialization),
|
||||
));
|
||||
return Some(ClassBase::Class(self.class.apply_optional_specialization(
|
||||
self.db,
|
||||
self.specialization,
|
||||
None,
|
||||
)));
|
||||
}
|
||||
self.full_mro_except_first_element().next()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,19 +202,27 @@ impl<'db> TupleType<'db> {
|
|||
// `static-frame` as part of a mypy_primer run! This is because it's called
|
||||
// from `NominalInstanceType::class()`, which is a very hot method.
|
||||
#[salsa::tracked(cycle_initial=to_class_type_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn to_class_type(self, db: &'db dyn Db) -> ClassType<'db> {
|
||||
pub(crate) fn to_class_type(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
let element_type = self.tuple(db).homogeneous_element_type(db);
|
||||
generic_context.specialize_tuple(db, element_type, self)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
})
|
||||
tuple_class.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
let element_type = self.tuple(db).homogeneous_element_type(db);
|
||||
generic_context.specialize_tuple(db, element_type, self)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return a normalized version of `self`.
|
||||
|
|
@ -294,18 +302,23 @@ fn to_class_type_cycle_initial<'db>(
|
|||
db: &'db dyn Db,
|
||||
_id: salsa::Id,
|
||||
self_: TupleType<'db>,
|
||||
binding_context: Option<Definition<'db>>,
|
||||
) -> ClassType<'db> {
|
||||
let tuple_class = KnownClass::Tuple
|
||||
.try_to_class_literal(db)
|
||||
.expect("Typeshed should always have a `tuple` class in `builtins.pyi`");
|
||||
|
||||
tuple_class.apply_specialization(db, |generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
generic_context.specialize_tuple(db, Type::Never, self_)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
})
|
||||
tuple_class.apply_specialization(
|
||||
db,
|
||||
|generic_context| {
|
||||
if generic_context.variables(db).len() == 1 {
|
||||
generic_context.specialize_tuple(db, Type::Never, self_)
|
||||
} else {
|
||||
generic_context.default_specialization(db, Some(KnownClass::Tuple))
|
||||
}
|
||||
},
|
||||
binding_context,
|
||||
)
|
||||
}
|
||||
|
||||
/// A tuple spec describes the contents of a tuple type, which might be fixed- or variable-length.
|
||||
|
|
|
|||
Loading…
Reference in New Issue