Change inference

This commit is contained in:
David Peter
2025-06-04 14:49:41 +02:00
parent e9b1fc3942
commit 7684e23612
5 changed files with 41 additions and 17 deletions

View File

@@ -138,3 +138,12 @@ def get_name() -> str:
# error: [invalid-type-alias-type] "The name of a `typing.TypeAlias` must be a string literal"
IntOrStr = TypeAliasType(get_name(), int | str)
```
## Recursive type aliases
```py
type Recursive = dict[str, "Recursive"]
# TODO: this should not be an error
r: Recursive = {"key": {}} # error: [invalid-assignment]
```

View File

@@ -396,10 +396,11 @@ type LiteralInt = TypeOf[int]
type LiteralStr = TypeOf[str]
type LiteralObject = TypeOf[object]
assert_type(bool, LiteralBool)
assert_type(int, LiteralInt)
assert_type(str, LiteralStr)
assert_type(object, LiteralObject)
# TODO: these should not be errors
assert_type(bool, LiteralBool) # error: [type-assertion-failure]
assert_type(int, LiteralInt) # error: [type-assertion-failure]
assert_type(str, LiteralStr) # error: [type-assertion-failure]
assert_type(object, LiteralObject) # error: [type-assertion-failure]
# bool
@@ -462,9 +463,10 @@ type LiteralBase = TypeOf[Base]
type LiteralDerived = TypeOf[Derived]
type LiteralUnrelated = TypeOf[Unrelated]
assert_type(Base, LiteralBase)
assert_type(Derived, LiteralDerived)
assert_type(Unrelated, LiteralUnrelated)
# TODO: these should not be errors
assert_type(Base, LiteralBase) # error: [type-assertion-failure]
assert_type(Derived, LiteralDerived) # error: [type-assertion-failure]
assert_type(Unrelated, LiteralUnrelated) # error: [type-assertion-failure]
static_assert(is_subtype_of(LiteralBase, type))
static_assert(is_subtype_of(LiteralBase, object))

View File

@@ -992,7 +992,7 @@ impl<'db> Type<'db> {
#[must_use]
pub fn normalized(self, db: &'db dyn Db) -> Self {
match self {
Type::TypeAliasRef(_) => todo!(),
Type::TypeAliasRef(alias) => alias.value_type(db).normalized(db),
Type::Union(union) => Type::Union(union.normalized(db)),
Type::Intersection(intersection) => Type::Intersection(intersection.normalized(db)),
Type::Tuple(tuple) => Type::Tuple(tuple.normalized(db)),
@@ -1069,9 +1069,8 @@ impl<'db> Type<'db> {
(Type::Never, _) => true,
(_, Type::Never) => false,
(_, Type::TypeAliasRef(_)) | (Type::TypeAliasRef(_), _) => {
todo!()
}
(left, Type::TypeAliasRef(right)) => left.is_subtype_of(db, right.value_type(db)),
(Type::TypeAliasRef(left), right) => left.value_type(db).is_subtype_of(db, right),
// Everything is a subtype of `object`.
(_, Type::NominalInstance(instance)) if instance.class.is_object(db) => true,
@@ -1799,7 +1798,8 @@ impl<'db> Type<'db> {
(Type::Dynamic(_), _) | (_, Type::Dynamic(_)) => false,
(Type::TypeAliasRef(_), _) | (_, Type::TypeAliasRef(_)) => todo!(),
(Type::TypeAliasRef(left), right) => left.value_type(db).is_disjoint_from(db, right),
(left, Type::TypeAliasRef(right)) => left.is_disjoint_from(db, right.value_type(db)),
// A typevar is never disjoint from itself, since all occurrences of the typevar must
// be specialized to the same type. (This is an important difference between typevars
@@ -2249,7 +2249,7 @@ impl<'db> Type<'db> {
/// Returns true if the type does not contain any gradual forms (as a sub-part).
pub(crate) fn is_fully_static(&self, db: &'db dyn Db) -> bool {
match self {
Type::TypeAliasRef(_) => todo!(),
Type::TypeAliasRef(alias) => alias.value_type(db).is_fully_static(db),
Type::Dynamic(_) => false,
Type::Never
| Type::FunctionLiteral(..)
@@ -5000,7 +5000,7 @@ impl<'db> Type<'db> {
}),
Type::KnownInstance(known_instance) => match known_instance {
KnownInstanceType::TypeAliasType(alias) => Ok(alias.value_type(db)),
KnownInstanceType::TypeAliasType(alias) => Ok(Type::TypeAliasRef(*alias)),
KnownInstanceType::TypeVar(typevar) => Ok(Type::TypeVar(*typevar)),
KnownInstanceType::SubscriptedProtocol(_) => Err(InvalidTypeExpressionError {
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::Protocol],
@@ -5315,7 +5315,7 @@ impl<'db> Type<'db> {
type_mapping: &TypeMapping<'a, 'db>,
) -> Type<'db> {
match self {
Type::TypeAliasRef(_) => todo!(),
Type::TypeAliasRef(alias) => alias.value_type(db).apply_type_mapping(db, type_mapping),
Type::TypeVar(typevar) => match type_mapping {
TypeMapping::Specialization(specialization) => {
specialization.get(db, typevar).unwrap_or(self)

View File

@@ -67,7 +67,7 @@ struct DisplayRepresentation<'db> {
impl Display for DisplayRepresentation<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.ty {
Type::TypeAliasRef(_) => todo!(),
Type::TypeAliasRef(alias) => f.write_str(alias.name(self.db)),
Type::Dynamic(dynamic) => dynamic.fmt(f),
Type::Never => f.write_str("Never"),
Type::NominalInstance(instance) => {

View File

@@ -6177,7 +6177,20 @@ impl<'db> TypeInferenceBuilder<'db> {
}
match (left_ty, right_ty, op) {
(Type::TypeAliasRef(_), _, _) | (_, Type::TypeAliasRef(_), _) => todo!(),
(Type::TypeAliasRef(alias), _, _) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
alias.value_type(self.db()),
right_ty,
op,
),
(_, Type::TypeAliasRef(alias), _) => self.infer_binary_expression_type(
node,
emitted_division_by_zero_diagnostic,
left_ty,
alias.value_type(self.db()),
op,
),
(Type::Union(lhs_union), rhs, _) => {
let mut union = UnionBuilder::new(self.db());