Skip to content

Commit 9da9d25

Browse files
committed
[ty] Remove use of ClassBase::try_from_type from super() machinery
1 parent df0648a commit 9da9d25

File tree

2 files changed

+30
-16
lines changed

2 files changed

+30
-16
lines changed

crates/ty_python_semantic/resources/mdtest/class/super.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,9 @@ instance or a subclass of the first. If either condition is violated, a `TypeErr
331331
runtime.
332332

333333
```py
334+
import typing
335+
import collections
336+
334337
def f(x: int):
335338
# error: [invalid-super-argument] "`int` is not a valid class"
336339
super(x, x)
@@ -367,6 +370,16 @@ reveal_type(super(B, A))
367370
reveal_type(super(B, object))
368371

369372
super(object, object()).__class__
373+
374+
# Not all objects valid in a class's bases list are valid as the first argument to `super()`.
375+
# For example, it's valid to inherit from `typing.ChainMap`, but it's not valid as the first argument to `super()`.
376+
#
377+
# error: [invalid-super-argument] "`typing.ChainMap` is not a valid class"
378+
reveal_type(super(typing.ChainMap, collections.ChainMap())) # revealed: Unknown
379+
380+
# Meanwhile, it's not valid to inherit from unsubscripted `typing.Generic`,
381+
# but it *is* valid as the first argument to `super()`.
382+
reveal_type(super(typing.Generic, typing.SupportsInt)) # revealed: <super: typing.Generic, <class 'SupportsInt'>>
370383
```
371384

372385
### Instance Member Access via `super`

crates/ty_python_semantic/src/types.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9389,23 +9389,24 @@ impl<'db> BoundSuperType<'db> {
93899389
));
93909390
}
93919391

9392-
// TODO: having to get a class-literal just to pass it in here is silly.
9393-
// `BoundSuperType` should probably not be using `ClassBase::try_from_type` here;
9394-
// this also leads to false negatives in some cases. See discussion in
9395-
// <https://github.com/astral-sh/ruff/pull/19560#discussion_r2271570071>.
9396-
let pivot_class = ClassBase::try_from_type(
9397-
db,
9398-
pivot_class_type,
9399-
KnownClass::Object
9400-
.to_class_literal(db)
9401-
.into_class_literal()
9402-
.expect("`object` should always exist in typeshed"),
9403-
)
9404-
.ok_or({
9405-
BoundSuperError::InvalidPivotClassType {
9406-
pivot_class: pivot_class_type,
9392+
// We don't use `Classbase::try_from_type` here because:
9393+
// - There are objects that may validly be present in a class's bases list
9394+
// but are not valid as pivot classes, e.g. `typing.ChainMap`
9395+
// - There are objects that are not valid in a class's bases list
9396+
// but are valid as pivot classes, e.g. unsubscripted `typing.Generic`
9397+
let pivot_class = match pivot_class_type {
9398+
Type::ClassLiteral(class) => ClassBase::Class(ClassType::NonGeneric(class)),
9399+
Type::GenericAlias(class) => ClassBase::Class(ClassType::Generic(class)),
9400+
Type::SpecialForm(SpecialFormType::Protocol) => ClassBase::Protocol,
9401+
Type::SpecialForm(SpecialFormType::Generic) => ClassBase::Generic,
9402+
Type::SpecialForm(SpecialFormType::TypedDict) => ClassBase::TypedDict,
9403+
Type::Dynamic(dynamic) => ClassBase::Dynamic(dynamic),
9404+
_ => {
9405+
return Err(BoundSuperError::InvalidPivotClassType {
9406+
pivot_class: pivot_class_type,
9407+
});
94079408
}
9408-
})?;
9409+
};
94099410

94109411
let owner = SuperOwnerKind::try_from_type(db, owner_type)
94119412
.and_then(|owner| {

0 commit comments

Comments
 (0)