Special-case type return
This commit is contained in:
@@ -7349,11 +7349,23 @@ impl<'db> Type<'db> {
|
||||
.to_instance(db)
|
||||
.expect("type should be convertible to instance type");
|
||||
|
||||
// Special case: if the return type is exactly `type`, treat it as returning the
|
||||
// instance type. This is a common pattern in singleton metaclasses where `__call__`
|
||||
// is annotated as `-> type` but actually returns an instance. Both mypy and pyright
|
||||
// handle this specially to avoid false positives.
|
||||
// Note: `-> type` in annotations becomes `NominalInstance(type)`.
|
||||
let returns_bare_type = matches!(
|
||||
metaclass_return_type,
|
||||
Type::NominalInstance(instance) if instance.class(db).is_known(db, KnownClass::Type)
|
||||
);
|
||||
|
||||
// Check if we should skip `__new__`/`__init__` evaluation.
|
||||
// Skip if: return type is not assignable to instance, is Never, or contains Any.
|
||||
let skip_new_init = !metaclass_return_type.is_assignable_to(db, instance_ty)
|
||||
|| metaclass_return_type.is_never()
|
||||
|| matches!(metaclass_return_type, Type::Dynamic(DynamicType::Any));
|
||||
// But don't skip if the return type is exactly `type` (common singleton pattern).
|
||||
let skip_new_init = !returns_bare_type
|
||||
&& (!metaclass_return_type.is_assignable_to(db, instance_ty)
|
||||
|| metaclass_return_type.is_never()
|
||||
|| matches!(metaclass_return_type, Type::Dynamic(DynamicType::Any)));
|
||||
|
||||
// If there are argument errors or we should skip `__new__`/`__init__`, return metaclass result.
|
||||
if call_result.is_err() || skip_new_init {
|
||||
|
||||
Reference in New Issue
Block a user