mirror of https://github.com/astral-sh/ruff
[ty] Allow `tuple[Any, ...]` to assign to `tuple[int, *tuple[int, ...]]` (#21803)
## Summary Closes https://github.com/astral-sh/ty/issues/1750.
This commit is contained in:
parent
9714c589e1
commit
ef45c97dab
|
|
@ -537,6 +537,9 @@ static_assert(is_assignable_to(tuple[Any, ...], tuple[Any, Any]))
|
||||||
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, ...]))
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, ...]))
|
||||||
static_assert(is_assignable_to(tuple[Any, ...], tuple[int]))
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[int]))
|
||||||
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, int]))
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, int]))
|
||||||
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, *tuple[int, ...]]))
|
||||||
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[*tuple[int, ...], int]))
|
||||||
|
static_assert(is_assignable_to(tuple[Any, ...], tuple[int, *tuple[int, ...], int]))
|
||||||
```
|
```
|
||||||
|
|
||||||
This also applies when `tuple[Any, ...]` is unpacked into a mixed tuple.
|
This also applies when `tuple[Any, ...]` is unpacked into a mixed tuple.
|
||||||
|
|
@ -560,6 +563,10 @@ static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int, ...]))
|
||||||
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int]))
|
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int]))
|
||||||
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int, int]))
|
static_assert(is_assignable_to(tuple[*tuple[Any, ...], int], tuple[int, int]))
|
||||||
|
|
||||||
|
# `*tuple[Any, ...]` can materialize to a tuple of any length as a special case,
|
||||||
|
# so this passes:
|
||||||
|
static_assert(is_assignable_to(tuple[*tuple[Any, ...], Any], tuple[*tuple[Any, ...], Any, Any]))
|
||||||
|
|
||||||
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, *tuple[Any, ...], int]))
|
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[int, *tuple[Any, ...], int]))
|
||||||
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any, ...]))
|
static_assert(is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any, ...]))
|
||||||
static_assert(not is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any]))
|
static_assert(not is_assignable_to(tuple[int, *tuple[Any, ...], int], tuple[Any]))
|
||||||
|
|
@ -580,6 +587,9 @@ static_assert(not is_assignable_to(tuple[int, ...], tuple[Any, Any]))
|
||||||
static_assert(is_assignable_to(tuple[int, ...], tuple[int, ...]))
|
static_assert(is_assignable_to(tuple[int, ...], tuple[int, ...]))
|
||||||
static_assert(not is_assignable_to(tuple[int, ...], tuple[int]))
|
static_assert(not is_assignable_to(tuple[int, ...], tuple[int]))
|
||||||
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, int]))
|
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, int]))
|
||||||
|
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, *tuple[int, ...]]))
|
||||||
|
static_assert(not is_assignable_to(tuple[int, ...], tuple[*tuple[int, ...], int]))
|
||||||
|
static_assert(not is_assignable_to(tuple[int, ...], tuple[int, *tuple[int, ...], int]))
|
||||||
|
|
||||||
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, *tuple[Any, ...]]))
|
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[int, *tuple[Any, ...]]))
|
||||||
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[Any, ...]))
|
static_assert(is_assignable_to(tuple[int, *tuple[int, ...]], tuple[Any, ...]))
|
||||||
|
|
|
||||||
|
|
@ -998,10 +998,22 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
relation_visitor,
|
relation_visitor,
|
||||||
disjointness_visitor,
|
disjointness_visitor,
|
||||||
),
|
),
|
||||||
EitherOrBoth::Right(_) => {
|
EitherOrBoth::Right(other_ty) => {
|
||||||
// The rhs has a required element that the lhs is not guaranteed to
|
// The rhs has a required element that the lhs is not guaranteed to
|
||||||
// provide.
|
// provide, unless the lhs has a dynamic variable-length portion
|
||||||
return ConstraintSet::from(false);
|
// that can materialize to provide it (for assignability only),
|
||||||
|
// as in `tuple[Any, ...]` matching `tuple[int, int]`.
|
||||||
|
if !relation.is_assignability() || !self.variable.is_dynamic() {
|
||||||
|
return ConstraintSet::from(false);
|
||||||
|
}
|
||||||
|
self.variable.has_relation_to_impl(
|
||||||
|
db,
|
||||||
|
other_ty,
|
||||||
|
inferable,
|
||||||
|
relation,
|
||||||
|
relation_visitor,
|
||||||
|
disjointness_visitor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if result
|
if result
|
||||||
|
|
@ -1037,10 +1049,22 @@ impl<'db> VariableLengthTuple<Type<'db>> {
|
||||||
relation_visitor,
|
relation_visitor,
|
||||||
disjointness_visitor,
|
disjointness_visitor,
|
||||||
),
|
),
|
||||||
EitherOrBoth::Right(_) => {
|
EitherOrBoth::Right(other_ty) => {
|
||||||
// The rhs has a required element that the lhs is not guaranteed to
|
// The rhs has a required element that the lhs is not guaranteed to
|
||||||
// provide.
|
// provide, unless the lhs has a dynamic variable-length portion
|
||||||
return ConstraintSet::from(false);
|
// that can materialize to provide it (for assignability only),
|
||||||
|
// as in `tuple[Any, ...]` matching `tuple[int, int]`.
|
||||||
|
if !relation.is_assignability() || !self.variable.is_dynamic() {
|
||||||
|
return ConstraintSet::from(false);
|
||||||
|
}
|
||||||
|
self.variable.has_relation_to_impl(
|
||||||
|
db,
|
||||||
|
*other_ty,
|
||||||
|
inferable,
|
||||||
|
relation,
|
||||||
|
relation_visitor,
|
||||||
|
disjointness_visitor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if result
|
if result
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue