From 46c0961b0bb6cd00e26905896eb2d150b82744b8 Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 22 Oct 2024 13:32:51 +0200 Subject: [PATCH] [red-knot] is_subtype_of: treat literals as subtype of 'object' (#13876) Add the following subtype relations: - `BooleanLiteral <: object` - `IntLiteral <: object` - `StringLiteral <: object` - `LiteralString <: object` - `BytesLiteral <: object` Added a test case for `bool <: int`. ## Test Plan New unit tests. --- crates/red_knot_python_semantic/src/types.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 92722689be..20beac4b29 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -415,6 +415,8 @@ impl<'db> Type<'db> { (_, Type::Unknown | Type::Any | Type::Todo) => false, (Type::Never, _) => true, (_, Type::Never) => false, + (_, Type::Instance(class)) if class.is_known(db, KnownClass::Object) => true, + (Type::Instance(class), _) if class.is_known(db, KnownClass::Object) => false, (Type::BooleanLiteral(_), Type::Instance(class)) if class.is_known(db, KnownClass::Bool) => { @@ -442,8 +444,6 @@ impl<'db> Type<'db> { .elements(db) .iter() .any(|&elem_ty| ty.is_subtype_of(db, elem_ty)), - (_, Type::Instance(class)) if class.is_known(db, KnownClass::Object) => true, - (Type::Instance(class), _) if class.is_known(db, KnownClass::Object) => false, (Type::Instance(self_class), Type::Instance(target_class)) => { self_class.is_subclass_of(db, target_class) } @@ -1884,13 +1884,20 @@ mod tests { #[test_case(Ty::BuiltinInstance("str"), Ty::BuiltinInstance("object"))] #[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("object"))] + #[test_case(Ty::BuiltinInstance("bool"), Ty::BuiltinInstance("object"))] + #[test_case(Ty::BuiltinInstance("bool"), Ty::BuiltinInstance("int"))] #[test_case(Ty::Never, Ty::IntLiteral(1))] #[test_case(Ty::IntLiteral(1), Ty::BuiltinInstance("int"))] + #[test_case(Ty::IntLiteral(1), Ty::BuiltinInstance("object"))] #[test_case(Ty::BooleanLiteral(true), Ty::BuiltinInstance("bool"))] + #[test_case(Ty::BooleanLiteral(true), Ty::BuiltinInstance("object"))] #[test_case(Ty::StringLiteral("foo"), Ty::BuiltinInstance("str"))] + #[test_case(Ty::StringLiteral("foo"), Ty::BuiltinInstance("object"))] #[test_case(Ty::StringLiteral("foo"), Ty::LiteralString)] #[test_case(Ty::LiteralString, Ty::BuiltinInstance("str"))] + #[test_case(Ty::LiteralString, Ty::BuiltinInstance("object"))] #[test_case(Ty::BytesLiteral("foo"), Ty::BuiltinInstance("bytes"))] + #[test_case(Ty::BytesLiteral("foo"), Ty::BuiltinInstance("object"))] #[test_case(Ty::IntLiteral(1), Ty::Union(vec![Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str")]))] #[test_case(Ty::Union(vec![Ty::BuiltinInstance("str"), Ty::BuiltinInstance("int")]), Ty::BuiltinInstance("object"))] #[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2), Ty::IntLiteral(3)]))]