Skip to content

Commit

Permalink
[red-knot] Fix is_assignable_to for unions (#14196)
Browse files Browse the repository at this point in the history
## Summary

Fix `Type::is_assignable_to` for union types on the left hand side (of
`.is_assignable_to`; or the right hand side of the `… = …` assignment):

`Literal[1, 2]` should be assignable to `int`.

## Test Plan

New unit tests that were previously failing.
  • Loading branch information
sharkdp authored Nov 8, 2024
1 parent d1ef418 commit fed35a2
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions crates/red_knot_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,10 @@ impl<'db> Type<'db> {
match (self, target) {
(Type::Unknown | Type::Any | Type::Todo, _) => true,
(_, Type::Unknown | Type::Any | Type::Todo) => true,
(Type::Union(union), ty) => union
.elements(db)
.iter()
.all(|&elem_ty| elem_ty.is_assignable_to(db, ty)),
(ty, Type::Union(union)) => union
.elements(db)
.iter()
Expand Down Expand Up @@ -2765,6 +2769,14 @@ mod tests {
#[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]))]
fn is_assignable_to(from: Ty, to: Ty) {
Expand All @@ -2776,6 +2788,14 @@ mod tests {
#[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])
)]
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)));
Expand Down

0 comments on commit fed35a2

Please sign in to comment.