[red-knot] More comprehensive is_assignable_to tests (#15353)
## Summary This changeset migrates all existing `is_assignable_to` tests to a Markdown-based test. It also increases our test coverage in a hopefully meaningful way (not claiming to be complete in any sense). But at least I found and fixed one bug while doing so. ## Test Plan Ran property tests to make sure the new test succeeds after fixing it. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
@@ -971,6 +971,9 @@ impl<'db> Type<'db> {
|
||||
return true;
|
||||
}
|
||||
match (self, target) {
|
||||
// Never can be assigned to any type.
|
||||
(Type::Never, _) => true,
|
||||
|
||||
// The dynamic type is assignable-to and assignable-from any type.
|
||||
(Type::Unknown | Type::Any | Type::Todo(_), _) => true,
|
||||
(_, Type::Unknown | Type::Any | Type::Todo(_)) => true,
|
||||
@@ -3988,7 +3991,6 @@ pub(crate) mod tests {
|
||||
},
|
||||
Tuple(Vec<Ty>),
|
||||
SubclassOfAny,
|
||||
SubclassOfUnknown,
|
||||
SubclassOfBuiltinClass(&'static str),
|
||||
SubclassOfAbcClass(&'static str),
|
||||
StdlibModule(KnownModule),
|
||||
@@ -4039,7 +4041,6 @@ pub(crate) mod tests {
|
||||
TupleType::from_elements(db, elements)
|
||||
}
|
||||
Ty::SubclassOfAny => SubclassOfType::subclass_of_any(),
|
||||
Ty::SubclassOfUnknown => SubclassOfType::subclass_of_unknown(),
|
||||
Ty::SubclassOfBuiltinClass(s) => SubclassOfType::from(
|
||||
db,
|
||||
builtins_symbol(db, s)
|
||||
@@ -4078,84 +4079,6 @@ pub(crate) mod tests {
|
||||
assert_eq!(ty.into_type(&db), Type::Never);
|
||||
}
|
||||
|
||||
#[test_case(Ty::BuiltinInstance("str"), Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::Unknown, Ty::IntLiteral(1))]
|
||||
#[test_case(Ty::Any, Ty::IntLiteral(1))]
|
||||
#[test_case(Ty::Never, Ty::IntLiteral(1))]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::Unknown)]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::Any)]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::BuiltinInstance("int"))]
|
||||
#[test_case(Ty::StringLiteral("foo"), Ty::BuiltinInstance("str"))]
|
||||
#[test_case(Ty::StringLiteral("foo"), Ty::LiteralString)]
|
||||
#[test_case(Ty::LiteralString, Ty::BuiltinInstance("str"))]
|
||||
#[test_case(Ty::BytesLiteral("foo"), Ty::BuiltinInstance("bytes"))]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::Union(vec![Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str")]))]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::Union(vec![Ty::Unknown, Ty::BuiltinInstance("str")]))]
|
||||
#[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]), Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]))]
|
||||
#[test_case(
|
||||
Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]),
|
||||
Ty::BuiltinInstance("int")
|
||||
)]
|
||||
#[test_case(
|
||||
Ty::Union(vec![Ty::IntLiteral(1), Ty::None]),
|
||||
Ty::Union(vec![Ty::BuiltinInstance("int"), Ty::None])
|
||||
)]
|
||||
#[test_case(Ty::Tuple(vec![Ty::Todo]), Ty::Tuple(vec![Ty::IntLiteral(2)]))]
|
||||
#[test_case(Ty::Tuple(vec![Ty::IntLiteral(2)]), Ty::Tuple(vec![Ty::Todo]))]
|
||||
#[test_case(Ty::SubclassOfAny, Ty::SubclassOfAny)]
|
||||
#[test_case(Ty::SubclassOfAny, Ty::SubclassOfBuiltinClass("object"))]
|
||||
#[test_case(Ty::SubclassOfAny, Ty::SubclassOfBuiltinClass("str"))]
|
||||
#[test_case(Ty::SubclassOfAny, Ty::BuiltinInstance("type"))]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("object"), Ty::SubclassOfAny)]
|
||||
#[test_case(
|
||||
Ty::SubclassOfBuiltinClass("object"),
|
||||
Ty::SubclassOfBuiltinClass("object")
|
||||
)]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("object"), Ty::BuiltinInstance("type"))]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::SubclassOfAny)]
|
||||
#[test_case(
|
||||
Ty::SubclassOfBuiltinClass("str"),
|
||||
Ty::SubclassOfBuiltinClass("object")
|
||||
)]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::SubclassOfBuiltinClass("str"))]
|
||||
#[test_case(Ty::SubclassOfBuiltinClass("str"), Ty::BuiltinInstance("type"))]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfAny)]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::BuiltinInstance("type"))]
|
||||
#[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"))]
|
||||
#[test_case(Ty::SubclassOfAny, Ty::BuiltinInstance("object"))]
|
||||
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)));
|
||||
}
|
||||
|
||||
#[test_case(Ty::BuiltinInstance("object"), Ty::BuiltinInstance("int"))]
|
||||
#[test_case(Ty::IntLiteral(1), Ty::BuiltinInstance("str"))]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str"))]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::IntLiteral(1))]
|
||||
#[test_case(
|
||||
Ty::Union(vec![Ty::IntLiteral(1), Ty::None]),
|
||||
Ty::BuiltinInstance("int")
|
||||
)]
|
||||
#[test_case(
|
||||
Ty::Union(vec![Ty::IntLiteral(1), Ty::None]),
|
||||
Ty::Union(vec![Ty::BuiltinInstance("str"), Ty::None])
|
||||
)]
|
||||
#[test_case(
|
||||
Ty::SubclassOfBuiltinClass("object"),
|
||||
Ty::SubclassOfBuiltinClass("str")
|
||||
)]
|
||||
#[test_case(Ty::BuiltinInstance("type"), Ty::SubclassOfBuiltinClass("str"))]
|
||||
fn is_not_assignable_to(from: Ty, to: Ty) {
|
||||
let db = setup_db();
|
||||
assert!(!from.into_type(&db).is_assignable_to(&db, to.into_type(&db)));
|
||||
}
|
||||
|
||||
#[test_case(Ty::BuiltinInstance("str"), Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("object"))]
|
||||
#[test_case(Ty::BuiltinInstance("bool"), Ty::BuiltinInstance("object"))]
|
||||
|
||||
@@ -220,7 +220,7 @@ macro_rules! type_property_test {
|
||||
}
|
||||
|
||||
mod stable {
|
||||
use super::KnownClass;
|
||||
use crate::types::{KnownClass, Type};
|
||||
|
||||
// `T` is equivalent to itself.
|
||||
type_property_test!(
|
||||
@@ -299,6 +299,18 @@ mod stable {
|
||||
all_fully_static_types_subtype_of_object, db,
|
||||
forall types t. t.is_fully_static(db) => t.is_subtype_of(db, KnownClass::Object.to_instance(db))
|
||||
);
|
||||
|
||||
// Never should be assignable to every type
|
||||
type_property_test!(
|
||||
never_assignable_to_every_type, db,
|
||||
forall types t. Type::Never.is_assignable_to(db, t)
|
||||
);
|
||||
|
||||
// And it should be a subtype of all fully static types
|
||||
type_property_test!(
|
||||
never_subtype_of_every_fully_static_type, db,
|
||||
forall types t. t.is_fully_static(db) => Type::Never.is_subtype_of(db, t)
|
||||
);
|
||||
}
|
||||
|
||||
/// This module contains property tests that currently lead to many false positives.
|
||||
|
||||
Reference in New Issue
Block a user