mirror of https://github.com/astral-sh/ruff
[ty] Generic "manual" PEP 695 type aliases
This commit is contained in:
parent
fdcb5a7e73
commit
e700c86857
|
|
@ -740,8 +740,26 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
|
||||
// TODO: This should jump to the definition of `Alias` above.
|
||||
assert_snapshot!(test.goto_type_definition(), @"No type definitions found");
|
||||
assert_snapshot!(test.goto_type_definition(), @r#"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> main.py:4:1
|
||||
|
|
||||
2 | from typing_extensions import TypeAliasType
|
||||
3 |
|
||||
4 | Alias = TypeAliasType("Alias", tuple[int, int])
|
||||
| ^^^^^
|
||||
5 |
|
||||
6 | Alias
|
||||
|
|
||||
info: Source
|
||||
--> main.py:6:1
|
||||
|
|
||||
4 | Alias = TypeAliasType("Alias", tuple[int, int])
|
||||
5 |
|
||||
6 | Alias
|
||||
| ^^^^^
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -217,8 +217,7 @@ MyList = TypeAliasType("MyList", list[T], type_params=(T,))
|
|||
MyAlias5 = Callable[[MyList[T]], int]
|
||||
|
||||
def _(c: MyAlias5[int]):
|
||||
# TODO: should be (list[int], /) -> int
|
||||
reveal_type(c) # revealed: (Unknown, /) -> int
|
||||
reveal_type(c) # revealed: (list[int], /) -> int
|
||||
|
||||
K = TypeVar("K")
|
||||
V = TypeVar("V")
|
||||
|
|
@ -228,14 +227,12 @@ MyDict = TypeAliasType("MyDict", dict[K, V], type_params=(K, V))
|
|||
MyAlias6 = Callable[[MyDict[K, V]], int]
|
||||
|
||||
def _(c: MyAlias6[str, bytes]):
|
||||
# TODO: should be (dict[str, bytes], /) -> int
|
||||
reveal_type(c) # revealed: (Unknown, /) -> int
|
||||
reveal_type(c) # revealed: (dict[str, bytes], /) -> int
|
||||
|
||||
ListOrDict: TypeAlias = MyList[T] | dict[str, T]
|
||||
|
||||
def _(x: ListOrDict[int]):
|
||||
# TODO: should be list[int] | dict[str, int]
|
||||
reveal_type(x) # revealed: Unknown | dict[str, int]
|
||||
reveal_type(x) # revealed: list[int] | dict[str, int]
|
||||
|
||||
MyAlias7: TypeAlias = Callable[Concatenate[T, ...], None]
|
||||
|
||||
|
|
|
|||
|
|
@ -223,8 +223,27 @@ T = TypeVar("T")
|
|||
IntAndT = TypeAliasType("IntAndT", tuple[int, T], type_params=(T,))
|
||||
|
||||
def f(x: IntAndT[str]) -> None:
|
||||
# TODO: This should be `tuple[int, str]`
|
||||
reveal_type(x) # revealed: Unknown
|
||||
reveal_type(x) # revealed: tuple[int, str]
|
||||
|
||||
U = TypeVar("U", default=str)
|
||||
|
||||
ListOrSet = TypeAliasType("ListOrSet", list[U] | set[U], type_params=(U,))
|
||||
|
||||
def g(
|
||||
list_or_set_of_int: ListOrSet[int],
|
||||
list_or_set_of_str: ListOrSet,
|
||||
) -> None:
|
||||
reveal_type(list_or_set_of_int) # revealed: list[int] | set[int]
|
||||
reveal_type(list_or_set_of_str) # revealed: list[str] | set[str]
|
||||
|
||||
MyDict = TypeAliasType("MyDict", dict[U, T], type_params=(U, T))
|
||||
|
||||
def h(
|
||||
dict_int_str: MyDict[int, str],
|
||||
dict_str_unknown: MyDict,
|
||||
) -> None:
|
||||
reveal_type(dict_int_str) # revealed: dict[int, str]
|
||||
reveal_type(dict_str_unknown) # revealed: dict[str, Unknown]
|
||||
```
|
||||
|
||||
### Error cases
|
||||
|
|
@ -241,6 +260,35 @@ def get_name() -> str:
|
|||
IntOrStr = TypeAliasType(get_name(), int | str)
|
||||
```
|
||||
|
||||
#### Type parameters argument is not a tuple
|
||||
|
||||
```py
|
||||
from typing_extensions import TypeAliasType, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
# error: [invalid-type-alias-type] "`type_params` argument to `TypeAliasType` must be a tuple"
|
||||
IntAndT = TypeAliasType("IntAndT", tuple[int, T], type_params=T)
|
||||
|
||||
def _(x: IntAndT[str]) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
#### Invalid type parameters entries
|
||||
|
||||
```py
|
||||
from typing_extensions import TypeAliasType, TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
# TODO: This should be an error
|
||||
IntAndT = TypeAliasType("IntAndT", tuple[int, T], type_params=(str,))
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias"
|
||||
def _(x: IntAndT[str]) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Cyclic aliases
|
||||
|
||||
### Self-referential
|
||||
|
|
|
|||
|
|
@ -12898,6 +12898,8 @@ pub struct ManualPEP695TypeAliasType<'db> {
|
|||
pub name: ast::name::Name,
|
||||
pub definition: Option<Definition<'db>>,
|
||||
pub value: Type<'db>,
|
||||
generic_context: Option<GenericContext<'db>>,
|
||||
specialization: Option<Specialization<'db>>,
|
||||
}
|
||||
|
||||
// The Salsa heap is tracked separately.
|
||||
|
|
@ -12912,12 +12914,50 @@ fn walk_manual_pep_695_type_alias<'db, V: visitor::TypeVisitor<'db> + ?Sized>(
|
|||
}
|
||||
|
||||
impl<'db> ManualPEP695TypeAliasType<'db> {
|
||||
pub(crate) fn value_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
self.apply_function_specialization(db, self.value(db))
|
||||
}
|
||||
|
||||
fn apply_function_specialization(self, db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
|
||||
if let Some(generic_context) = self.generic_context(db) {
|
||||
let specialization = self
|
||||
.specialization(db)
|
||||
.unwrap_or_else(|| generic_context.default_specialization(db, None));
|
||||
ty.apply_specialization(db, specialization)
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_specialization(
|
||||
self,
|
||||
db: &'db dyn Db,
|
||||
f: impl FnOnce(GenericContext<'db>) -> Specialization<'db>,
|
||||
) -> ManualPEP695TypeAliasType<'db> {
|
||||
match self.generic_context(db) {
|
||||
None => self,
|
||||
Some(generic_context) => {
|
||||
let specialization = f(generic_context);
|
||||
ManualPEP695TypeAliasType::new(
|
||||
db,
|
||||
self.name(db),
|
||||
self.definition(db),
|
||||
self.value(db),
|
||||
self.generic_context(db),
|
||||
Some(specialization),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn normalized_impl(self, db: &'db dyn Db, visitor: &NormalizedVisitor<'db>) -> Self {
|
||||
Self::new(
|
||||
db,
|
||||
self.name(db),
|
||||
self.definition(db),
|
||||
self.value(db).normalized_impl(db, visitor),
|
||||
self.generic_context(db),
|
||||
self.specialization(db),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -12929,6 +12969,8 @@ impl<'db> ManualPEP695TypeAliasType<'db> {
|
|||
self.definition(db),
|
||||
self.value(db)
|
||||
.recursive_type_normalized_impl(db, div, true)?,
|
||||
self.generic_context(db),
|
||||
self.specialization(db),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -12999,7 +13041,7 @@ impl<'db> TypeAliasType<'db> {
|
|||
pub fn value_type(self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.value_type(db),
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.value(db),
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.value_type(db),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13018,24 +13060,25 @@ impl<'db> TypeAliasType<'db> {
|
|||
}
|
||||
|
||||
pub(crate) fn generic_context(self, db: &'db dyn Db) -> Option<GenericContext<'db>> {
|
||||
// TODO: Add support for generic non-PEP695 type aliases.
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.generic_context(db),
|
||||
TypeAliasType::ManualPEP695(_) => None,
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.generic_context(db),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn specialization(self, db: &'db dyn Db) -> Option<Specialization<'db>> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.specialization(db),
|
||||
TypeAliasType::ManualPEP695(_) => None,
|
||||
TypeAliasType::ManualPEP695(type_alias) => type_alias.specialization(db),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_function_specialization(self, db: &'db dyn Db, ty: Type<'db>) -> Type<'db> {
|
||||
match self {
|
||||
TypeAliasType::PEP695(type_alias) => type_alias.apply_function_specialization(db, ty),
|
||||
TypeAliasType::ManualPEP695(_) => ty,
|
||||
TypeAliasType::ManualPEP695(type_alias) => {
|
||||
type_alias.apply_function_specialization(db, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13048,7 +13091,9 @@ impl<'db> TypeAliasType<'db> {
|
|||
TypeAliasType::PEP695(type_alias) => {
|
||||
TypeAliasType::PEP695(type_alias.apply_specialization(db, f))
|
||||
}
|
||||
TypeAliasType::ManualPEP695(_) => self,
|
||||
TypeAliasType::ManualPEP695(type_alias) => {
|
||||
TypeAliasType::ManualPEP695(type_alias.apply_specialization(db, f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::semantic_index::{
|
|||
use crate::types::bound_super::BoundSuperError;
|
||||
use crate::types::constraints::{ConstraintSet, IteratorConstraintsExtension};
|
||||
use crate::types::context::InferContext;
|
||||
use crate::types::diagnostic::{INVALID_TYPE_ALIAS_TYPE, SUPER_CALL_IN_NAMED_TUPLE_METHOD};
|
||||
use crate::types::diagnostic::SUPER_CALL_IN_NAMED_TUPLE_METHOD;
|
||||
use crate::types::enums::enum_metadata;
|
||||
use crate::types::function::{DataclassTransformerParams, KnownFunction};
|
||||
use crate::types::generics::{
|
||||
|
|
@ -35,9 +35,9 @@ use crate::types::{
|
|||
ApplyTypeMappingVisitor, Binding, BoundSuperType, CallableType, CallableTypes, DATACLASS_FLAGS,
|
||||
DataclassFlags, DataclassParams, DeprecatedInstance, FindLegacyTypeVarsVisitor,
|
||||
HasRelationToVisitor, IsDisjointVisitor, IsEquivalentVisitor, KnownInstanceType,
|
||||
ManualPEP695TypeAliasType, MaterializationKind, NormalizedVisitor, PropertyInstanceType,
|
||||
StringLiteralType, TypeAliasType, TypeContext, TypeMapping, TypeRelation, TypedDictParams,
|
||||
UnionBuilder, VarianceInferable, binding_type, declaration_type, determine_upper_bound,
|
||||
MaterializationKind, NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeContext,
|
||||
TypeMapping, TypeRelation, TypedDictParams, UnionBuilder, VarianceInferable, binding_type,
|
||||
declaration_type, determine_upper_bound,
|
||||
};
|
||||
use crate::{
|
||||
Db, FxIndexMap, FxIndexSet, FxOrderSet, Program,
|
||||
|
|
@ -5664,42 +5664,6 @@ impl KnownClass {
|
|||
)));
|
||||
}
|
||||
|
||||
KnownClass::TypeAliasType => {
|
||||
let assigned_to = index
|
||||
.try_expression(ast::ExprRef::from(call_expression))
|
||||
.and_then(|expr| expr.assigned_to(db));
|
||||
|
||||
let containing_assignment = assigned_to.as_ref().and_then(|assigned_to| {
|
||||
match assigned_to.node(module).targets.as_slice() {
|
||||
[ast::Expr::Name(target)] => Some(index.expect_single_definition(target)),
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
|
||||
let [Some(name), Some(value), ..] = overload.parameter_types() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(name) = name.as_string_literal() else {
|
||||
if let Some(builder) =
|
||||
context.report_lint(&INVALID_TYPE_ALIAS_TYPE, call_expression)
|
||||
{
|
||||
builder.into_diagnostic(
|
||||
"The name of a `typing.TypeAlias` must be a string literal",
|
||||
);
|
||||
}
|
||||
return;
|
||||
};
|
||||
overload.set_return_type(Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||
TypeAliasType::ManualPEP695(ManualPEP695TypeAliasType::new(
|
||||
db,
|
||||
ast::name::Name::new(name.value(db)),
|
||||
containing_assignment,
|
||||
value,
|
||||
)),
|
||||
)));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,12 +61,12 @@ use crate::types::diagnostic::{
|
|||
INVALID_ARGUMENT_TYPE, INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE,
|
||||
INVALID_DECLARATION, INVALID_GENERIC_CLASS, INVALID_KEY, INVALID_LEGACY_TYPE_VARIABLE,
|
||||
INVALID_METACLASS, INVALID_NAMED_TUPLE, INVALID_NEWTYPE, INVALID_OVERLOAD,
|
||||
INVALID_PARAMETER_DEFAULT, INVALID_PARAMSPEC, INVALID_PROTOCOL, INVALID_TYPE_ARGUMENTS,
|
||||
INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL, INVALID_TYPE_VARIABLE_CONSTRAINTS,
|
||||
IncompatibleBases, NON_SUBSCRIPTABLE, POSSIBLY_MISSING_ATTRIBUTE,
|
||||
POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT, SUBCLASS_OF_FINAL_CLASS,
|
||||
UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT,
|
||||
UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR, USELESS_OVERLOAD_BODY,
|
||||
INVALID_PARAMETER_DEFAULT, INVALID_PARAMSPEC, INVALID_PROTOCOL, INVALID_TYPE_ALIAS_TYPE,
|
||||
INVALID_TYPE_ARGUMENTS, INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NON_SUBSCRIPTABLE,
|
||||
POSSIBLY_MISSING_ATTRIBUTE, POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT,
|
||||
SUBCLASS_OF_FINAL_CLASS, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_GLOBAL,
|
||||
UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR, USELESS_OVERLOAD_BODY,
|
||||
hint_if_stdlib_attribute_exists_on_other_versions,
|
||||
hint_if_stdlib_submodule_exists_on_other_versions, report_attempted_protocol_instantiation,
|
||||
report_bad_dunder_set_call, report_cannot_pop_required_field_on_typed_dict,
|
||||
|
|
@ -105,13 +105,13 @@ use crate::types::visitor::any_over_type;
|
|||
use crate::types::{
|
||||
BoundTypeVarInstance, CallDunderError, CallableBinding, CallableType, CallableTypes,
|
||||
ClassLiteral, ClassType, DataclassParams, DynamicType, InternedType, IntersectionBuilder,
|
||||
IntersectionType, KnownClass, KnownInstanceType, LintDiagnosticGuard, MemberLookupPolicy,
|
||||
MetaclassCandidate, PEP695TypeAliasType, ParameterForm, SpecialFormType, SubclassOfType,
|
||||
TrackedConstraintSet, Truthiness, Type, TypeAliasType, TypeAndQualifiers, TypeContext,
|
||||
TypeQualifiers, TypeVarBoundOrConstraints, TypeVarBoundOrConstraintsEvaluation,
|
||||
TypeVarDefaultEvaluation, TypeVarIdentity, TypeVarInstance, TypeVarKind, TypeVarVariance,
|
||||
TypedDictType, UnionBuilder, UnionType, UnionTypeInstance, binding_type, infer_scope_types,
|
||||
overrides, todo_type,
|
||||
IntersectionType, KnownClass, KnownInstanceType, LintDiagnosticGuard,
|
||||
ManualPEP695TypeAliasType, MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType,
|
||||
ParameterForm, SpecialFormType, SubclassOfType, TrackedConstraintSet, Truthiness, Type,
|
||||
TypeAliasType, TypeAndQualifiers, TypeContext, TypeQualifiers, TypeVarBoundOrConstraints,
|
||||
TypeVarBoundOrConstraintsEvaluation, TypeVarDefaultEvaluation, TypeVarIdentity,
|
||||
TypeVarInstance, TypeVarKind, TypeVarVariance, TypedDictType, UnionBuilder, UnionType,
|
||||
UnionTypeInstance, binding_type, infer_scope_types, overrides, todo_type,
|
||||
};
|
||||
use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic};
|
||||
use crate::unpack::{EvaluationMode, UnpackPosition};
|
||||
|
|
@ -4843,6 +4843,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
Some(KnownClass::NewType) => {
|
||||
self.infer_newtype_expression(target, call_expr, definition)
|
||||
}
|
||||
Some(KnownClass::TypeAliasType) => {
|
||||
self.infer_type_alias_type_expression(target, call_expr, definition)
|
||||
}
|
||||
Some(_) | None => {
|
||||
self.infer_call_expression_impl(call_expr, callable_type, tcx)
|
||||
}
|
||||
|
|
@ -5373,6 +5376,129 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
)))
|
||||
}
|
||||
|
||||
/// Infer a `TypeAliasType(name, value, type_params=(...))` call expression.
|
||||
fn infer_type_alias_type_expression(
|
||||
&mut self,
|
||||
target: &ast::Expr,
|
||||
call_expr: &ast::ExprCall,
|
||||
definition: Definition<'db>,
|
||||
) -> Type<'db> {
|
||||
fn error<'db>(
|
||||
context: &InferContext<'db, '_>,
|
||||
message: impl std::fmt::Display,
|
||||
node: impl Ranged,
|
||||
) -> Type<'db> {
|
||||
if let Some(builder) = context.report_lint(&INVALID_TYPE_ALIAS_TYPE, node) {
|
||||
builder.into_diagnostic(message);
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
let db = self.db();
|
||||
let arguments = &call_expr.arguments;
|
||||
|
||||
// Extract positional arguments: name, value
|
||||
let positional_args: Vec<_> = arguments
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| !arg.is_starred_expr())
|
||||
.collect();
|
||||
|
||||
if positional_args.len() < 2 {
|
||||
return error(
|
||||
&self.context,
|
||||
format!(
|
||||
"Wrong number of arguments in `TypeAliasType` creation, expected at least 2, found {}",
|
||||
positional_args.len()
|
||||
),
|
||||
call_expr,
|
||||
);
|
||||
}
|
||||
|
||||
// First argument: name (string literal)
|
||||
let name_param_ty = self.infer_expression(positional_args[0], TypeContext::default());
|
||||
let Some(name) = name_param_ty.as_string_literal().map(|n| n.value(db)) else {
|
||||
return error(
|
||||
&self.context,
|
||||
"The name of a `typing.TypeAlias` must be a string literal",
|
||||
positional_args[0],
|
||||
);
|
||||
};
|
||||
|
||||
// Validate that the target is a simple name and matches
|
||||
let ast::Expr::Name(ast::ExprName {
|
||||
id: target_name, ..
|
||||
}) = target
|
||||
else {
|
||||
return error(
|
||||
&self.context,
|
||||
"A `TypeAliasType` definition must be a simple variable assignment",
|
||||
target,
|
||||
);
|
||||
};
|
||||
|
||||
if name != target_name {
|
||||
return error(
|
||||
&self.context,
|
||||
format_args!(
|
||||
"The name of a `TypeAliasType` (`{name}`) must match \
|
||||
the name of the variable it is assigned to (`{target_name}`)"
|
||||
),
|
||||
target,
|
||||
);
|
||||
}
|
||||
|
||||
// Second argument: value
|
||||
let value_ty = self.infer_type_expression(positional_args[1]);
|
||||
|
||||
// Optional keyword argument: type_params
|
||||
let generic_context = if let Some(type_params) = arguments
|
||||
.keywords
|
||||
.iter()
|
||||
.find(|kw| kw.arg.as_ref().is_some_and(|arg| arg.id == "type_params"))
|
||||
{
|
||||
let type_params_ty = self.infer_expression(&type_params.value, TypeContext::default());
|
||||
let Some(tuple_spec) = type_params_ty.tuple_instance_spec(db) else {
|
||||
return error(
|
||||
&self.context,
|
||||
"`type_params` argument to `TypeAliasType` must be a tuple",
|
||||
&type_params.value,
|
||||
);
|
||||
};
|
||||
|
||||
let mut bound_typevars = tuple_spec
|
||||
.all_elements()
|
||||
.filter_map(|element| {
|
||||
if let Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) = element {
|
||||
Some(typevar.with_binding_context(db, definition))
|
||||
} else {
|
||||
// TODO: Emit a diagnostic if this is not a valid TypeVar, ParamSpec, or TypeVarTuple.
|
||||
None
|
||||
}
|
||||
})
|
||||
.peekable();
|
||||
|
||||
if bound_typevars.peek().is_some() {
|
||||
Some(GenericContext::from_typevar_instances(db, bound_typevars))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Type::KnownInstance(KnownInstanceType::TypeAliasType(
|
||||
TypeAliasType::ManualPEP695(ManualPEP695TypeAliasType::new(
|
||||
db,
|
||||
ast::name::Name::new(name),
|
||||
Some(definition),
|
||||
value_ty,
|
||||
generic_context,
|
||||
None,
|
||||
)),
|
||||
))
|
||||
}
|
||||
|
||||
fn infer_assignment_deferred(&mut self, value: &ast::Expr) {
|
||||
// Infer deferred bounds/constraints/defaults of a legacy TypeVar / ParamSpec / NewType.
|
||||
let ast::Expr::Call(ast::ExprCall {
|
||||
|
|
@ -11020,19 +11146,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
);
|
||||
}
|
||||
}
|
||||
Type::KnownInstance(KnownInstanceType::TypeAliasType(TypeAliasType::ManualPEP695(
|
||||
_,
|
||||
))) => {
|
||||
let slice_ty = self.infer_expression(slice, TypeContext::default());
|
||||
let mut variables = FxOrderSet::default();
|
||||
slice_ty.bind_and_find_all_legacy_typevars(
|
||||
self.db(),
|
||||
self.typevar_binding_context,
|
||||
&mut variables,
|
||||
);
|
||||
let generic_context = GenericContext::from_typevar_instances(self.db(), variables);
|
||||
return Type::Dynamic(DynamicType::UnknownGeneric(generic_context));
|
||||
}
|
||||
Type::KnownInstance(KnownInstanceType::TypeAliasType(type_alias)) => {
|
||||
if let Some(generic_context) = type_alias.generic_context(self.db()) {
|
||||
return self.infer_explicit_type_alias_type_specialization(
|
||||
|
|
@ -11042,6 +11155,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
generic_context,
|
||||
);
|
||||
}
|
||||
|
||||
self.infer_expression(slice, TypeContext::default());
|
||||
if let Some(builder) = self.context.report_lint(&NON_SUBSCRIPTABLE, subscript) {
|
||||
builder
|
||||
.into_diagnostic(format_args!("Cannot subscript non-generic type alias"));
|
||||
}
|
||||
|
||||
return Type::unknown();
|
||||
}
|
||||
Type::SpecialForm(SpecialFormType::Tuple) => {
|
||||
return tuple_generic_alias(self.db(), self.infer_tuple_type_expression(slice));
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
|||
use crate::types::visitor::any_over_type;
|
||||
use crate::types::{
|
||||
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, SpecialFormType, SubclassOfType, Type, TypeAliasType,
|
||||
TypeContext, TypeIsType, TypeMapping, UnionBuilder, UnionType, todo_type,
|
||||
KnownInstanceType, LintDiagnosticGuard, SpecialFormType, SubclassOfType, Type, TypeContext,
|
||||
TypeIsType, TypeMapping, UnionBuilder, UnionType, todo_type,
|
||||
};
|
||||
|
||||
/// Type expressions
|
||||
|
|
@ -911,7 +911,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => {
|
||||
KnownInstanceType::TypeAliasType(type_alias) => {
|
||||
match type_alias.generic_context(self.db()) {
|
||||
Some(generic_context) => {
|
||||
let specialized_type_alias = self
|
||||
|
|
@ -945,19 +945,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
KnownInstanceType::TypeAliasType(TypeAliasType::ManualPEP695(_)) => {
|
||||
// TODO: support generic "manual" PEP 695 type aliases
|
||||
let slice_ty = self.infer_expression(slice, TypeContext::default());
|
||||
let mut variables = FxOrderSet::default();
|
||||
slice_ty.bind_and_find_all_legacy_typevars(
|
||||
self.db(),
|
||||
self.typevar_binding_context,
|
||||
&mut variables,
|
||||
);
|
||||
let generic_context =
|
||||
GenericContext::from_typevar_instances(self.db(), variables);
|
||||
Type::Dynamic(DynamicType::UnknownGeneric(generic_context))
|
||||
}
|
||||
KnownInstanceType::LiteralStringAlias(_) => {
|
||||
self.infer_type_expression(slice);
|
||||
todo_type!("Generic stringified PEP-613 type alias")
|
||||
|
|
|
|||
Loading…
Reference in New Issue