Rename Type::Instance to Type::NominalInstance and InstanceType to NominalInstanceType

This commit is contained in:
Alex Waygood
2025-04-24 12:46:09 +01:00
parent 1bdb22c139
commit ffd4a7a0fc
11 changed files with 122 additions and 107 deletions

View File

@@ -1114,7 +1114,7 @@ mod tests {
fn assert_bound_string_symbol<'db>(db: &'db dyn Db, symbol: Symbol<'db>) {
assert!(matches!(
symbol,
Symbol::Type(Type::Instance(_), Boundness::Bound)
Symbol::Type(Type::NominalInstance(_), Boundness::Bound)
));
assert_eq!(symbol.expect_type(), KnownClass::Str.to_instance(db));
}

View File

@@ -50,7 +50,7 @@ pub(crate) use crate::types::narrow::infer_narrowing_constraint;
use crate::types::signatures::{Parameter, ParameterForm, Parameters};
use crate::{Db, FxOrderSet, Module, Program};
pub(crate) use class::{ClassLiteral, ClassType, GenericAlias, KnownClass};
pub(crate) use instance::InstanceType;
pub(crate) use instance::NominalInstanceType;
pub(crate) use known_instance::KnownInstanceType;
mod builder;
@@ -475,7 +475,7 @@ pub enum Type<'db> {
SubclassOf(SubclassOfType<'db>),
/// The set of Python objects with the given class in their __class__'s method resolution order.
/// Construct this variant using the `Type::instance` constructor function.
Instance(InstanceType<'db>),
NominalInstance(NominalInstanceType<'db>),
/// A single Python object that requires special treatment in the type system
KnownInstance(KnownInstanceType<'db>),
/// An instance of `builtins.property`
@@ -510,7 +510,7 @@ pub enum Type<'db> {
TypeVar(TypeVarInstance<'db>),
// A bound super object like `super()` or `super(A, A())`
// This type doesn't handle an unbound super object like `super(A)`; for that we just use
// a `Type::Instance` of `builtins.super`.
// a `Type::NominalInstance` of `builtins.super`.
BoundSuper(BoundSuperType<'db>),
// TODO protocols, overloads, generics
}
@@ -583,7 +583,7 @@ impl<'db> Type<'db> {
| Self::BooleanLiteral(_)
| Self::BytesLiteral(_)
| Self::FunctionLiteral(_)
| Self::Instance(_)
| Self::NominalInstance(_)
| Self::ModuleLiteral(_)
| Self::ClassLiteral(_)
| Self::KnownInstance(_)
@@ -888,7 +888,7 @@ impl<'db> Type<'db> {
Type::Tuple(tuple) => Type::Tuple(tuple.normalized(db)),
Type::Callable(callable) => Type::Callable(callable.normalized(db)),
Type::LiteralString
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::PropertyInstance(_)
| Type::AlwaysFalsy
| Type::AlwaysTruthy
@@ -980,7 +980,7 @@ impl<'db> Type<'db> {
(_, Type::Never) => false,
// Everything is a subtype of `object`.
(_, Type::Instance(instance)) if instance.class().is_object(db) => true,
(_, Type::NominalInstance(instance)) if instance.class().is_object(db) => true,
// A fully static typevar is always a subtype of itself, and is never a subtype of any
// other typevar, since there is no guarantee that they will be specialized to the same
@@ -1232,7 +1232,7 @@ impl<'db> Type<'db> {
metaclass_instance_type.is_subtype_of(db, target)
}),
// For example: `Type::KnownInstance(KnownInstanceType::Type)` is a subtype of `Type::Instance(_SpecialForm)`,
// For example: `Type::KnownInstance(KnownInstanceType::Type)` is a subtype of `Type::NominalInstance(_SpecialForm)`,
// because `Type::KnownInstance(KnownInstanceType::Type)` is a set with exactly one runtime value in it
// (the symbol `typing.Type`), and that symbol is known to be an instance of `typing._SpecialForm` at runtime.
(Type::KnownInstance(left), right) => {
@@ -1241,11 +1241,11 @@ impl<'db> Type<'db> {
// `bool` is a subtype of `int`, because `bool` subclasses `int`,
// which means that all instances of `bool` are also instances of `int`
(Type::Instance(self_instance), Type::Instance(target_instance)) => {
(Type::NominalInstance(self_instance), Type::NominalInstance(target_instance)) => {
self_instance.is_subtype_of(db, target_instance)
}
(Type::Instance(_), Type::Callable(_)) => {
(Type::NominalInstance(_), Type::Callable(_)) => {
let call_symbol = self.member(db, "__call__").symbol;
match call_symbol {
Symbol::Type(Type::BoundMethod(call_function), _) => call_function
@@ -1264,7 +1264,7 @@ impl<'db> Type<'db> {
// Other than the special cases enumerated above, `Instance` types and typevars are
// never subtypes of any other variants
(Type::Instance(_) | Type::TypeVar(_), _) => false,
(Type::NominalInstance(_) | Type::TypeVar(_), _) => false,
}
}
@@ -1286,7 +1286,7 @@ impl<'db> Type<'db> {
// All types are assignable to `object`.
// TODO this special case might be removable once the below cases are comprehensive
(_, Type::Instance(instance)) if instance.class().is_object(db) => true,
(_, Type::NominalInstance(instance)) if instance.class().is_object(db) => true,
// A typevar is always assignable to itself, and is never assignable to any other
// typevar, since there is no guarantee that they will be specialized to the same
@@ -1420,7 +1420,7 @@ impl<'db> Type<'db> {
// subtypes of `type[object]` are `type[...]` types (or `Never`), and `type[Any]` can
// materialize to any `type[...]` type (or to `type[Never]`, which is equivalent to
// `Never`.)
(Type::SubclassOf(subclass_of_ty), Type::Instance(_))
(Type::SubclassOf(subclass_of_ty), Type::NominalInstance(_))
if subclass_of_ty.is_dynamic()
&& (KnownClass::Type
.to_instance(db)
@@ -1432,7 +1432,7 @@ impl<'db> Type<'db> {
// Any type that is assignable to `type[object]` is also assignable to `type[Any]`,
// because `type[Any]` can materialize to `type[object]`.
(Type::Instance(_), Type::SubclassOf(subclass_of_ty))
(Type::NominalInstance(_), Type::SubclassOf(subclass_of_ty))
if subclass_of_ty.is_dynamic()
&& self.is_assignable_to(db, KnownClass::Type.to_instance(db)) =>
{
@@ -1441,11 +1441,11 @@ impl<'db> Type<'db> {
// TODO: This is a workaround to avoid false positives (e.g. when checking function calls
// with `SupportsIndex` parameters), which should be removed when we understand protocols.
(lhs, Type::Instance(instance))
(lhs, Type::NominalInstance(instance))
if instance.class().is_known(db, KnownClass::SupportsIndex) =>
{
match lhs {
Type::Instance(instance)
Type::NominalInstance(instance)
if matches!(
instance.class().known(db),
Some(KnownClass::Int | KnownClass::SupportsIndex)
@@ -1459,7 +1459,9 @@ impl<'db> Type<'db> {
}
// TODO: ditto for avoiding false positives when checking function calls with `Sized` parameters.
(lhs, Type::Instance(instance)) if instance.class().is_known(db, KnownClass::Sized) => {
(lhs, Type::NominalInstance(instance))
if instance.class().is_known(db, KnownClass::Sized) =>
{
matches!(
lhs.to_meta_type(db).member(db, "__len__"),
SymbolAndQualifiers {
@@ -1469,7 +1471,7 @@ impl<'db> Type<'db> {
)
}
(Type::Instance(self_instance), Type::Instance(target_instance)) => {
(Type::NominalInstance(self_instance), Type::NominalInstance(target_instance)) => {
self_instance.is_assignable_to(db, target_instance)
}
@@ -1477,7 +1479,7 @@ impl<'db> Type<'db> {
self_callable.is_assignable_to(db, target_callable)
}
(Type::Instance(_), Type::Callable(_)) => {
(Type::NominalInstance(_), Type::Callable(_)) => {
let call_symbol = self.member(db, "__call__").symbol;
match call_symbol {
Symbol::Type(Type::BoundMethod(call_function), _) => call_function
@@ -1517,7 +1519,9 @@ impl<'db> Type<'db> {
}
(Type::Tuple(left), Type::Tuple(right)) => left.is_equivalent_to(db, right),
(Type::Callable(left), Type::Callable(right)) => left.is_equivalent_to(db, right),
(Type::Instance(left), Type::Instance(right)) => left.is_equivalent_to(db, right),
(Type::NominalInstance(left), Type::NominalInstance(right)) => {
left.is_equivalent_to(db, right)
}
_ => self == other && self.is_fully_static(db) && other.is_fully_static(db),
}
}
@@ -1552,7 +1556,7 @@ impl<'db> Type<'db> {
(Type::TypeVar(first), Type::TypeVar(second)) => first == second,
(Type::Instance(first), Type::Instance(second)) => {
(Type::NominalInstance(first), Type::NominalInstance(second)) => {
first.is_gradual_equivalent_to(db, second)
}
@@ -1780,8 +1784,8 @@ impl<'db> Type<'db> {
.is_disjoint_from(db, other),
},
(Type::KnownInstance(known_instance), Type::Instance(instance))
| (Type::Instance(instance), Type::KnownInstance(known_instance)) => {
(Type::KnownInstance(known_instance), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::KnownInstance(known_instance)) => {
!known_instance.is_instance_of(db, instance.class())
}
@@ -1790,8 +1794,8 @@ impl<'db> Type<'db> {
known_instance_ty.is_disjoint_from(db, KnownClass::Tuple.to_instance(db))
}
(Type::BooleanLiteral(..), Type::Instance(instance))
| (Type::Instance(instance), Type::BooleanLiteral(..)) => {
(Type::BooleanLiteral(..), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::BooleanLiteral(..)) => {
// A `Type::BooleanLiteral()` must be an instance of exactly `bool`
// (it cannot be an instance of a `bool` subclass)
!KnownClass::Bool.is_subclass_of(db, instance.class())
@@ -1799,8 +1803,8 @@ impl<'db> Type<'db> {
(Type::BooleanLiteral(..), _) | (_, Type::BooleanLiteral(..)) => true,
(Type::IntLiteral(..), Type::Instance(instance))
| (Type::Instance(instance), Type::IntLiteral(..)) => {
(Type::IntLiteral(..), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::IntLiteral(..)) => {
// A `Type::IntLiteral()` must be an instance of exactly `int`
// (it cannot be an instance of an `int` subclass)
!KnownClass::Int.is_subclass_of(db, instance.class())
@@ -1811,8 +1815,8 @@ impl<'db> Type<'db> {
(Type::StringLiteral(..), Type::LiteralString)
| (Type::LiteralString, Type::StringLiteral(..)) => false,
(Type::StringLiteral(..) | Type::LiteralString, Type::Instance(instance))
| (Type::Instance(instance), Type::StringLiteral(..) | Type::LiteralString) => {
(Type::StringLiteral(..) | Type::LiteralString, Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::StringLiteral(..) | Type::LiteralString) => {
// A `Type::StringLiteral()` or a `Type::LiteralString` must be an instance of exactly `str`
// (it cannot be an instance of a `str` subclass)
!KnownClass::Str.is_subclass_of(db, instance.class())
@@ -1821,15 +1825,15 @@ impl<'db> Type<'db> {
(Type::LiteralString, Type::LiteralString) => false,
(Type::LiteralString, _) | (_, Type::LiteralString) => true,
(Type::BytesLiteral(..), Type::Instance(instance))
| (Type::Instance(instance), Type::BytesLiteral(..)) => {
(Type::BytesLiteral(..), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::BytesLiteral(..)) => {
// A `Type::BytesLiteral()` must be an instance of exactly `bytes`
// (it cannot be an instance of a `bytes` subclass)
!KnownClass::Bytes.is_subclass_of(db, instance.class())
}
(Type::SliceLiteral(..), Type::Instance(instance))
| (Type::Instance(instance), Type::SliceLiteral(..)) => {
(Type::SliceLiteral(..), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::SliceLiteral(..)) => {
// A `Type::SliceLiteral` must be an instance of exactly `slice`
// (it cannot be an instance of a `slice` subclass)
!KnownClass::Slice.is_subclass_of(db, instance.class())
@@ -1838,17 +1842,19 @@ impl<'db> Type<'db> {
// A class-literal type `X` is always disjoint from an instance type `Y`,
// unless the type expressing "all instances of `Z`" is a subtype of of `Y`,
// where `Z` is `X`'s metaclass.
(Type::ClassLiteral(class), instance @ Type::Instance(_))
| (instance @ Type::Instance(_), Type::ClassLiteral(class)) => !class
.metaclass_instance_type(db)
.is_subtype_of(db, instance),
(Type::GenericAlias(alias), instance @ Type::Instance(_))
| (instance @ Type::Instance(_), Type::GenericAlias(alias)) => !ClassType::from(alias)
(Type::ClassLiteral(class), instance @ Type::NominalInstance(_))
| (instance @ Type::NominalInstance(_), Type::ClassLiteral(class)) => !class
.metaclass_instance_type(db)
.is_subtype_of(db, instance),
(Type::GenericAlias(alias), instance @ Type::NominalInstance(_))
| (instance @ Type::NominalInstance(_), Type::GenericAlias(alias)) => {
!ClassType::from(alias)
.metaclass_instance_type(db)
.is_subtype_of(db, instance)
}
(Type::FunctionLiteral(..), Type::Instance(instance))
| (Type::Instance(instance), Type::FunctionLiteral(..)) => {
(Type::FunctionLiteral(..), Type::NominalInstance(instance))
| (Type::NominalInstance(instance), Type::FunctionLiteral(..)) => {
// A `Type::FunctionLiteral()` must be an instance of exactly `types.FunctionType`
// (it cannot be an instance of a `types.FunctionType` subclass)
!KnownClass::FunctionType.is_subclass_of(db, instance.class())
@@ -1904,13 +1910,15 @@ impl<'db> Type<'db> {
false
}
(Type::ModuleLiteral(..), other @ Type::Instance(..))
| (other @ Type::Instance(..), Type::ModuleLiteral(..)) => {
(Type::ModuleLiteral(..), other @ Type::NominalInstance(..))
| (other @ Type::NominalInstance(..), Type::ModuleLiteral(..)) => {
// Modules *can* actually be instances of `ModuleType` subclasses
other.is_disjoint_from(db, KnownClass::ModuleType.to_instance(db))
}
(Type::Instance(left), Type::Instance(right)) => left.is_disjoint_from(db, right),
(Type::NominalInstance(left), Type::NominalInstance(right)) => {
left.is_disjoint_from(db, right)
}
(Type::Tuple(tuple), Type::Tuple(other_tuple)) => {
let self_elements = tuple.elements(db);
@@ -1922,8 +1930,8 @@ impl<'db> Type<'db> {
.any(|(e1, e2)| e1.is_disjoint_from(db, *e2))
}
(Type::Tuple(..), instance @ Type::Instance(_))
| (instance @ Type::Instance(_), Type::Tuple(..)) => {
(Type::Tuple(..), instance @ Type::NominalInstance(_))
| (instance @ Type::NominalInstance(_), Type::Tuple(..)) => {
// We cannot be sure if the tuple is disjoint from the instance because:
// - 'other' might be the homogeneous arbitrary-length tuple type
// tuple[T, ...] (which we don't have support for yet); if all of
@@ -1983,7 +1991,7 @@ impl<'db> Type<'db> {
!matches!(bound_super.pivot_class(db), ClassBase::Dynamic(_))
&& !matches!(bound_super.owner(db), SuperOwnerKind::Dynamic(_))
}
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::Instance(_) => {
Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::NominalInstance(_) => {
// TODO: Ideally, we would iterate over the MRO of the class, check if all
// bases are fully static, and only return `true` if that is the case.
//
@@ -2089,7 +2097,7 @@ impl<'db> Type<'db> {
false
}
Type::DataclassDecorator(_) | Type::DataclassTransformer(_) => false,
Type::Instance(instance) => instance.is_singleton(db),
Type::NominalInstance(instance) => instance.is_singleton(db),
Type::PropertyInstance(_) => false,
Type::Tuple(..) => {
// The empty tuple is a singleton on CPython and PyPy, but not on other Python
@@ -2161,7 +2169,7 @@ impl<'db> Type<'db> {
.iter()
.all(|elem| elem.is_single_valued(db)),
Type::Instance(instance) => instance.is_single_valued(db),
Type::NominalInstance(instance) => instance.is_single_valued(db),
Type::BoundSuper(_) => {
// At runtime two super instances never compare equal, even if their arguments are identical.
@@ -2299,10 +2307,11 @@ impl<'db> Type<'db> {
.to_class_literal(db)
.find_name_in_mro_with_policy(db, name, policy),
// We eagerly normalize type[object], i.e. Type::SubclassOf(object) to `type`, i.e. Type::Instance(type).
// So looking up a name in the MRO of `Type::Instance(type)` is equivalent to looking up the name in the
// We eagerly normalize type[object], i.e. Type::SubclassOf(object) to `type`,
// i.e. Type::NominalInstance(type). So looking up a name in the MRO of
// `Type::NominalInstance(type)` is equivalent to looking up the name in the
// MRO of the class `object`.
Type::Instance(instance) if instance.class().is_known(db, KnownClass::Type) => {
Type::NominalInstance(instance) if instance.class().is_known(db, KnownClass::Type) => {
KnownClass::Object
.to_class_literal(db)
.find_name_in_mro_with_policy(db, name, policy)
@@ -2327,7 +2336,7 @@ impl<'db> Type<'db> {
| Type::SliceLiteral(_)
| Type::Tuple(_)
| Type::TypeVar(_)
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::PropertyInstance(_) => None,
}
}
@@ -2392,7 +2401,7 @@ impl<'db> Type<'db> {
Type::Dynamic(_) | Type::Never => Symbol::bound(self).into(),
Type::Instance(instance) => instance.class().instance_member(db, name),
Type::NominalInstance(instance) => instance.class().instance_member(db, name),
Type::FunctionLiteral(_) => KnownClass::FunctionType
.to_instance(db)
@@ -2833,7 +2842,7 @@ impl<'db> Type<'db> {
.to_instance(db)
.member_lookup_with_policy(db, name, policy),
Type::Instance(instance)
Type::NominalInstance(instance)
if matches!(name.as_str(), "major" | "minor")
&& instance.class().is_known(db, KnownClass::VersionInfo) =>
{
@@ -2875,7 +2884,7 @@ impl<'db> Type<'db> {
policy,
),
Type::Instance(..)
Type::NominalInstance(..)
| Type::BooleanLiteral(..)
| Type::IntLiteral(..)
| Type::StringLiteral(..)
@@ -3167,7 +3176,7 @@ impl<'db> Type<'db> {
}
},
Type::Instance(instance) => match instance.class().known(db) {
Type::NominalInstance(instance) => match instance.class().known(db) {
Some(known_class) => known_class.bool(),
None => try_dunder_bool()?,
},
@@ -3911,7 +3920,7 @@ impl<'db> Type<'db> {
SubclassOfInner::Class(class) => Type::from(class).signatures(db),
},
Type::Instance(_) => {
Type::NominalInstance(_) => {
// Note that for objects that have a (possibly not callable!) `__call__` attribute,
// we will get the signature of the `__call__` attribute, but will pass in the type
// of the original object as the "callable type". That ensures that we get errors
@@ -4361,7 +4370,7 @@ impl<'db> Type<'db> {
| Type::WrapperDescriptor(_)
| Type::DataclassDecorator(_)
| Type::DataclassTransformer(_)
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::KnownInstance(_)
| Type::PropertyInstance(_)
| Type::ModuleLiteral(_)
@@ -4381,7 +4390,7 @@ impl<'db> Type<'db> {
///
/// For example, the builtin `int` as a value expression is of type
/// `Type::ClassLiteral(builtins.int)`, that is, it is the `int` class itself. As a type
/// expression, it names the type `Type::Instance(builtins.int)`, that is, all objects whose
/// expression, it names the type `Type::NominalInstance(builtins.int)`, that is, all objects whose
/// `__class__` is `int`.
pub fn in_type_expression(
&self,
@@ -4558,7 +4567,7 @@ impl<'db> Type<'db> {
Type::Dynamic(_) => Ok(*self),
Type::Instance(instance) => match instance.class().known(db) {
Type::NominalInstance(instance) => match instance.class().known(db) {
Some(KnownClass::TypeVar) => Ok(todo_type!(
"Support for `typing.TypeVar` instances in type expressions"
)),
@@ -4634,7 +4643,7 @@ impl<'db> Type<'db> {
pub fn to_meta_type(&self, db: &'db dyn Db) -> Type<'db> {
match self {
Type::Never => Type::Never,
Type::Instance(instance) => instance.to_meta_type(db),
Type::NominalInstance(instance) => instance.to_meta_type(db),
Type::KnownInstance(known_instance) => known_instance.to_meta_type(db),
Type::PropertyInstance(_) => KnownClass::Property.to_class_literal(db),
Type::Union(union) => union.map(db, |ty| ty.to_meta_type(db)),
@@ -4805,7 +4814,7 @@ impl<'db> Type<'db> {
| Type::BoundSuper(_)
// Instance contains a ClassType, which has already been specialized if needed, like
// above with BoundMethod's self_instance.
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::KnownInstance(_) => self,
}
}
@@ -4869,7 +4878,7 @@ impl<'db> Type<'db> {
Some(TypeDefinition::Class(class_literal.definition(db)))
}
Self::GenericAlias(alias) => Some(TypeDefinition::Class(alias.definition(db))),
Self::Instance(instance) => {
Self::NominalInstance(instance) => {
Some(TypeDefinition::Class(instance.class().definition(db)))
}
Self::KnownInstance(instance) => match instance {
@@ -7457,7 +7466,7 @@ impl BoundSuperError<'_> {
pub enum SuperOwnerKind<'db> {
Dynamic(DynamicType),
Class(ClassType<'db>),
Instance(InstanceType<'db>),
Instance(NominalInstanceType<'db>),
}
impl<'db> SuperOwnerKind<'db> {
@@ -7491,7 +7500,7 @@ impl<'db> SuperOwnerKind<'db> {
Type::ClassLiteral(class_literal) => Some(SuperOwnerKind::Class(
class_literal.apply_optional_specialization(db, None),
)),
Type::Instance(instance) => Some(SuperOwnerKind::Instance(instance)),
Type::NominalInstance(instance) => Some(SuperOwnerKind::Instance(instance)),
Type::BooleanLiteral(_) => {
SuperOwnerKind::try_from_type(db, KnownClass::Bool.to_instance(db))
}

View File

@@ -611,7 +611,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
Type::AlwaysFalsy if addition_is_bool_instance => {
new_positive = Type::BooleanLiteral(false);
}
Type::Instance(instance)
Type::NominalInstance(instance)
if instance.class().is_known(db, KnownClass::Bool) =>
{
match new_positive {
@@ -722,7 +722,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
Type::Never => {
// Adding ~Never to an intersection is a no-op.
}
Type::Instance(instance) if instance.class().is_object(db) => {
Type::NominalInstance(instance) if instance.class().is_object(db) => {
// Adding ~object to an intersection results in Never.
*self = Self::default();
self.positive.insert(Type::Never);

View File

@@ -78,12 +78,14 @@ impl<'db> ClassBase<'db> {
Self::Class(literal.default_specialization(db))
}),
Type::GenericAlias(generic) => Some(Self::Class(ClassType::Generic(generic))),
Type::Instance(instance) if instance.class().is_known(db, KnownClass::GenericAlias) => {
Type::NominalInstance(instance)
if instance.class().is_known(db, KnownClass::GenericAlias) =>
{
Self::try_from_type(db, todo_type!("GenericAlias instance"))
}
Type::Union(_) => None, // TODO -- forces consideration of multiple possible MROs?
Type::Intersection(_) => None, // TODO -- probably incorrect?
Type::Instance(_) => None, // TODO -- handle `__mro_entries__`?
Type::NominalInstance(_) => None, // TODO -- handle `__mro_entries__`?
Type::PropertyInstance(_) => None,
Type::Never
| Type::BooleanLiteral(_)

View File

@@ -73,12 +73,14 @@ impl Display for DisplayRepresentation<'_> {
match self.ty {
Type::Dynamic(dynamic) => dynamic.fmt(f),
Type::Never => f.write_str("Never"),
Type::Instance(instance) => match (instance.class(), instance.class().known(self.db)) {
(_, Some(KnownClass::NoneType)) => f.write_str("None"),
(_, Some(KnownClass::NoDefaultType)) => f.write_str("NoDefault"),
(ClassType::NonGeneric(class), _) => f.write_str(class.name(self.db)),
(ClassType::Generic(alias), _) => write!(f, "{}", alias.display(self.db)),
},
Type::NominalInstance(instance) => {
match (instance.class(), instance.class().known(self.db)) {
(_, Some(KnownClass::NoneType)) => f.write_str("None"),
(_, Some(KnownClass::NoDefaultType)) => f.write_str("NoDefault"),
(ClassType::NonGeneric(class), _) => f.write_str(class.name(self.db)),
(ClassType::Generic(alias), _) => write!(f, "{}", alias.display(self.db)),
}
}
Type::PropertyInstance(_) => f.write_str("property"),
Type::ModuleLiteral(module) => {
write!(f, "<module '{}'>", module.module(self.db).name())

View File

@@ -1064,7 +1064,7 @@ impl<'db> TypeInferenceBuilder<'db> {
) -> bool {
match left {
Type::BooleanLiteral(_) | Type::IntLiteral(_) => {}
Type::Instance(instance)
Type::NominalInstance(instance)
if matches!(
instance.class().known(self.db()),
Some(KnownClass::Float | KnownClass::Int | KnownClass::Bool)
@@ -2515,7 +2515,7 @@ impl<'db> TypeInferenceBuilder<'db> {
}
// Super instances do not allow attribute assignment
Type::Instance(instance) if instance.class().is_known(db, KnownClass::Super) => {
Type::NominalInstance(instance) if instance.class().is_known(db, KnownClass::Super) => {
if emit_diagnostics {
if let Some(builder) = self.context.report_lint(&INVALID_ASSIGNMENT, target) {
builder.into_diagnostic(format_args!(
@@ -2540,7 +2540,7 @@ impl<'db> TypeInferenceBuilder<'db> {
Type::Dynamic(..) | Type::Never => true,
Type::Instance(..)
Type::NominalInstance(..)
| Type::BooleanLiteral(..)
| Type::IntLiteral(..)
| Type::StringLiteral(..)
@@ -3031,7 +3031,7 @@ impl<'db> TypeInferenceBuilder<'db> {
}
// Handle various singletons.
if let Type::Instance(instance) = declared_ty.inner_type() {
if let Type::NominalInstance(instance) = declared_ty.inner_type() {
if instance
.class()
.is_known(self.db(), KnownClass::SpecialForm)
@@ -5007,7 +5007,7 @@ impl<'db> TypeInferenceBuilder<'db> {
| Type::ClassLiteral(_)
| Type::GenericAlias(_)
| Type::SubclassOf(_)
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::KnownInstance(_)
| Type::PropertyInstance(_)
| Type::Union(_)
@@ -5287,7 +5287,7 @@ impl<'db> TypeInferenceBuilder<'db> {
| Type::ClassLiteral(_)
| Type::GenericAlias(_)
| Type::SubclassOf(_)
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::KnownInstance(_)
| Type::PropertyInstance(_)
| Type::Intersection(_)
@@ -5312,7 +5312,7 @@ impl<'db> TypeInferenceBuilder<'db> {
| Type::ClassLiteral(_)
| Type::GenericAlias(_)
| Type::SubclassOf(_)
| Type::Instance(_)
| Type::NominalInstance(_)
| Type::KnownInstance(_)
| Type::PropertyInstance(_)
| Type::Intersection(_)
@@ -5745,13 +5745,13 @@ impl<'db> TypeInferenceBuilder<'db> {
right_ty: right,
}),
},
(Type::IntLiteral(_), Type::Instance(_)) => self.infer_binary_type_comparison(
(Type::IntLiteral(_), Type::NominalInstance(_)) => self.infer_binary_type_comparison(
KnownClass::Int.to_instance(self.db()),
op,
right,
range,
),
(Type::Instance(_), Type::IntLiteral(_)) => self.infer_binary_type_comparison(
(Type::NominalInstance(_), Type::IntLiteral(_)) => self.infer_binary_type_comparison(
left,
op,
KnownClass::Int.to_instance(self.db()),
@@ -5877,7 +5877,7 @@ impl<'db> TypeInferenceBuilder<'db> {
KnownClass::Bytes.to_instance(self.db()),
range,
),
(Type::Tuple(_), Type::Instance(instance))
(Type::Tuple(_), Type::NominalInstance(instance))
if instance
.class()
.is_known(self.db(), KnownClass::VersionInfo) =>
@@ -5889,7 +5889,7 @@ impl<'db> TypeInferenceBuilder<'db> {
range,
)
}
(Type::Instance(instance), Type::Tuple(_))
(Type::NominalInstance(instance), Type::Tuple(_))
if instance
.class()
.is_known(self.db(), KnownClass::VersionInfo) =>
@@ -6275,7 +6275,7 @@ impl<'db> TypeInferenceBuilder<'db> {
) -> Type<'db> {
match (value_ty, slice_ty) {
(
Type::Instance(instance),
Type::NominalInstance(instance),
Type::IntLiteral(_) | Type::BooleanLiteral(_) | Type::SliceLiteral(_),
) if instance
.class()
@@ -6576,7 +6576,7 @@ impl<'db> TypeInferenceBuilder<'db> {
Err(_) => SliceArg::Unsupported,
},
Some(Type::BooleanLiteral(b)) => SliceArg::Arg(Some(i32::from(b))),
Some(Type::Instance(instance))
Some(Type::NominalInstance(instance))
if instance.class().is_known(self.db(), KnownClass::NoneType) =>
{
SliceArg::Arg(None)

View File

@@ -5,12 +5,12 @@ use crate::Db;
impl<'db> Type<'db> {
pub(crate) const fn instance(class: ClassType<'db>) -> Self {
Self::Instance(InstanceType { class })
Self::NominalInstance(NominalInstanceType { class })
}
pub(crate) const fn into_instance(self) -> Option<InstanceType<'db>> {
pub(crate) const fn into_instance(self) -> Option<NominalInstanceType<'db>> {
match self {
Type::Instance(instance_type) => Some(instance_type),
Type::NominalInstance(instance_type) => Some(instance_type),
_ => None,
}
}
@@ -18,13 +18,13 @@ impl<'db> Type<'db> {
/// A type representing the set of runtime objects which are instances of a certain nominal class.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update)]
pub struct InstanceType<'db> {
// Keep this field private, so that the only way of constructing `InstanceType` instances
pub struct NominalInstanceType<'db> {
// Keep this field private, so that the only way of constructing `NominalInstanceType` instances
// is through the `Type::instance` constructor function.
class: ClassType<'db>,
}
impl<'db> InstanceType<'db> {
impl<'db> NominalInstanceType<'db> {
pub(super) fn class(self) -> ClassType<'db> {
self.class
}
@@ -87,8 +87,8 @@ impl<'db> InstanceType<'db> {
}
}
impl<'db> From<InstanceType<'db>> for Type<'db> {
fn from(value: InstanceType<'db>) -> Self {
Self::Instance(value)
impl<'db> From<NominalInstanceType<'db>> for Type<'db> {
fn from(value: NominalInstanceType<'db>) -> Self {
Self::NominalInstance(value)
}
}

View File

@@ -1,6 +1,6 @@
//! The `KnownInstance` type.
//!
//! Despite its name, this is quite a different type from [`super::InstanceType`].
//! Despite its name, this is quite a different type from [`super::NominalInstanceType`].
//! For the vast majority of instance-types in Python, we cannot say how many possible
//! inhabitants there are or could be of that type at runtime. Each variant of the
//! [`KnownInstanceType`] enum, however, represents a specific runtime symbol
@@ -249,7 +249,7 @@ impl<'db> KnownInstanceType<'db> {
///
/// For example, the symbol `typing.Literal` is an instance of `typing._SpecialForm`,
/// so `KnownInstanceType::Literal.instance_fallback(db)`
/// returns `Type::Instance(InstanceType { class: <typing._SpecialForm> })`.
/// returns `Type::NominalInstance(NominalInstanceType { class: <typing._SpecialForm> })`.
pub(super) fn instance_fallback(self, db: &dyn Db) -> Type {
self.class().to_instance(db)
}

View File

@@ -472,7 +472,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
union.map(db, |ty| filter_to_cannot_be_equal(db, *ty, rhs_ty))
}
// Treat `bool` as `Literal[True, False]`.
Type::Instance(instance) if instance.class().is_known(db, KnownClass::Bool) => {
Type::NominalInstance(instance) if instance.class().is_known(db, KnownClass::Bool) => {
UnionType::from_elements(
db,
[Type::BooleanLiteral(true), Type::BooleanLiteral(false)]
@@ -501,7 +501,7 @@ impl<'db> NarrowingConstraintsBuilder<'db> {
fn evaluate_expr_ne(&mut self, lhs_ty: Type<'db>, rhs_ty: Type<'db>) -> Option<Type<'db>> {
match (lhs_ty, rhs_ty) {
(Type::Instance(instance), Type::IntLiteral(i))
(Type::NominalInstance(instance), Type::IntLiteral(i))
if instance.class().is_known(self.db, KnownClass::Bool) =>
{
if i == 0 {

View File

@@ -16,8 +16,8 @@ impl<'db> SubclassOfType<'db> {
/// This method does not always return a [`Type::SubclassOf`] variant.
/// If the class object is known to be a final class,
/// this method will return a [`Type::ClassLiteral`] variant; this is a more precise type.
/// If the class object is `builtins.object`, `Type::Instance(<builtins.type>)` will be returned;
/// this is no more precise, but it is exactly equivalent to `type[object]`.
/// If the class object is `builtins.object`, `Type::NominalInstance(<builtins.type>)`
/// will be returned; this is no more precise, but it is exactly equivalent to `type[object]`.
///
/// The eager normalization here means that we do not need to worry elsewhere about distinguishing
/// between `@final` classes and other classes when dealing with [`Type::SubclassOf`] variants.

View File

@@ -126,10 +126,12 @@ pub(super) fn union_or_intersection_elements_ordering<'db>(
(Type::SubclassOf(_), _) => Ordering::Less,
(_, Type::SubclassOf(_)) => Ordering::Greater,
(Type::Instance(left), Type::Instance(right)) => left.class().cmp(&right.class()),
(Type::NominalInstance(left), Type::NominalInstance(right)) => {
left.class().cmp(&right.class())
}
(Type::Instance(_), _) => Ordering::Less,
(_, Type::Instance(_)) => Ordering::Greater,
(Type::NominalInstance(_), _) => Ordering::Less,
(_, Type::NominalInstance(_)) => Ordering::Greater,
(Type::TypeVar(left), Type::TypeVar(right)) => left.cmp(right),
(Type::TypeVar(_), _) => Ordering::Less,