From ccb6abfa6742acb9774384fd04ce3c46fbed75bd Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 14 Dec 2024 16:14:27 +0000 Subject: [PATCH] Fix tests and add a few more --- .../resources/mdtest/type_of/dynamic.md | 9 ++++++++- crates/red_knot_python_semantic/src/types.rs | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md b/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md index edb44057333a77..519f665bad17b1 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md +++ b/crates/red_knot_python_semantic/resources/mdtest/type_of/dynamic.md @@ -1,6 +1,7 @@ # `type[Any]` -This file contains tests for non-fully-static `type[]` types, such as `type[Any]` and `type[Unknown]`. +This file contains tests for non-fully-static `type[]` types, such as `type[Any]` and +`type[Unknown]`. ## Simple @@ -80,6 +81,7 @@ def test(x: Any, y: SomethingUnknown): ## `type[Unknown]` has similar properties to `type[Any]` ```py +import abc from typing import Any from does_not_exist import SomethingUnknown # error: [unresolved-import] @@ -92,4 +94,9 @@ def test(a: type[Any], b: type[str], c: type[Any], d: type[str]): b = c c = has_unknown_type d = has_unknown_type + +def test2(a: type[Any], b: abc.ABCMeta): + """Instances of `type` subclasses are also assignable to `type[Any]` or `type[Unknown]`""" + b = a + b = has_unknown_type ``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index bbdc5dbe63c33c..5af3a9c10495ce 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -854,26 +854,26 @@ impl<'db> Type<'db> { } ( Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), Type::SubclassOf(_), ) => true, ( Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), - Type::Instance(target), - ) if target.class.is_known(db, KnownClass::Type) => true, + Type::Instance(_), + ) if target.is_subtype_of(db, KnownClass::Type.to_instance(db)) => true, ( - Type::Instance(class), + Type::Instance(_), Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), - ) if class.class.is_known(db, KnownClass::Type) => true, + ) if self.is_subtype_of(db, KnownClass::Type.to_instance(db)) => true, ( Type::ClassLiteral(_) | Type::SubclassOf(_), Type::SubclassOf(SubclassOfType { - base: ClassBase::Any, + base: ClassBase::Any | ClassBase::Todo(_) | ClassBase::Unknown, }), ) => true, // TODO other types containing gradual forms (e.g. generics containing Any/Unknown) @@ -3475,6 +3475,8 @@ pub(crate) mod tests { #[test_case(Ty::BuiltinClassLiteral("str"), Ty::SubclassOfAny)] #[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::SubclassOfUnknown)] #[test_case(Ty::SubclassOfUnknown, Ty::SubclassOfBuiltinClass("str"))] + #[test_case(Ty::SubclassOfAny, Ty::AbcInstance("ABCMeta"))] + #[test_case(Ty::SubclassOfUnknown, Ty::AbcInstance("ABCMeta"))] fn is_assignable_to(from: Ty, to: Ty) { let db = setup_db(); assert!(from.into_type(&db).is_assignable_to(&db, to.into_type(&db)));