Special-case type return

This commit is contained in:
Charlie Marsh
2025-12-31 13:35:52 -05:00
parent ebe4f00b82
commit 6ea342e548
2 changed files with 49 additions and 3 deletions

View File

@@ -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 {