Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,26 @@ def f(x: IntOr, y: OrInt):
reveal_type(y) # revealed: Never
```

### With legacy generic

```py
from typing import Generic, TypeVar

T = TypeVar("T")

type Alias = list["Alias"] | int

class A(Generic[T]):
attr: T

class B(A[Alias]):
pass

def f(b: B):
reveal_type(b) # revealed: B
reveal_type(b.attr) # revealed: list[Alias] | int
```

### Mutually recursive

```py
Expand Down
95 changes: 65 additions & 30 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ruff_text_size::{Ranged, TextRange};
use type_ordering::union_or_intersection_elements_ordering;

pub(crate) use self::builder::{IntersectionBuilder, UnionBuilder};
pub(crate) use self::cyclic::{PairVisitor, TypeTransformer};
pub(crate) use self::cyclic::{CycleDetector, PairVisitor, TypeTransformer};
pub use self::diagnostic::TypeCheckDiagnostics;
pub(crate) use self::diagnostic::register_lints;
pub(crate) use self::infer::{
Expand Down Expand Up @@ -191,6 +191,10 @@ pub(crate) struct IsDisjoint;
pub(crate) type IsEquivalentVisitor<'db, C> = PairVisitor<'db, IsEquivalent, C>;
pub(crate) struct IsEquivalent;

/// A [`CycleDetector`] for `find_legacy_typevars` methods.
pub(crate) type FindLegacyTypeVarsVisitor<'db> = CycleDetector<FindLegacyTypeVars, Type<'db>, ()>;
pub(crate) struct FindLegacyTypeVars;

/// A [`TypeTransformer`] that is used in `normalized` methods.
pub(crate) type NormalizedVisitor<'db> = TypeTransformer<'db, Normalized>;
pub(crate) struct Normalized;
Expand Down Expand Up @@ -503,17 +507,18 @@ impl<'db> PropertyInstanceType<'db> {
)
}

fn find_legacy_typevars(
fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
if let Some(ty) = self.getter(db) {
ty.find_legacy_typevars(db, binding_context, typevars);
ty.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
if let Some(ty) = self.setter(db) {
ty.find_legacy_typevars(db, binding_context, typevars);
ty.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
}

Expand Down Expand Up @@ -6157,6 +6162,21 @@ impl<'db> Type<'db> {
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
) {
self.find_legacy_typevars_impl(
db,
binding_context,
typevars,
&FindLegacyTypeVarsVisitor::default(),
);
}

pub(crate) fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
match self {
Type::NonInferableTypeVar(bound_typevar) | Type::TypeVar(bound_typevar) => {
Expand All @@ -6171,80 +6191,94 @@ impl<'db> Type<'db> {
}

Type::FunctionLiteral(function) => {
function.find_legacy_typevars(db, binding_context, typevars);
function.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::BoundMethod(method) => {
method
.self_instance(db)
.find_legacy_typevars(db, binding_context, typevars);
method
.function(db)
.find_legacy_typevars(db, binding_context, typevars);
method.self_instance(db).find_legacy_typevars_impl(
db,
binding_context,
typevars,
visitor,
);
method.function(db).find_legacy_typevars_impl(
db,
binding_context,
typevars,
visitor,
);
}

Type::MethodWrapper(
MethodWrapperKind::FunctionTypeDunderGet(function)
| MethodWrapperKind::FunctionTypeDunderCall(function),
) => {
function.find_legacy_typevars(db, binding_context, typevars);
function.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::MethodWrapper(
MethodWrapperKind::PropertyDunderGet(property)
| MethodWrapperKind::PropertyDunderSet(property),
) => {
property.find_legacy_typevars(db, binding_context, typevars);
property.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::Callable(callable) => {
callable.find_legacy_typevars(db, binding_context, typevars);
callable.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::PropertyInstance(property) => {
property.find_legacy_typevars(db, binding_context, typevars);
property.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::Union(union) => {
for element in union.elements(db) {
element.find_legacy_typevars(db, binding_context, typevars);
element.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
}
Type::Intersection(intersection) => {
for positive in intersection.positive(db) {
positive.find_legacy_typevars(db, binding_context, typevars);
positive.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
for negative in intersection.negative(db) {
negative.find_legacy_typevars(db, binding_context, typevars);
negative.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
}

Type::GenericAlias(alias) => {
alias.find_legacy_typevars(db, binding_context, typevars);
alias.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::NominalInstance(instance) => {
instance.find_legacy_typevars(db, binding_context, typevars);
instance.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::ProtocolInstance(instance) => {
instance.find_legacy_typevars(db, binding_context, typevars);
instance.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::SubclassOf(subclass_of) => {
subclass_of.find_legacy_typevars(db, binding_context, typevars);
subclass_of.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

Type::TypeIs(type_is) => {
type_is
.return_type(db)
.find_legacy_typevars(db, binding_context, typevars);
type_is.return_type(db).find_legacy_typevars_impl(
db,
binding_context,
typevars,
visitor,
);
}

Type::TypeAlias(alias) => {
alias
.value_type(db)
.find_legacy_typevars(db, binding_context, typevars);
visitor.visit(self, || {
alias.value_type(db).find_legacy_typevars_impl(
db,
binding_context,
typevars,
visitor,
);
});
}

Type::Dynamic(_)
Expand Down Expand Up @@ -8911,14 +8945,15 @@ impl<'db> CallableType<'db> {
)
}

fn find_legacy_typevars(
fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
self.signatures(db)
.find_legacy_typevars(db, binding_context, typevars);
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

/// Check whether this callable type has the given relation to another callable type.
Expand Down
22 changes: 13 additions & 9 deletions crates/ty_python_semantic/src/types/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ use crate::types::tuple::{TupleSpec, TupleType};
use crate::types::typed_dict::typed_dict_params_from_class_def;
use crate::types::{
ApplyTypeMappingVisitor, Binding, BoundSuperError, BoundSuperType, CallableType,
DataclassParams, DeprecatedInstance, HasRelationToVisitor, IsEquivalentVisitor,
KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind, NormalizedVisitor,
PropertyInstanceType, StringLiteralType, TypeAliasType, TypeMapping, TypeRelation,
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypedDictParams, VarianceInferable,
declaration_type, infer_definition_types, todo_type,
DataclassParams, DeprecatedInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
IsEquivalentVisitor, KnownInstanceType, ManualPEP695TypeAliasType, MaterializationKind,
NormalizedVisitor, PropertyInstanceType, StringLiteralType, TypeAliasType, TypeMapping,
TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypedDictParams,
VarianceInferable, declaration_type, infer_definition_types, todo_type,
};
use crate::{
Db, FxIndexMap, FxOrderSet, Program,
Expand Down Expand Up @@ -303,14 +303,15 @@ impl<'db> GenericAlias<'db> {
)
}

pub(super) fn find_legacy_typevars(
pub(super) fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
self.specialization(db)
.find_legacy_typevars(db, binding_context, typevars);
.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}

pub(super) fn is_typed_dict(self, db: &'db dyn Db) -> bool {
Expand Down Expand Up @@ -503,15 +504,18 @@ impl<'db> ClassType<'db> {
}
}

pub(super) fn find_legacy_typevars(
pub(super) fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
match self {
Self::NonGeneric(_) => {}
Self::Generic(generic) => generic.find_legacy_typevars(db, binding_context, typevars),
Self::Generic(generic) => {
generic.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions crates/ty_python_semantic/src/types/cyclic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,9 @@ impl<Tag, T: Hash + Eq + Clone, R: Clone> CycleDetector<Tag, T, R> {
ret
}
}

impl<Tag, T: Hash + Eq + Clone, R: Default + Clone> Default for CycleDetector<Tag, T, R> {
fn default() -> Self {
CycleDetector::new(R::default())
}
}
11 changes: 6 additions & 5 deletions crates/ty_python_semantic/src/types/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ use crate::types::signatures::{CallableSignature, Signature};
use crate::types::visitor::any_over_type;
use crate::types::{
BoundMethodType, BoundTypeVarInstance, CallableType, ClassBase, ClassLiteral, ClassType,
DeprecatedInstance, DynamicType, HasRelationToVisitor, IsEquivalentVisitor, KnownClass,
NormalizedVisitor, SpecialFormType, Truthiness, Type, TypeMapping, TypeRelation, UnionBuilder,
all_members, walk_type_mapping,
DeprecatedInstance, DynamicType, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
IsEquivalentVisitor, KnownClass, NormalizedVisitor, SpecialFormType, Truthiness, Type,
TypeMapping, TypeRelation, UnionBuilder, all_members, walk_type_mapping,
};
use crate::{Db, FxOrderSet, ModuleName, resolve_module};

Expand Down Expand Up @@ -915,15 +915,16 @@ impl<'db> FunctionType<'db> {
self_signature.is_equivalent_to_impl(db, other_signature, visitor)
}

pub(crate) fn find_legacy_typevars(
pub(crate) fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
let signatures = self.signature(db);
for signature in &signatures.overloads {
signature.find_legacy_typevars(db, binding_context, typevars);
signature.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
}

Expand Down
13 changes: 7 additions & 6 deletions crates/ty_python_semantic/src/types/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ use crate::types::instance::{Protocol, ProtocolInstanceType};
use crate::types::signatures::{Parameter, Parameters, Signature};
use crate::types::tuple::{TupleSpec, TupleType, walk_tuple_type};
use crate::types::{
ApplyTypeMappingVisitor, BoundTypeVarInstance, HasRelationToVisitor, IsEquivalentVisitor,
KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor, Type, TypeMapping,
TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance, UnionType,
binding_type, declaration_type,
ApplyTypeMappingVisitor, BoundTypeVarInstance, FindLegacyTypeVarsVisitor, HasRelationToVisitor,
IsEquivalentVisitor, KnownClass, KnownInstanceType, MaterializationKind, NormalizedVisitor,
Type, TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarVariance,
UnionType, binding_type, declaration_type,
};
use crate::{Db, FxOrderSet};

Expand Down Expand Up @@ -888,14 +888,15 @@ impl<'db> Specialization<'db> {
result
}

pub(crate) fn find_legacy_typevars(
pub(crate) fn find_legacy_typevars_impl(
self,
db: &'db dyn Db,
binding_context: Option<Definition<'db>>,
typevars: &mut FxOrderSet<BoundTypeVarInstance<'db>>,
visitor: &FindLegacyTypeVarsVisitor<'db>,
) {
for ty in self.types(db) {
ty.find_legacy_typevars(db, binding_context, typevars);
ty.find_legacy_typevars_impl(db, binding_context, typevars, visitor);
}
// A tuple's specialization will include all of its element types, so we don't need to also
// look in `self.tuple`.
Expand Down
Loading
Loading