diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md new file mode 100644 index 0000000000000..452fa9f015e24 --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/stdlib_typing_aliases.md @@ -0,0 +1,83 @@ +# Typing-module aliases to other stdlib classes + +The `typing` module has various aliases to other stdlib classes. These are a legacy feature, but +still need to be supported by a type checker. + +## Currently unsupported + +Support for most of these symbols is currently a TODO: + +```py +import typing + +def f( + a: typing.List, + b: typing.List[int], + c: typing.Dict, + d: typing.Dict[int, str], + e: typing.DefaultDict, + f: typing.DefaultDict[str, int], + g: typing.Set, + h: typing.Set[int], + i: typing.FrozenSet, + j: typing.FrozenSet[str], + k: typing.OrderedDict, + l: typing.OrderedDict[int, str], + m: typing.Counter, + n: typing.Counter[int], +): + reveal_type(a) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(b) # revealed: @Todo(typing.List alias) + reveal_type(c) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(d) # revealed: @Todo(typing.Dict alias) + reveal_type(e) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(f) # revealed: @Todo(typing.DefaultDict[] alias) + reveal_type(g) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(h) # revealed: @Todo(typing.Set alias) + reveal_type(i) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(j) # revealed: @Todo(typing.FrozenSet alias) + reveal_type(k) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(l) # revealed: @Todo(typing.OrderedDict alias) + reveal_type(m) # revealed: @Todo(Unsupported or invalid type in a type expression) + reveal_type(n) # revealed: @Todo(typing.Counter[] alias) +``` + +## Inheritance + +The aliases can be inherited from. Some of these are still partially or wholly TODOs. + +```py +import typing + +class A(typing.Dict): ... + +# TODO: should have `Generic`, should not have `Unknown` +reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[dict], Unknown, Literal[object]] + +class B(typing.List): ... + +# TODO: should have `Generic`, should not have `Unknown` +reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[list], Unknown, Literal[object]] + +class C(typing.Set): ... + +# TODO: should have `Generic`, should not have `Unknown` +reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[set], Unknown, Literal[object]] + +class D(typing.FrozenSet): ... + +# TODO: should have `Generic`, should not have `Unknown` +reveal_type(D.__mro__) # revealed: tuple[Literal[D], Literal[frozenset], Unknown, Literal[object]] + +class E(typing.DefaultDict): ... + +reveal_type(E.__mro__) # revealed: tuple[Literal[E], @Todo(Support for more typing aliases as base classes), Literal[object]] + +class F(typing.OrderedDict): ... + +reveal_type(F.__mro__) # revealed: tuple[Literal[F], @Todo(Support for more typing aliases as base classes), Literal[object]] + +class G(typing.Counter): ... + +reveal_type(G.__mro__) # revealed: tuple[Literal[G], @Todo(Support for more typing aliases as base classes), Literal[object]] +``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md new file mode 100644 index 0000000000000..a66220e8d7dec --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md @@ -0,0 +1,71 @@ +# Unsupported special forms + +## Not yet supported + +Several special forms are unsupported by red-knot currently. However, we also don't emit +false-positive errors if you use one in an annotation: + +```py +from typing_extensions import Self, TypeVarTuple, Unpack, TypeGuard, TypeIs, Concatenate, ParamSpec, TypeAlias, Callable, TypeVar + +P = ParamSpec("P") +Ts = TypeVarTuple("Ts") +R_co = TypeVar("R_co", covariant=True) + +Alias: TypeAlias = int + +def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]: + # TODO: should understand the annotation + reveal_type(args) # revealed: tuple + + reveal_type(Alias) # revealed: @Todo(Unsupported or invalid type in a type expression) + +def g() -> TypeGuard[int]: ... +def h() -> TypeIs[int]: ... +def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.kwargs) -> R_co: + # TODO: should understand the annotation + reveal_type(args) # revealed: tuple + + # TODO: should understand the annotation + reveal_type(kwargs) # revealed: dict + + return callback(42, *args, **kwargs) + +class Foo: + def method(self, x: Self): + reveal_type(x) # revealed: @Todo(Unsupported or invalid type in a type expression) +``` + +## Inheritance + +You can't inherit from most of these. `typing.Callable` is an exception. + +```py +from typing import Callable +from typing_extensions import Self, Unpack, TypeGuard, TypeIs, Concatenate + +class A(Self): ... # error: [invalid-base] +class B(Unpack): ... # error: [invalid-base] +class C(TypeGuard): ... # error: [invalid-base] +class D(TypeIs): ... # error: [invalid-base] +class E(Concatenate): ... # error: [invalid-base] +class F(Callable): ... + +reveal_type(F.__mro__) # revealed: tuple[Literal[F], @Todo(Support for more typing aliases as base classes), Literal[object]] +``` + +## Subscriptability + +Some of these are not subscriptable: + +```py +from typing_extensions import Self, TypeAlias + +X: TypeAlias[T] = int # error: [invalid-type-parameter] + +class Foo[T]: + # error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter" + # error: [invalid-type-parameter] "Special form `typing.Self` expected no type parameter" + def method(self: Self[int]) -> Self[int]: + reveal_type(self) # revealed: Unknown +``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md new file mode 100644 index 0000000000000..0a61157d62d9d --- /dev/null +++ b/crates/red_knot_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md @@ -0,0 +1,37 @@ +# Unsupported type qualifiers + +## Not yet supported + +Several type qualifiers are unsupported by red-knot currently. However, we also don't emit +false-positive errors if you use one in an annotation: + +```py +from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly, TypedDict + +X: Final = 42 +Y: Final[int] = 42 + +class Foo: + A: ClassVar[int] = 42 + +# TODO: `TypedDict` is actually valid as a base +# error: [invalid-base] +class Bar(TypedDict): + x: Required[int] + y: NotRequired[str] + z: ReadOnly[bytes] +``` + +## Inheritance + +You can't inherit from a type qualifier. + +```py +from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly + +class A(Final): ... # error: [invalid-base] +class B(ClassVar): ... # error: [invalid-base] +class C(Required): ... # error: [invalid-base] +class D(NotRequired): ... # error: [invalid-base] +class E(ReadOnly): ... # error: [invalid-base] +``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 3047c8adcf144..390df3ee05362 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -1255,6 +1255,7 @@ impl<'db> Type<'db> { | KnownClass::List | KnownClass::Tuple | KnownClass::Set + | KnownClass::FrozenSet | KnownClass::Dict | KnownClass::Slice | KnownClass::BaseException @@ -1263,6 +1264,7 @@ impl<'db> Type<'db> { | KnownClass::ModuleType | KnownClass::FunctionType | KnownClass::SpecialForm + | KnownClass::StdlibAlias | KnownClass::TypeVar, ) => false, None => false, @@ -1782,7 +1784,8 @@ impl<'db> Type<'db> { } Type::KnownInstance(KnownInstanceType::LiteralString) => Type::LiteralString, Type::KnownInstance(KnownInstanceType::Any) => Type::Any, - _ => todo_type!(), + Type::Todo(_) => *self, + _ => todo_type!("Unsupported or invalid type in a type expression"), } } @@ -1934,6 +1937,7 @@ pub enum KnownClass { List, Tuple, Set, + FrozenSet, Dict, Slice, BaseException, @@ -1945,6 +1949,7 @@ pub enum KnownClass { // Typeshed NoneType, // Part of `types` for Python >= 3.10 // Typing + StdlibAlias, SpecialForm, TypeVar, TypeAliasType, @@ -1962,6 +1967,7 @@ impl<'db> KnownClass { Self::Tuple => "tuple", Self::Int => "int", Self::Float => "float", + Self::FrozenSet => "frozenset", Self::Str => "str", Self::Set => "set", Self::Dict => "dict", @@ -1978,6 +1984,8 @@ impl<'db> KnownClass { Self::TypeVar => "TypeVar", Self::TypeAliasType => "TypeAliasType", Self::NoDefaultType => "_NoDefaultType", + // For example, `typing.List` is defined as `List = _Alias()` in typeshed + Self::StdlibAlias => "_Alias", // This is the name the type of `sys.version_info` has in typeshed, // which is different to what `type(sys.version_info).__name__` is at runtime. // (At runtime, `type(sys.version_info).__name__ == "version_info"`, @@ -2016,6 +2024,7 @@ impl<'db> KnownClass { | Self::List | Self::Tuple | Self::Set + | Self::FrozenSet | Self::Dict | Self::BaseException | Self::BaseExceptionGroup @@ -2023,7 +2032,9 @@ impl<'db> KnownClass { Self::VersionInfo => CoreStdlibModule::Sys, Self::GenericAlias | Self::ModuleType | Self::FunctionType => CoreStdlibModule::Types, Self::NoneType => CoreStdlibModule::Typeshed, - Self::SpecialForm | Self::TypeVar | Self::TypeAliasType => CoreStdlibModule::Typing, + Self::SpecialForm | Self::TypeVar | Self::TypeAliasType | Self::StdlibAlias => { + CoreStdlibModule::Typing + } Self::NoDefaultType => { let python_version = Program::get(db).target_version(db); @@ -2054,6 +2065,7 @@ impl<'db> KnownClass { | Self::Float | Self::Str | Self::Set + | Self::FrozenSet | Self::Dict | Self::List | Self::Type @@ -2062,6 +2074,7 @@ impl<'db> KnownClass { | Self::ModuleType | Self::FunctionType | Self::SpecialForm + | Self::StdlibAlias | Self::BaseException | Self::BaseExceptionGroup | Self::TypeVar => false, @@ -2082,6 +2095,7 @@ impl<'db> KnownClass { "float" => Self::Float, "str" => Self::Str, "set" => Self::Set, + "frozenset" => Self::FrozenSet, "dict" => Self::Dict, "list" => Self::List, "slice" => Self::Slice, @@ -2092,6 +2106,7 @@ impl<'db> KnownClass { "ModuleType" => Self::ModuleType, "FunctionType" => Self::FunctionType, "TypeAliasType" => Self::TypeAliasType, + "_Alias" => Self::StdlibAlias, "_SpecialForm" => Self::SpecialForm, "_NoDefaultType" => Self::NoDefaultType, "_version_info" => Self::VersionInfo, @@ -2118,9 +2133,11 @@ impl<'db> KnownClass { | Self::List | Self::Tuple | Self::Set + | Self::FrozenSet | Self::Dict | Self::Slice | Self::GenericAlias + | Self::StdlibAlias // no equivalent class exists in typing_extensions, nor ever will | Self::ModuleType | Self::VersionInfo | Self::BaseException @@ -2159,6 +2176,30 @@ pub enum KnownInstanceType<'db> { TypeVar(TypeVarInstance<'db>), /// A single instance of `typing.TypeAliasType` (PEP 695 type alias) TypeAliasType(TypeAliasType<'db>), + + // Various special forms, special aliases and type qualifiers that we don't yet understand + // (all currently inferred as TODO in most contexts): + TypingSelf, + Final, + ClassVar, + Callable, + Concatenate, + Unpack, + Required, + NotRequired, + TypeAlias, + TypeGuard, + TypeIs, + List, + Dict, + DefaultDict, + Set, + FrozenSet, + Counter, + Deque, + ChainMap, + OrderedDict, + ReadOnly, // TODO: fill this enum out with more special forms, etc. } @@ -2176,6 +2217,27 @@ impl<'db> KnownInstanceType<'db> { Self::Tuple => "Tuple", Self::Type => "Type", Self::TypeAliasType(_) => "TypeAliasType", + Self::TypingSelf => "Self", + Self::Final => "Final", + Self::ClassVar => "ClassVar", + Self::Callable => "Callable", + Self::Concatenate => "Concatenate", + Self::Unpack => "Unpack", + Self::Required => "Required", + Self::NotRequired => "NotRequired", + Self::TypeAlias => "TypeAlias", + Self::TypeGuard => "TypeGuard", + Self::TypeIs => "TypeIs", + Self::List => "List", + Self::Dict => "Dict", + Self::DefaultDict => "DefaultDict", + Self::Set => "Set", + Self::FrozenSet => "FrozenSet", + Self::Counter => "Counter", + Self::Deque => "Deque", + Self::ChainMap => "ChainMap", + Self::OrderedDict => "OrderedDict", + Self::ReadOnly => "ReadOnly", } } @@ -2192,6 +2254,27 @@ impl<'db> KnownInstanceType<'db> { | Self::Any | Self::Tuple | Self::Type + | Self::TypingSelf + | Self::Final + | Self::ClassVar + | Self::Callable + | Self::Concatenate + | Self::Unpack + | Self::Required + | Self::NotRequired + | Self::TypeAlias + | Self::TypeGuard + | Self::TypeIs + | Self::List + | Self::Dict + | Self::DefaultDict + | Self::Set + | Self::FrozenSet + | Self::Counter + | Self::Deque + | Self::ChainMap + | Self::OrderedDict + | Self::ReadOnly | Self::TypeAliasType(_) => Truthiness::AlwaysTrue, } } @@ -2208,6 +2291,27 @@ impl<'db> KnownInstanceType<'db> { Self::Any => "typing.Any", Self::Tuple => "typing.Tuple", Self::Type => "typing.Type", + Self::TypingSelf => "typing.Self", + Self::Final => "typing.Final", + Self::ClassVar => "typing.ClassVar", + Self::Callable => "typing.Callable", + Self::Concatenate => "typing.Concatenate", + Self::Unpack => "typing.Unpack", + Self::Required => "typing.Required", + Self::NotRequired => "typing.NotRequired", + Self::TypeAlias => "typing.TypeAlias", + Self::TypeGuard => "typing.TypeGuard", + Self::TypeIs => "typing.TypeIs", + Self::List => "typing.List", + Self::Dict => "typing.Dict", + Self::DefaultDict => "typing.DefaultDict", + Self::Set => "typing.Set", + Self::FrozenSet => "typing.FrozenSet", + Self::Counter => "typing.Counter", + Self::Deque => "typing.Deque", + Self::ChainMap => "typing.ChainMap", + Self::OrderedDict => "typing.OrderedDict", + Self::ReadOnly => "typing.ReadOnly", Self::TypeVar(typevar) => typevar.name(db), Self::TypeAliasType(_) => "typing.TypeAliasType", } @@ -2225,6 +2329,27 @@ impl<'db> KnownInstanceType<'db> { Self::Any => KnownClass::Object, Self::Tuple => KnownClass::SpecialForm, Self::Type => KnownClass::SpecialForm, + Self::TypingSelf => KnownClass::SpecialForm, + Self::Final => KnownClass::SpecialForm, + Self::ClassVar => KnownClass::SpecialForm, + Self::Callable => KnownClass::SpecialForm, + Self::Concatenate => KnownClass::SpecialForm, + Self::Unpack => KnownClass::SpecialForm, + Self::Required => KnownClass::SpecialForm, + Self::NotRequired => KnownClass::SpecialForm, + Self::TypeAlias => KnownClass::SpecialForm, + Self::TypeGuard => KnownClass::SpecialForm, + Self::TypeIs => KnownClass::SpecialForm, + Self::ReadOnly => KnownClass::SpecialForm, + Self::List => KnownClass::StdlibAlias, + Self::Dict => KnownClass::StdlibAlias, + Self::DefaultDict => KnownClass::StdlibAlias, + Self::Set => KnownClass::StdlibAlias, + Self::FrozenSet => KnownClass::StdlibAlias, + Self::Counter => KnownClass::StdlibAlias, + Self::Deque => KnownClass::StdlibAlias, + Self::ChainMap => KnownClass::StdlibAlias, + Self::OrderedDict => KnownClass::StdlibAlias, Self::TypeVar(_) => KnownClass::TypeVar, Self::TypeAliasType(_) => KnownClass::TypeAliasType, } @@ -2245,14 +2370,35 @@ impl<'db> KnownInstanceType<'db> { } match (module.name().as_str(), instance_name) { ("typing", "Any") => Some(Self::Any), + ("typing", "ClassVar") => Some(Self::ClassVar), + ("typing", "Deque") => Some(Self::Deque), + ("typing", "List") => Some(Self::List), + ("typing", "Dict") => Some(Self::Dict), + ("typing", "DefaultDict") => Some(Self::DefaultDict), + ("typing", "Set") => Some(Self::Set), + ("typing", "FrozenSet") => Some(Self::FrozenSet), + ("typing", "Counter") => Some(Self::Counter), + ("typing", "ChainMap") => Some(Self::ChainMap), + ("typing", "OrderedDict") => Some(Self::OrderedDict), + ("typing", "Optional") => Some(Self::Optional), + ("typing", "Union") => Some(Self::Union), + ("typing", "NoReturn") => Some(Self::NoReturn), + ("typing", "Tuple") => Some(Self::Tuple), + ("typing", "Type") => Some(Self::Type), + ("typing", "Callable") => Some(Self::Callable), ("typing" | "typing_extensions", "Literal") => Some(Self::Literal), ("typing" | "typing_extensions", "LiteralString") => Some(Self::LiteralString), - ("typing" | "typing_extensions", "Optional") => Some(Self::Optional), - ("typing" | "typing_extensions", "Union") => Some(Self::Union), - ("typing" | "typing_extensions", "NoReturn") => Some(Self::NoReturn), ("typing" | "typing_extensions", "Never") => Some(Self::Never), - ("typing" | "typing_extensions", "Tuple") => Some(Self::Tuple), - ("typing" | "typing_extensions", "Type") => Some(Self::Type), + ("typing" | "typing_extensions", "Self") => Some(Self::TypingSelf), + ("typing" | "typing_extensions", "Final") => Some(Self::Final), + ("typing" | "typing_extensions", "Concatenate") => Some(Self::Concatenate), + ("typing" | "typing_extensions", "Unpack") => Some(Self::Unpack), + ("typing" | "typing_extensions", "Required") => Some(Self::Required), + ("typing" | "typing_extensions", "NotRequired") => Some(Self::NotRequired), + ("typing" | "typing_extensions", "TypeAlias") => Some(Self::TypeAlias), + ("typing" | "typing_extensions", "TypeGuard") => Some(Self::TypeGuard), + ("typing" | "typing_extensions", "TypeIs") => Some(Self::TypeIs), + ("typing" | "typing_extensions", "ReadOnly") => Some(Self::ReadOnly), _ => None, } } diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index f50d4219ef7f4..6b4393f58818e 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -4786,6 +4786,10 @@ impl<'db> TypeInferenceBuilder<'db> { Type::KnownInstance(known_instance) => { self.infer_parameterized_known_instance_type_expression(subscript, known_instance) } + Type::Todo(_) => { + self.infer_type_expression(slice); + value_ty + } _ => { self.infer_type_expression(slice); todo_type!("generics") @@ -4833,13 +4837,89 @@ impl<'db> TypeInferenceBuilder<'db> { }, KnownInstanceType::TypeVar(_) => { self.infer_type_expression(parameters); - todo_type!() + todo_type!("TypeVar annotations") } KnownInstanceType::TypeAliasType(_) => { self.infer_type_expression(parameters); - todo_type!("generic type alias") + todo_type!("Generic PEP-695 type alias") + } + KnownInstanceType::Callable => { + self.infer_type_expression(parameters); + todo_type!("Callable types") + } + KnownInstanceType::ChainMap => { + self.infer_type_expression(parameters); + todo_type!("typing.ChainMap alias") + } + KnownInstanceType::OrderedDict => { + self.infer_type_expression(parameters); + todo_type!("typing.OrderedDict alias") + } + KnownInstanceType::Dict => { + self.infer_type_expression(parameters); + todo_type!("typing.Dict alias") + } + KnownInstanceType::List => { + self.infer_type_expression(parameters); + todo_type!("typing.List alias") + } + KnownInstanceType::DefaultDict => { + self.infer_type_expression(parameters); + todo_type!("typing.DefaultDict[] alias") + } + KnownInstanceType::Counter => { + self.infer_type_expression(parameters); + todo_type!("typing.Counter[] alias") + } + KnownInstanceType::Set => { + self.infer_type_expression(parameters); + todo_type!("typing.Set alias") + } + KnownInstanceType::FrozenSet => { + self.infer_type_expression(parameters); + todo_type!("typing.FrozenSet alias") + } + KnownInstanceType::Deque => { + self.infer_type_expression(parameters); + todo_type!("typing.Deque alias") + } + KnownInstanceType::ReadOnly => { + self.infer_type_expression(parameters); + todo_type!("Required[] type qualifier") } - KnownInstanceType::NoReturn | KnownInstanceType::Never => { + KnownInstanceType::NotRequired => { + self.infer_type_expression(parameters); + todo_type!("NotRequired[] type qualifier") + } + KnownInstanceType::ClassVar => { + self.infer_type_expression(parameters); + todo_type!("ClassVar[] type qualifier") + } + KnownInstanceType::Final => { + self.infer_type_expression(parameters); + todo_type!("Final[] type qualifier") + } + KnownInstanceType::Required => { + self.infer_type_expression(parameters); + todo_type!("Required[] type qualifier") + } + KnownInstanceType::TypeIs => { + self.infer_type_expression(parameters); + todo_type!("TypeIs[] special form") + } + KnownInstanceType::TypeGuard => { + self.infer_type_expression(parameters); + todo_type!("TypeGuard[] special form") + } + KnownInstanceType::Concatenate => { + self.infer_type_expression(parameters); + todo_type!("Concatenate[] special form") + } + KnownInstanceType::Unpack => { + self.infer_type_expression(parameters); + todo_type!("Unpack[] special form") + } + KnownInstanceType::NoReturn | KnownInstanceType::Never | KnownInstanceType::Any => { self.diagnostics.add_lint( &INVALID_TYPE_PARAMETER, subscript.into(), @@ -4850,30 +4930,30 @@ impl<'db> TypeInferenceBuilder<'db> { ); Type::Unknown } - KnownInstanceType::LiteralString => { + KnownInstanceType::TypingSelf | KnownInstanceType::TypeAlias => { self.diagnostics.add_lint( &INVALID_TYPE_PARAMETER, subscript.into(), format_args!( - "Type `{}` expected no type parameter. Did you mean to use `Literal[...]` instead?", + "Special form `{}` expected no type parameter", known_instance.repr(self.db) ), ); Type::Unknown } - KnownInstanceType::Type => self.infer_subclass_of_type_expression(parameters), - KnownInstanceType::Tuple => self.infer_tuple_type_expression(parameters), - KnownInstanceType::Any => { + KnownInstanceType::LiteralString => { self.diagnostics.add_lint( &INVALID_TYPE_PARAMETER, subscript.into(), format_args!( - "Type `{}` expected no type parameter", + "Type `{}` expected no type parameter. Did you mean to use `Literal[...]` instead?", known_instance.repr(self.db) ), ); Type::Unknown } + KnownInstanceType::Type => self.infer_subclass_of_type_expression(parameters), + KnownInstanceType::Tuple => self.infer_tuple_type_expression(parameters), } } diff --git a/crates/red_knot_python_semantic/src/types/mro.rs b/crates/red_knot_python_semantic/src/types/mro.rs index 0514925248234..bd9982f0a6749 100644 --- a/crates/red_knot_python_semantic/src/types/mro.rs +++ b/crates/red_knot_python_semantic/src/types/mro.rs @@ -4,7 +4,7 @@ use std::ops::Deref; use itertools::Either; use rustc_hash::FxHashSet; -use super::{Class, ClassLiteralType, KnownClass, KnownInstanceType, TodoType, Type}; +use super::{todo_type, Class, ClassLiteralType, KnownClass, KnownInstanceType, TodoType, Type}; use crate::Db; /// The inferred method resolution order of a given class. @@ -362,15 +362,47 @@ impl<'db> ClassBase<'db> { | KnownInstanceType::Union | KnownInstanceType::NoReturn | KnownInstanceType::Never + | KnownInstanceType::Final + | KnownInstanceType::NotRequired + | KnownInstanceType::TypeGuard + | KnownInstanceType::TypeIs + | KnownInstanceType::TypingSelf + | KnownInstanceType::Unpack + | KnownInstanceType::ClassVar + | KnownInstanceType::Concatenate + | KnownInstanceType::Required + | KnownInstanceType::TypeAlias + | KnownInstanceType::ReadOnly | KnownInstanceType::Optional => None, KnownInstanceType::Any => Some(Self::Any), // TODO: Classes inheriting from `typing.Type` et al. also have `Generic` in their MRO + KnownInstanceType::Dict => { + ClassBase::try_from_ty(db, KnownClass::Dict.to_class_literal(db)) + } + KnownInstanceType::List => { + ClassBase::try_from_ty(db, KnownClass::List.to_class_literal(db)) + } KnownInstanceType::Type => { ClassBase::try_from_ty(db, KnownClass::Type.to_class_literal(db)) } KnownInstanceType::Tuple => { ClassBase::try_from_ty(db, KnownClass::Tuple.to_class_literal(db)) } + KnownInstanceType::Set => { + ClassBase::try_from_ty(db, KnownClass::Set.to_class_literal(db)) + } + KnownInstanceType::FrozenSet => { + ClassBase::try_from_ty(db, KnownClass::FrozenSet.to_class_literal(db)) + } + KnownInstanceType::Callable + | KnownInstanceType::ChainMap + | KnownInstanceType::Counter + | KnownInstanceType::DefaultDict + | KnownInstanceType::Deque + | KnownInstanceType::OrderedDict => Self::try_from_ty( + db, + todo_type!("Support for more typing aliases as base classes"), + ), }, } }