mirror of https://github.com/astral-sh/ruff
[ty] Generic implicit types aliases
This commit is contained in:
parent
dd15656deb
commit
013d43a2dd
|
|
@ -79,9 +79,8 @@ async def main():
|
||||||
task("B"),
|
task("B"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: these should be `int`
|
reveal_type(a) # revealed: int
|
||||||
reveal_type(a) # revealed: Unknown
|
reveal_type(b) # revealed: int
|
||||||
reveal_type(b) # revealed: Unknown
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Under the hood
|
## Under the hood
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,8 @@ ListOrTuple = list[T] | tuple[T, ...]
|
||||||
ListOrTupleLegacy = Union[list[T], tuple[T, ...]]
|
ListOrTupleLegacy = Union[list[T], tuple[T, ...]]
|
||||||
MyCallable = Callable[P, T]
|
MyCallable = Callable[P, T]
|
||||||
AnnotatedType = Annotated[T, "tag"]
|
AnnotatedType = Annotated[T, "tag"]
|
||||||
|
TransparentAlias = T
|
||||||
|
MyOptional = T | None
|
||||||
|
|
||||||
# TODO: Consider displaying this as `<class 'list[T]'>`, … instead? (and similar for some others below)
|
# TODO: Consider displaying this as `<class 'list[T]'>`, … instead? (and similar for some others below)
|
||||||
reveal_type(MyList) # revealed: <class 'list[typing.TypeVar]'>
|
reveal_type(MyList) # revealed: <class 'list[typing.TypeVar]'>
|
||||||
|
|
@ -400,43 +402,40 @@ reveal_type(ListOrTuple) # revealed: types.UnionType
|
||||||
reveal_type(ListOrTupleLegacy) # revealed: types.UnionType
|
reveal_type(ListOrTupleLegacy) # revealed: types.UnionType
|
||||||
reveal_type(MyCallable) # revealed: GenericAlias
|
reveal_type(MyCallable) # revealed: GenericAlias
|
||||||
reveal_type(AnnotatedType) # revealed: <typing.Annotated special form>
|
reveal_type(AnnotatedType) # revealed: <typing.Annotated special form>
|
||||||
|
reveal_type(TransparentAlias) # revealed: typing.TypeVar
|
||||||
|
reveal_type(MyOptional) # revealed: types.UnionType
|
||||||
|
|
||||||
def _(
|
def _(
|
||||||
list_of_ints: MyList[int],
|
list_of_ints: MyList[int],
|
||||||
dict_str_to_int: MyDict[str, int],
|
dict_str_to_int: MyDict[str, int],
|
||||||
# TODO: no error here
|
|
||||||
# error: [invalid-type-form] "`typing.TypeVar` is not a generic class"
|
|
||||||
subclass_of_int: MyType[int],
|
subclass_of_int: MyType[int],
|
||||||
int_and_str: IntAndType[str],
|
int_and_str: IntAndType[str],
|
||||||
pair_of_ints: Pair[int],
|
pair_of_ints: Pair[int],
|
||||||
int_and_bytes: Sum[int, bytes],
|
int_and_bytes: Sum[int, bytes],
|
||||||
list_or_tuple: ListOrTuple[int],
|
list_or_tuple: ListOrTuple[int],
|
||||||
list_or_tuple_legacy: ListOrTupleLegacy[int],
|
list_or_tuple_legacy: ListOrTupleLegacy[int],
|
||||||
# TODO: no error here
|
# TODO: no errors here
|
||||||
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `tuple[str, bytes]`?"
|
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `tuple[str, bytes]`?"
|
||||||
|
# error: [too-many-positional-arguments] "Too many positional arguments: expected 1, got 2"
|
||||||
my_callable: MyCallable[[str, bytes], int],
|
my_callable: MyCallable[[str, bytes], int],
|
||||||
annotated_int: AnnotatedType[int],
|
annotated_int: AnnotatedType[int],
|
||||||
|
transparent_alias: TransparentAlias[int],
|
||||||
|
optional_int: MyOptional[int],
|
||||||
):
|
):
|
||||||
# TODO: This should be `list[int]`
|
reveal_type(list_of_ints) # revealed: list[int]
|
||||||
reveal_type(list_of_ints) # revealed: @Todo(specialized generic alias in type expression)
|
reveal_type(dict_str_to_int) # revealed: dict[str, int]
|
||||||
# TODO: This should be `dict[str, int]`
|
reveal_type(subclass_of_int) # revealed: type[int]
|
||||||
reveal_type(dict_str_to_int) # revealed: @Todo(specialized generic alias in type expression)
|
reveal_type(int_and_str) # revealed: tuple[int, str]
|
||||||
# TODO: This should be `type[int]`
|
reveal_type(pair_of_ints) # revealed: tuple[int, int]
|
||||||
reveal_type(subclass_of_int) # revealed: Unknown
|
reveal_type(int_and_bytes) # revealed: tuple[int, bytes]
|
||||||
# TODO: This should be `tuple[int, str]`
|
reveal_type(list_or_tuple) # revealed: list[int] | tuple[int, ...]
|
||||||
reveal_type(int_and_str) # revealed: @Todo(specialized generic alias in type expression)
|
reveal_type(list_or_tuple_legacy) # revealed: list[int] | tuple[int, ...]
|
||||||
# TODO: This should be `tuple[int, int]`
|
reveal_type(list_or_tuple_legacy) # revealed: list[int] | tuple[int, ...]
|
||||||
reveal_type(pair_of_ints) # revealed: @Todo(specialized generic alias in type expression)
|
|
||||||
# TODO: This should be `tuple[int, bytes]`
|
|
||||||
reveal_type(int_and_bytes) # revealed: @Todo(specialized generic alias in type expression)
|
|
||||||
# TODO: This should be `list[int] | tuple[int, ...]`
|
|
||||||
reveal_type(list_or_tuple) # revealed: @Todo(Generic specialization of types.UnionType)
|
|
||||||
# TODO: This should be `list[int] | tuple[int, ...]`
|
|
||||||
reveal_type(list_or_tuple_legacy) # revealed: @Todo(Generic specialization of types.UnionType)
|
|
||||||
# TODO: This should be `(str, bytes) -> int`
|
# TODO: This should be `(str, bytes) -> int`
|
||||||
reveal_type(my_callable) # revealed: @Todo(Generic specialization of typing.Callable)
|
reveal_type(my_callable) # revealed: Unknown
|
||||||
# TODO: This should be `int`
|
reveal_type(annotated_int) # revealed: int
|
||||||
reveal_type(annotated_int) # revealed: @Todo(Generic specialization of typing.Annotated)
|
reveal_type(transparent_alias) # revealed: int
|
||||||
|
reveal_type(optional_int) # revealed: int | None
|
||||||
```
|
```
|
||||||
|
|
||||||
Generic implicit type aliases can be partially specialized:
|
Generic implicit type aliases can be partially specialized:
|
||||||
|
|
@ -446,15 +445,12 @@ U = TypeVar("U")
|
||||||
|
|
||||||
DictStrTo = MyDict[str, U]
|
DictStrTo = MyDict[str, U]
|
||||||
|
|
||||||
reveal_type(DictStrTo) # revealed: GenericAlias
|
reveal_type(DictStrTo) # revealed: <class 'dict[str, typing.TypeVar]'>
|
||||||
|
|
||||||
def _(
|
def _(
|
||||||
# TODO: No error here
|
|
||||||
# error: [invalid-type-form] "Invalid subscript of object of type `GenericAlias` in type expression"
|
|
||||||
dict_str_to_int: DictStrTo[int],
|
dict_str_to_int: DictStrTo[int],
|
||||||
):
|
):
|
||||||
# TODO: This should be `dict[str, int]`
|
reveal_type(dict_str_to_int) # revealed: dict[str, int]
|
||||||
reveal_type(dict_str_to_int) # revealed: Unknown
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Using specializations of generic implicit type aliases in other implicit type aliases works as
|
Using specializations of generic implicit type aliases in other implicit type aliases works as
|
||||||
|
|
@ -465,25 +461,31 @@ IntsOrNone = MyList[int] | None
|
||||||
IntsOrStrs = Pair[int] | Pair[str]
|
IntsOrStrs = Pair[int] | Pair[str]
|
||||||
ListOfPairs = MyList[Pair[str]]
|
ListOfPairs = MyList[Pair[str]]
|
||||||
|
|
||||||
reveal_type(IntsOrNone) # revealed: UnionType
|
reveal_type(IntsOrNone) # revealed: types.UnionType
|
||||||
reveal_type(IntsOrStrs) # revealed: UnionType
|
reveal_type(IntsOrStrs) # revealed: types.UnionType
|
||||||
reveal_type(ListOfPairs) # revealed: GenericAlias
|
reveal_type(ListOfPairs) # revealed: <class 'list[tuple[str, str]]'>
|
||||||
|
|
||||||
def _(
|
def _(
|
||||||
# TODO: This should not be an error
|
|
||||||
# error: [invalid-type-form] "Variable of type `UnionType` is not allowed in a type expression"
|
|
||||||
ints_or_none: IntsOrNone,
|
ints_or_none: IntsOrNone,
|
||||||
# TODO: This should not be an error
|
|
||||||
# error: [invalid-type-form] "Variable of type `UnionType` is not allowed in a type expression"
|
|
||||||
ints_or_strs: IntsOrStrs,
|
ints_or_strs: IntsOrStrs,
|
||||||
list_of_pairs: ListOfPairs,
|
list_of_pairs: ListOfPairs,
|
||||||
):
|
):
|
||||||
# TODO: This should be `list[int] | None`
|
reveal_type(ints_or_none) # revealed: list[int] | None
|
||||||
reveal_type(ints_or_none) # revealed: Unknown
|
reveal_type(ints_or_strs) # revealed: tuple[int, int] | tuple[str, str]
|
||||||
# TODO: This should be `tuple[int, int] | tuple[str, str]`
|
reveal_type(list_of_pairs) # revealed: list[tuple[str, str]]
|
||||||
reveal_type(ints_or_strs) # revealed: Unknown
|
```
|
||||||
# TODO: This should be `list[tuple[str, str]]`
|
|
||||||
reveal_type(list_of_pairs) # revealed: @Todo(Support for `typing.GenericAlias` instances in type expressions)
|
A generic implicit type alias can also be used in another generic implicit type alias:
|
||||||
|
|
||||||
|
```py
|
||||||
|
MyOtherList = MyList[T]
|
||||||
|
|
||||||
|
reveal_type(MyOtherList) # revealed: <class 'list[typing.TypeVar]'>
|
||||||
|
|
||||||
|
def _(
|
||||||
|
list_of_ints: MyOtherList[int],
|
||||||
|
):
|
||||||
|
reveal_type(list_of_ints) # revealed: list[int]
|
||||||
```
|
```
|
||||||
|
|
||||||
If a generic implicit type alias is used unspecialized in a type expression, we treat it as an
|
If a generic implicit type alias is used unspecialized in a type expression, we treat it as an
|
||||||
|
|
@ -522,8 +524,6 @@ reveal_mro(Derived1)
|
||||||
|
|
||||||
GenericBaseAlias = GenericBase[T]
|
GenericBaseAlias = GenericBase[T]
|
||||||
|
|
||||||
# TODO: No error here
|
|
||||||
# error: [non-subscriptable] "Cannot subscript object of type `<class 'GenericBase[typing.TypeVar]'>` with no `__class_getitem__` method"
|
|
||||||
class Derived2(GenericBaseAlias[int]):
|
class Derived2(GenericBaseAlias[int]):
|
||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
@ -533,10 +533,9 @@ A generic alias that is already fully specialized cannot be specialized again:
|
||||||
```py
|
```py
|
||||||
ListOfInts = list[int]
|
ListOfInts = list[int]
|
||||||
|
|
||||||
# TODO: this should be an error
|
# error: [too-many-positional-arguments] "Too many positional arguments: expected 0, got 1"
|
||||||
def _(doubly_specialized: ListOfInts[int]):
|
def _(doubly_specialized: ListOfInts[int]):
|
||||||
# TODO: this should be `Unknown`
|
reveal_type(doubly_specialized) # revealed: Unknown
|
||||||
reveal_type(doubly_specialized) # revealed: @Todo(specialized generic alias in type expression)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Specializing a generic implicit type alias with an incorrect number of type arguments also results
|
Specializing a generic implicit type alias with an incorrect number of type arguments also results
|
||||||
|
|
@ -544,15 +543,13 @@ in an error:
|
||||||
|
|
||||||
```py
|
```py
|
||||||
def _(
|
def _(
|
||||||
# TODO: this should be an error
|
# error: [too-many-positional-arguments] "Too many positional arguments: expected 1, got 2"
|
||||||
list_too_many_args: MyList[int, str],
|
list_too_many_args: MyList[int, str],
|
||||||
# TODO: this should be an error
|
# error: [missing-argument] "No argument provided for required parameter `U`"
|
||||||
dict_too_few_args: MyDict[int],
|
dict_too_few_args: MyDict[int],
|
||||||
):
|
):
|
||||||
# TODO: this should be `Unknown`
|
reveal_type(list_too_many_args) # revealed: Unknown
|
||||||
reveal_type(list_too_many_args) # revealed: @Todo(specialized generic alias in type expression)
|
reveal_type(dict_too_few_args) # revealed: Unknown
|
||||||
# TODO: this should be `Unknown`
|
|
||||||
reveal_type(dict_too_few_args) # revealed: @Todo(specialized generic alias in type expression)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## `Literal`s
|
## `Literal`s
|
||||||
|
|
@ -642,8 +639,7 @@ Deprecated = Annotated[T, "deprecated attribute"]
|
||||||
class C:
|
class C:
|
||||||
old: Deprecated[int]
|
old: Deprecated[int]
|
||||||
|
|
||||||
# TODO: Should be `int`
|
reveal_type(C().old) # revealed: int
|
||||||
reveal_type(C().old) # revealed: @Todo(Generic specialization of typing.Annotated)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If the metadata argument is missing, we emit an error (because this code fails at runtime), but
|
If the metadata argument is missing, we emit an error (because this code fails at runtime), but
|
||||||
|
|
|
||||||
|
|
@ -7198,7 +7198,9 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) => match type_mapping {
|
Type::KnownInstance(known_instance) => match known_instance {
|
||||||
|
KnownInstanceType::TypeVar(typevar) => {
|
||||||
|
match type_mapping {
|
||||||
TypeMapping::BindLegacyTypevars(binding_context) => {
|
TypeMapping::BindLegacyTypevars(binding_context) => {
|
||||||
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
Type::TypeVar(BoundTypeVarInstance::new(db, typevar, *binding_context))
|
||||||
}
|
}
|
||||||
|
|
@ -7210,6 +7212,57 @@ impl<'db> Type<'db> {
|
||||||
TypeMapping::Materialize(_) |
|
TypeMapping::Materialize(_) |
|
||||||
TypeMapping::ReplaceParameterDefaults => self,
|
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) => {
|
Type::FunctionLiteral(function) => {
|
||||||
let function = Type::FunctionLiteral(function.apply_type_mapping_impl(db, type_mapping, tcx, visitor));
|
let function = Type::FunctionLiteral(function.apply_type_mapping_impl(db, type_mapping, tcx, visitor));
|
||||||
|
|
@ -7369,8 +7422,7 @@ impl<'db> Type<'db> {
|
||||||
// some other generic context's specialization is applied to it.
|
// some other generic context's specialization is applied to it.
|
||||||
| Type::ClassLiteral(_)
|
| Type::ClassLiteral(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::SpecialForm(_)
|
| Type::SpecialForm(_) => self,
|
||||||
| Type::KnownInstance(_) => 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::Dynamic(_)
|
||||||
| Type::Never
|
| Type::Never
|
||||||
| Type::AlwaysTruthy
|
| Type::AlwaysTruthy
|
||||||
|
|
@ -7534,7 +7624,6 @@ impl<'db> Type<'db> {
|
||||||
| Type::EnumLiteral(_)
|
| Type::EnumLiteral(_)
|
||||||
| Type::BoundSuper(_)
|
| Type::BoundSuper(_)
|
||||||
| Type::SpecialForm(_)
|
| Type::SpecialForm(_)
|
||||||
| Type::KnownInstance(_)
|
|
||||||
| Type::TypedDict(_) => {}
|
| Type::TypedDict(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10794,6 +10794,12 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
|
|
||||||
fn infer_subscript_load(&mut self, subscript: &ast::ExprSubscript) -> Type<'db> {
|
fn infer_subscript_load(&mut self, subscript: &ast::ExprSubscript) -> Type<'db> {
|
||||||
let value_ty = self.infer_expression(&subscript.value, TypeContext::default());
|
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)
|
self.infer_subscript_load_impl(value_ty, subscript)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use itertools::Either;
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
|
|
||||||
use super::{DeferredExpressionState, TypeInferenceBuilder};
|
use super::{DeferredExpressionState, TypeInferenceBuilder};
|
||||||
|
use crate::FxOrderSet;
|
||||||
use crate::types::diagnostic::{
|
use crate::types::diagnostic::{
|
||||||
self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form,
|
self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form,
|
||||||
report_invalid_arguments_to_callable,
|
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::tuple::{TupleSpecBuilder, TupleType};
|
||||||
use crate::types::visitor::any_over_type;
|
use crate::types::visitor::any_over_type;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
CallableType, DynamicType, IntersectionBuilder, KnownClass, KnownInstanceType,
|
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||||
LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType, Type,
|
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||||
TypeAliasType, TypeContext, TypeIsType, UnionBuilder, UnionType, todo_type,
|
Type, TypeAliasType, TypeContext, TypeIsType, TypeMapping, UnionBuilder, UnionType, todo_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type expressions
|
/// 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(
|
fn infer_subscript_type_expression(
|
||||||
&mut self,
|
&mut self,
|
||||||
subscript: &ast::ExprSubscript,
|
subscript: &ast::ExprSubscript,
|
||||||
|
|
@ -840,10 +884,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
Type::unknown()
|
Type::unknown()
|
||||||
}
|
}
|
||||||
KnownInstanceType::TypeVar(_) => {
|
|
||||||
self.infer_type_expression(slice);
|
|
||||||
todo_type!("TypeVar annotations")
|
|
||||||
}
|
|
||||||
KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => {
|
KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => {
|
||||||
match type_alias.generic_context(self.db()) {
|
match type_alias.generic_context(self.db()) {
|
||||||
Some(generic_context) => {
|
Some(generic_context) => {
|
||||||
|
|
@ -886,11 +926,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
todo_type!("Generic stringified PEP-613 type alias")
|
todo_type!("Generic stringified PEP-613 type alias")
|
||||||
}
|
}
|
||||||
KnownInstanceType::UnionType(_) => {
|
KnownInstanceType::Literal(ty) => {
|
||||||
self.infer_type_expression(slice);
|
|
||||||
todo_type!("Generic specialization of types.UnionType")
|
|
||||||
}
|
|
||||||
KnownInstanceType::Literal(ty) | KnownInstanceType::TypeGenericAlias(ty) => {
|
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||||
builder.into_diagnostic(format_args!(
|
builder.into_diagnostic(format_args!(
|
||||||
|
|
@ -900,13 +936,14 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
Type::unknown()
|
Type::unknown()
|
||||||
}
|
}
|
||||||
KnownInstanceType::Callable(_) => {
|
KnownInstanceType::TypeVar(_) => self
|
||||||
self.infer_type_expression(slice);
|
.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, false),
|
||||||
todo_type!("Generic specialization of typing.Callable")
|
|
||||||
}
|
KnownInstanceType::UnionType(_)
|
||||||
KnownInstanceType::Annotated(_) => {
|
| KnownInstanceType::Callable(_)
|
||||||
self.infer_type_expression(slice);
|
| KnownInstanceType::Annotated(_)
|
||||||
todo_type!("Generic specialization of typing.Annotated")
|
| KnownInstanceType::TypeGenericAlias(_) => {
|
||||||
|
self.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, true)
|
||||||
}
|
}
|
||||||
KnownInstanceType::NewType(newtype) => {
|
KnownInstanceType::NewType(newtype) => {
|
||||||
self.infer_type_expression(&subscript.slice);
|
self.infer_type_expression(&subscript.slice);
|
||||||
|
|
@ -949,11 +986,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::GenericAlias(_) => {
|
Type::GenericAlias(_) => {
|
||||||
self.infer_type_expression(slice);
|
self.infer_explicitly_specialized_implicit_type_alias(subscript, value_ty, true)
|
||||||
// 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")
|
|
||||||
}
|
}
|
||||||
Type::StringLiteral(_) => {
|
Type::StringLiteral(_) => {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue