[ty] Generic implicit types aliases
This commit is contained in:
@@ -7198,17 +7198,70 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
|
||||
TypeMapping::BindLegacyTypevars(binding_context) => {
|
||||
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
||||
Type::KnownInstance(known_instance) => match known_instance {
|
||||
KnownInstanceType::TypeVar(typevar) => {
|
||||
match type_mapping {
|
||||
TypeMapping::BindLegacyTypevars(binding_context) => {
|
||||
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
||||
}
|
||||
TypeMapping::Specialization(_) |
|
||||
TypeMapping::PartialSpecialization(_) |
|
||||
TypeMapping::PromoteLiterals(_) |
|
||||
TypeMapping::BindSelf(_) |
|
||||
TypeMapping::ReplaceSelf { .. } |
|
||||
TypeMapping::Materialize(_) |
|
||||
TypeMapping::ReplaceParameterDefaults => self,
|
||||
}
|
||||
}
|
||||
TypeMapping::Specialization(_) |
|
||||
TypeMapping::PartialSpecialization(_) |
|
||||
TypeMapping::PromoteLiterals(_) |
|
||||
TypeMapping::BindSelf(_) |
|
||||
TypeMapping::ReplaceSelf { .. } |
|
||||
TypeMapping::Materialize(_) |
|
||||
TypeMapping::ReplaceParameterDefaults => self,
|
||||
KnownInstanceType::UnionType(instance) => {
|
||||
if let Ok(union_type) = instance.union_type(db) {
|
||||
Type::KnownInstance(KnownInstanceType::UnionType(
|
||||
UnionTypeInstance::new(
|
||||
db,
|
||||
instance._value_expr_types(db),
|
||||
Ok(union_type.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
|
||||
)
|
||||
)))
|
||||
} else {
|
||||
self
|
||||
}
|
||||
},
|
||||
KnownInstanceType::Annotated(ty) => {
|
||||
Type::KnownInstance(KnownInstanceType::Annotated(
|
||||
InternedType::new(
|
||||
db,
|
||||
ty.inner(db).apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||
)
|
||||
))
|
||||
},
|
||||
KnownInstanceType::Callable(callable_type) => {
|
||||
Type::KnownInstance(KnownInstanceType::Callable(
|
||||
callable_type.apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||
))
|
||||
},
|
||||
KnownInstanceType::TypeGenericAlias(ty) => {
|
||||
Type::KnownInstance(KnownInstanceType::TypeGenericAlias(
|
||||
InternedType::new(
|
||||
db,
|
||||
ty.inner(db).apply_type_mapping_impl(db, type_mapping, tcx, visitor),
|
||||
)
|
||||
))
|
||||
},
|
||||
|
||||
KnownInstanceType::SubscriptedProtocol(_) |
|
||||
KnownInstanceType::SubscriptedGeneric(_) |
|
||||
KnownInstanceType::TypeAliasType(_) |
|
||||
KnownInstanceType::Deprecated(_) |
|
||||
KnownInstanceType::Field(_) |
|
||||
KnownInstanceType::ConstraintSet(_) |
|
||||
KnownInstanceType::GenericContext(_) |
|
||||
KnownInstanceType::Specialization(_) |
|
||||
KnownInstanceType::Literal(_) |
|
||||
KnownInstanceType::LiteralStringAlias(_) |
|
||||
KnownInstanceType::NewType(_) => {
|
||||
// TODO: ?
|
||||
self
|
||||
},
|
||||
}
|
||||
|
||||
Type::FunctionLiteral(function) => {
|
||||
@@ -7369,8 +7422,7 @@ impl<'db> Type<'db> {
|
||||
// some other generic context's specialization is applied to it.
|
||||
| Type::ClassLiteral(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::KnownInstance(_) => self,
|
||||
| Type::SpecialForm(_) => self,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7507,6 +7559,44 @@ impl<'db> Type<'db> {
|
||||
});
|
||||
}
|
||||
|
||||
Type::KnownInstance(known_instance) => match known_instance {
|
||||
KnownInstanceType::UnionType(instance) => {
|
||||
if let Ok(union_type) = instance.union_type(db) {
|
||||
union_type.find_legacy_typevars_impl(
|
||||
db,
|
||||
binding_context,
|
||||
typevars,
|
||||
visitor,
|
||||
);
|
||||
}
|
||||
}
|
||||
KnownInstanceType::Annotated(ty) => {
|
||||
ty.inner(db)
|
||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
KnownInstanceType::Callable(callable_type) => {
|
||||
callable_type.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
KnownInstanceType::TypeGenericAlias(ty) => {
|
||||
ty.inner(db)
|
||||
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
|
||||
}
|
||||
KnownInstanceType::SubscriptedProtocol(_)
|
||||
| KnownInstanceType::SubscriptedGeneric(_)
|
||||
| KnownInstanceType::TypeVar(_)
|
||||
| KnownInstanceType::TypeAliasType(_)
|
||||
| KnownInstanceType::Deprecated(_)
|
||||
| KnownInstanceType::Field(_)
|
||||
| KnownInstanceType::ConstraintSet(_)
|
||||
| KnownInstanceType::GenericContext(_)
|
||||
| KnownInstanceType::Specialization(_)
|
||||
| KnownInstanceType::Literal(_)
|
||||
| KnownInstanceType::LiteralStringAlias(_)
|
||||
| KnownInstanceType::NewType(_) => {
|
||||
// TODO?
|
||||
}
|
||||
},
|
||||
|
||||
Type::Dynamic(_)
|
||||
| Type::Never
|
||||
| Type::AlwaysTruthy
|
||||
@@ -7534,7 +7624,6 @@ impl<'db> Type<'db> {
|
||||
| Type::EnumLiteral(_)
|
||||
| Type::BoundSuper(_)
|
||||
| Type::SpecialForm(_)
|
||||
| Type::KnownInstance(_)
|
||||
| Type::TypedDict(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10794,6 +10794,12 @@ 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 value_ty.is_generic_alias() {
|
||||
return self
|
||||
.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, false);
|
||||
}
|
||||
|
||||
self.infer_subscript_load_impl(value_ty, subscript)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use itertools::Either;
|
||||
use ruff_python_ast as ast;
|
||||
|
||||
use super::{DeferredExpressionState, TypeInferenceBuilder};
|
||||
use crate::FxOrderSet;
|
||||
use crate::types::diagnostic::{
|
||||
self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form,
|
||||
report_invalid_arguments_to_callable,
|
||||
@@ -11,9 +12,9 @@ use crate::types::string_annotation::parse_string_annotation;
|
||||
use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
||||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
CallableType, DynamicType, IntersectionBuilder, KnownClass, KnownInstanceType,
|
||||
LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType, Type,
|
||||
TypeAliasType, TypeContext, TypeIsType, UnionBuilder, UnionType, todo_type,
|
||||
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||
Type, TypeAliasType, TypeContext, TypeIsType, TypeMapping, UnionBuilder, UnionType, todo_type,
|
||||
};
|
||||
|
||||
/// Type expressions
|
||||
@@ -750,6 +751,49 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn infer_explicitly_specialized_implicit_type_alias(
|
||||
&mut self,
|
||||
subscript: &ast::ExprSubscript,
|
||||
value_ty: Type<'db>,
|
||||
in_type_expression: bool,
|
||||
) -> Type<'db> {
|
||||
let db = self.db();
|
||||
|
||||
let generic_type_alias = value_ty.apply_type_mapping(
|
||||
db,
|
||||
&TypeMapping::BindLegacyTypevars(BindingContext::Synthetic),
|
||||
TypeContext::default(),
|
||||
);
|
||||
|
||||
let mut variables = FxOrderSet::default();
|
||||
generic_type_alias.find_legacy_typevars(db, None, &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 specialize = |types: &[Option<Type<'db>>]| {
|
||||
let specialized = generic_type_alias.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)
|
||||
.unwrap_or_else(|_| Type::unknown())
|
||||
} else {
|
||||
specialized
|
||||
}
|
||||
};
|
||||
|
||||
self.infer_explicit_callable_specialization(
|
||||
subscript,
|
||||
value_ty,
|
||||
generic_context,
|
||||
specialize,
|
||||
)
|
||||
}
|
||||
|
||||
fn infer_subscript_type_expression(
|
||||
&mut self,
|
||||
subscript: &ast::ExprSubscript,
|
||||
@@ -840,10 +884,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::TypeVar(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("TypeVar annotations")
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => {
|
||||
match type_alias.generic_context(self.db()) {
|
||||
Some(generic_context) => {
|
||||
@@ -886,11 +926,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic stringified PEP-613 type alias")
|
||||
}
|
||||
KnownInstanceType::UnionType(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic specialization of types.UnionType")
|
||||
}
|
||||
KnownInstanceType::Literal(ty) | KnownInstanceType::TypeGenericAlias(ty) => {
|
||||
KnownInstanceType::Literal(ty) => {
|
||||
self.infer_type_expression(slice);
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||
builder.into_diagnostic(format_args!(
|
||||
@@ -900,13 +936,14 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::Callable(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic specialization of typing.Callable")
|
||||
}
|
||||
KnownInstanceType::Annotated(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic specialization of typing.Annotated")
|
||||
KnownInstanceType::TypeVar(_) => self
|
||||
.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, false),
|
||||
|
||||
KnownInstanceType::UnionType(_)
|
||||
| KnownInstanceType::Callable(_)
|
||||
| KnownInstanceType::Annotated(_)
|
||||
| KnownInstanceType::TypeGenericAlias(_) => {
|
||||
self.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, true)
|
||||
}
|
||||
KnownInstanceType::NewType(newtype) => {
|
||||
self.infer_type_expression(&subscript.slice);
|
||||
@@ -949,11 +986,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
}
|
||||
Type::GenericAlias(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
// If the generic alias is already fully specialized, this is an error. But it
|
||||
// could have been specialized with another typevar (e.g. a type alias like `MyList
|
||||
// = list[T]`), in which case it's later valid to do `MyList[int]`.
|
||||
todo_type!("specialized generic alias in type expression")
|
||||
self.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, true)
|
||||
}
|
||||
Type::StringLiteral(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
|
||||
Reference in New Issue
Block a user