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
185 changes: 163 additions & 22 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@ impl<'db> PropertyInstanceType<'db> {
Self::new(db, getter, setter)
}

fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
db,
self.getter(db).map(|ty| ty.normalized(db)),
self.setter(db).map(|ty| ty.normalized(db)),
)
}

fn find_legacy_typevars(
self,
db: &'db dyn Db,
Expand Down Expand Up @@ -1005,28 +1013,17 @@ impl<'db> Type<'db> {
Type::Callable(callable) => Type::Callable(callable.normalized(db)),
Type::ProtocolInstance(protocol) => protocol.normalized(db),
Type::NominalInstance(instance) => Type::NominalInstance(instance.normalized(db)),
Type::Dynamic(_) => Type::any(),
Type::LiteralString
| Type::PropertyInstance(_)
| Type::AlwaysFalsy
| Type::AlwaysTruthy
| Type::BooleanLiteral(_)
| Type::BytesLiteral(_)
| Type::StringLiteral(_)
| Type::Never
| Type::FunctionLiteral(_)
| Type::MethodWrapper(_)
| Type::BoundMethod(_)
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
| Type::ClassLiteral(_)
| Type::KnownInstance(_)
| Type::IntLiteral(_)
| Type::BoundSuper(_)
| Type::SubclassOf(_) => self,
Type::Dynamic(dynamic) => Type::Dynamic(dynamic.normalized()),
Type::FunctionLiteral(function) => Type::FunctionLiteral(function.normalized(db)),
Type::PropertyInstance(property) => Type::PropertyInstance(property.normalized(db)),
Type::MethodWrapper(method_kind) => Type::MethodWrapper(method_kind.normalized(db)),
Type::BoundMethod(method) => Type::BoundMethod(method.normalized(db)),
Type::BoundSuper(bound_super) => Type::BoundSuper(bound_super.normalized(db)),
Type::GenericAlias(generic) => Type::GenericAlias(generic.normalized(db)),
Type::SubclassOf(subclass_of) => Type::SubclassOf(subclass_of.normalized(db)),
Type::KnownInstance(known_instance) => {
Type::KnownInstance(known_instance.normalized(db))
}
Type::TypeVar(typevar) => match typevar.bound_or_constraints(db) {
Some(TypeVarBoundOrConstraints::UpperBound(bound)) => {
Type::TypeVar(TypeVarInstance::new(
Expand All @@ -1052,6 +1049,19 @@ impl<'db> Type<'db> {
}
None => self,
},
Type::LiteralString
| Type::AlwaysFalsy
| Type::AlwaysTruthy
| Type::BooleanLiteral(_)
| Type::BytesLiteral(_)
| Type::StringLiteral(_)
| Type::Never
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::ModuleLiteral(_)
| Type::ClassLiteral(_)
| Type::IntLiteral(_) => self,
}
}

Expand Down Expand Up @@ -5604,6 +5614,18 @@ impl<'db> TypeMapping<'_, 'db> {
TypeMapping::PromoteLiterals => TypeMapping::PromoteLiterals,
}
}

fn normalized(&self, db: &'db dyn Db) -> Self {
match self {
TypeMapping::Specialization(specialization) => {
TypeMapping::Specialization(specialization.normalized(db))
}
TypeMapping::PartialSpecialization(partial) => {
TypeMapping::PartialSpecialization(partial.normalized(db))
}
TypeMapping::PromoteLiterals => TypeMapping::PromoteLiterals,
}
}
}

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
Expand All @@ -5627,6 +5649,13 @@ pub enum DynamicType {
TodoPEP695ParamSpec,
}

impl DynamicType {
#[expect(clippy::unused_self)]
fn normalized(self) -> Self {
Self::Any
}
}

impl std::fmt::Display for DynamicType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down Expand Up @@ -5877,6 +5906,18 @@ impl<'db> TypeVarInstance<'db> {
None
}
}

pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
db,
self.name(db),
self.definition(db),
self.bound_or_constraints(db).map(|b| b.normalized(db)),
self.variance(db),
self.default_ty(db).map(|d| d.normalized(db)),
self.kind(db),
)
}
}

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update)]
Expand All @@ -5893,6 +5934,19 @@ pub enum TypeVarBoundOrConstraints<'db> {
Constraints(UnionType<'db>),
}

impl<'db> TypeVarBoundOrConstraints<'db> {
fn normalized(self, db: &'db dyn Db) -> Self {
match self {
TypeVarBoundOrConstraints::UpperBound(bound) => {
TypeVarBoundOrConstraints::UpperBound(bound.normalized(db))
}
TypeVarBoundOrConstraints::Constraints(constraints) => {
TypeVarBoundOrConstraints::Constraints(constraints.normalized(db))
}
}
}
}

/// Error returned if a type is not (or may not be) a context manager.
#[derive(Debug)]
enum ContextManagerError<'db> {
Expand Down Expand Up @@ -7123,6 +7177,29 @@ impl<'db> FunctionType<'db> {
.is_gradual_equivalent_to(db, other.into_callable_type(db))
}

fn normalized(self, db: &'db dyn Db) -> Self {
let context = self
.inherited_generic_context(db)
.map(|ctx| ctx.normalized(db));

let mappings: Box<_> = self
.type_mappings(db)
.iter()
.map(|mapping| mapping.normalized(db))
.collect();

Self::new(
db,
self.name(db),
self.known(db),
self.body_scope(db),
self.decorators(db),
self.dataclass_transformer_params(db),
context,
mappings,
)
}

/// Returns a tuple of two spans. The first is
/// the span for the identifier of the function
/// definition for `self`. The second is
Expand Down Expand Up @@ -7410,6 +7487,14 @@ impl<'db> BoundMethodType<'db> {
))
}

fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
db,
self.function(db).normalized(db),
self.self_instance(db).normalized(db),
)
}

fn is_subtype_of(self, db: &'db dyn Db, other: Self) -> bool {
// A bound method is a typically a subtype of itself. However, we must explicitly verify
// the subtyping of the underlying function signatures (since they might be specialized
Expand Down Expand Up @@ -7813,6 +7898,24 @@ impl<'db> MethodWrapperKind<'db> {
) => false,
}
}

fn normalized(self, db: &'db dyn Db) -> Self {
match self {
MethodWrapperKind::FunctionTypeDunderGet(function) => {
MethodWrapperKind::FunctionTypeDunderGet(function.normalized(db))
}
MethodWrapperKind::FunctionTypeDunderCall(function) => {
MethodWrapperKind::FunctionTypeDunderCall(function.normalized(db))
}
MethodWrapperKind::PropertyDunderGet(property) => {
MethodWrapperKind::PropertyDunderGet(property.normalized(db))
}
MethodWrapperKind::PropertyDunderSet(property) => {
MethodWrapperKind::PropertyDunderSet(property.normalized(db))
}
MethodWrapperKind::StrStartswith(_) => self,
}
}
}

/// Represents a specific instance of `types.WrapperDescriptorType`
Expand Down Expand Up @@ -7907,6 +8010,10 @@ impl<'db> PEP695TypeAliasType<'db> {
let definition = self.definition(db);
definition_expression_type(db, definition, &type_alias_stmt_node.value)
}

fn normalized(self, _db: &'db dyn Db) -> Self {
self
}
}

/// # Ordering
Expand All @@ -7921,17 +8028,35 @@ pub struct BareTypeAliasType<'db> {
pub value: Type<'db>,
}

impl<'db> BareTypeAliasType<'db> {
fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
db,
self.name(db),
self.definition(db),
self.value(db).normalized(db),
)
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update)]
pub enum TypeAliasType<'db> {
PEP695(PEP695TypeAliasType<'db>),
Bare(BareTypeAliasType<'db>),
}

impl<'db> TypeAliasType<'db> {
pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
match self {
TypeAliasType::PEP695(type_alias) => TypeAliasType::PEP695(type_alias.normalized(db)),
TypeAliasType::Bare(type_alias) => TypeAliasType::Bare(type_alias.normalized(db)),
}
}

pub(crate) fn name(self, db: &'db dyn Db) -> &'db str {
match self {
TypeAliasType::PEP695(type_alias) => type_alias.name(db),
TypeAliasType::Bare(type_alias) => type_alias.name(db).as_str(),
TypeAliasType::Bare(type_alias) => type_alias.name(db),
}
}

Expand Down Expand Up @@ -8595,6 +8720,14 @@ pub enum SuperOwnerKind<'db> {
}

impl<'db> SuperOwnerKind<'db> {
fn normalized(self, db: &'db dyn Db) -> Self {
match self {
SuperOwnerKind::Dynamic(dynamic) => SuperOwnerKind::Dynamic(dynamic.normalized()),
SuperOwnerKind::Class(class) => SuperOwnerKind::Class(class.normalized(db)),
SuperOwnerKind::Instance(instance) => SuperOwnerKind::Instance(instance.normalized(db)),
}
}

fn iter_mro(self, db: &'db dyn Db) -> impl Iterator<Item = ClassBase<'db>> {
match self {
SuperOwnerKind::Dynamic(dynamic) => {
Expand Down Expand Up @@ -8829,6 +8962,14 @@ impl<'db> BoundSuperType<'db> {
),
}
}

fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
db,
self.pivot_class(db).normalized(db),
self.owner(db).normalized(db),
)
}
}

// Make sure that the `Type` enum does not grow unexpectedly.
Expand Down
13 changes: 13 additions & 0 deletions crates/ty_python_semantic/src/types/class_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ impl<'db> ClassBase<'db> {
Self::Dynamic(DynamicType::Unknown)
}

pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
match self {
Self::Dynamic(dynamic) => Self::Dynamic(dynamic.normalized()),
Self::Class(class) => Self::Class(class.normalized(db)),
Self::Protocol(generic_context) => {
Self::Protocol(generic_context.map(|context| context.normalized(db)))
}
Self::Generic(generic_context) => {
Self::Generic(generic_context.map(|context| context.normalized(db)))
}
}
}

pub(crate) fn display(self, db: &'db dyn Db) -> impl std::fmt::Display + 'db {
struct Display<'db> {
base: ClassBase<'db>,
Expand Down
19 changes: 19 additions & 0 deletions crates/ty_python_semantic/src/types/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ impl<'db> GenericContext<'db> {

Specialization::new(db, self, expanded.into_boxed_slice())
}

pub(crate) fn normalized(self, db: &'db dyn Db) -> Self {
let variables: FxOrderSet<_> = self
.variables(db)
.iter()
.map(|ty| ty.normalized(db))
.collect();
Self::new(db, variables, self.origin(db))
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -561,6 +570,16 @@ impl<'db> PartialSpecialization<'_, 'db> {
types: Cow::from(self.types.clone().into_owned()),
}
}

pub(crate) fn normalized(&self, db: &'db dyn Db) -> PartialSpecialization<'db, 'db> {
let generic_context = self.generic_context.normalized(db);
let types: Cow<_> = self.types.iter().map(|ty| ty.normalized(db)).collect();

PartialSpecialization {
generic_context,
types,
}
}
}

/// Performs type inference between parameter annotations and argument types, producing a
Expand Down
Loading
Loading