[ty] disallow explicit specialization of type variables themselves (#21938)
## Summary This PR makes explicit specialization of a type variable itself an error, and the result of the specialization is `Unknown`. The change also fixes https://github.com/astral-sh/ty/issues/1794. ## Test Plan mdtests updated new corpus test --------- Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
committed by
GitHub
parent
5a2aba237b
commit
e19c050386
@@ -7994,7 +7994,7 @@ impl<'db> Type<'db> {
|
||||
) {
|
||||
let matching_typevar = |bound_typevar: &BoundTypeVarInstance<'db>| {
|
||||
match bound_typevar.typevar(db).kind(db) {
|
||||
TypeVarKind::Legacy | TypeVarKind::TypingSelf
|
||||
TypeVarKind::Legacy | TypeVarKind::Pep613Alias | TypeVarKind::TypingSelf
|
||||
if binding_context.is_none_or(|binding_context| {
|
||||
bound_typevar.binding_context(db)
|
||||
== BindingContext::Definition(binding_context)
|
||||
@@ -9472,6 +9472,8 @@ pub enum TypeVarKind {
|
||||
ParamSpec,
|
||||
/// `def foo[**P]() -> None: ...`
|
||||
Pep695ParamSpec,
|
||||
/// `Alias: typing.TypeAlias = T`
|
||||
Pep613Alias,
|
||||
}
|
||||
|
||||
impl TypeVarKind {
|
||||
|
||||
@@ -5866,6 +5866,24 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
};
|
||||
|
||||
if is_pep_613_type_alias {
|
||||
let inferred_ty =
|
||||
if let Type::KnownInstance(KnownInstanceType::TypeVar(typevar)) = inferred_ty {
|
||||
let identity = TypeVarIdentity::new(
|
||||
self.db(),
|
||||
typevar.identity(self.db()).name(self.db()),
|
||||
typevar.identity(self.db()).definition(self.db()),
|
||||
TypeVarKind::Pep613Alias,
|
||||
);
|
||||
Type::KnownInstance(KnownInstanceType::TypeVar(TypeVarInstance::new(
|
||||
self.db(),
|
||||
identity,
|
||||
typevar._bound_or_constraints(self.db()),
|
||||
typevar.explicit_variance(self.db()),
|
||||
typevar._default(self.db()),
|
||||
)))
|
||||
} else {
|
||||
inferred_ty
|
||||
};
|
||||
self.add_declaration_with_binding(
|
||||
target.into(),
|
||||
definition,
|
||||
|
||||
@@ -16,8 +16,8 @@ use crate::types::tuple::{TupleSpecBuilder, TupleType};
|
||||
use crate::types::{
|
||||
BindingContext, CallableType, DynamicType, GenericContext, IntersectionBuilder, KnownClass,
|
||||
KnownInstanceType, LintDiagnosticGuard, Parameter, Parameters, SpecialFormType, SubclassOfType,
|
||||
Type, TypeAliasType, TypeContext, TypeIsType, TypeMapping, UnionBuilder, UnionType,
|
||||
any_over_type, todo_type,
|
||||
Type, TypeAliasType, TypeContext, TypeIsType, TypeMapping, TypeVarKind, UnionBuilder,
|
||||
UnionType, any_over_type, todo_type,
|
||||
};
|
||||
|
||||
/// Type expressions
|
||||
@@ -995,8 +995,26 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
KnownInstanceType::TypeVar(_) => {
|
||||
self.infer_explicit_type_alias_specialization(subscript, value_ty, false)
|
||||
KnownInstanceType::TypeVar(typevar) => {
|
||||
// The type variable designated as a generic type alias by `typing.TypeAlias` can be explicitly specialized.
|
||||
// ```py
|
||||
// from typing import TypeVar, TypeAlias
|
||||
// T = TypeVar('T')
|
||||
// Annotated: TypeAlias = T
|
||||
// _: Annotated[int] = 1 # valid
|
||||
// ```
|
||||
if typevar.identity(self.db()).kind(self.db()) == TypeVarKind::Pep613Alias {
|
||||
self.infer_explicit_type_alias_specialization(subscript, value_ty, false)
|
||||
} else {
|
||||
if let Some(builder) =
|
||||
self.context.report_lint(&INVALID_TYPE_FORM, subscript)
|
||||
{
|
||||
builder.into_diagnostic(format_args!(
|
||||
"A type variable itself cannot be specialized",
|
||||
));
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
}
|
||||
|
||||
KnownInstanceType::UnionType(_)
|
||||
|
||||
Reference in New Issue
Block a user