Improved handling of + operator when both operands are tuples. It now produces a more accurate type when one (but not both) of the two tuples is of indeterminate length. (#6410)

This commit is contained in:
Eric Traut 2023-11-09 17:08:38 -08:00 committed by GitHub
parent 2436c8d9aa
commit ace7edb41e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 9 deletions

View File

@ -368,20 +368,28 @@ export function validateBinaryOperation(
isClassInstance(leftSubtypeExpanded) &&
isTupleClass(leftSubtypeExpanded) &&
leftSubtypeExpanded.tupleTypeArguments &&
!isUnboundedTupleClass(leftSubtypeExpanded) &&
isClassInstance(rightSubtypeExpanded) &&
isTupleClass(rightSubtypeExpanded) &&
rightSubtypeExpanded.tupleTypeArguments &&
!isUnboundedTupleClass(rightSubtypeExpanded) &&
tupleClassType &&
isInstantiableClass(tupleClassType)
) {
return ClassType.cloneAsInstance(
specializeTupleClass(tupleClassType, [
...leftSubtypeExpanded.tupleTypeArguments,
...rightSubtypeExpanded.tupleTypeArguments,
])
);
// If at least one of the tuples is of fixed size, we can
// combine them into a precise new type. If both are unbounded
// (or contain an unbounded element), we cannot combine them
// in this manner because tuples can contain at most one
// unbounded element.
if (
!isUnboundedTupleClass(leftSubtypeExpanded) ||
!isUnboundedTupleClass(rightSubtypeExpanded)
) {
return ClassType.cloneAsInstance(
specializeTupleClass(tupleClassType, [
...leftSubtypeExpanded.tupleTypeArguments,
...rightSubtypeExpanded.tupleTypeArguments,
])
);
}
}
const magicMethodName = binaryOperatorMap[operator][0];

View File

@ -10,10 +10,18 @@ def func1(a: tuple[int, int, int], b: tuple[str, str]):
def func2(a: tuple[int, int, int], b: tuple[str, ...]):
reveal_type(a + b, expected_text="tuple[int, int, int, *tuple[str, ...]]")
def func3(a: tuple[int, ...], b: tuple[str, ...]):
reveal_type(a + b, expected_text="tuple[int | str, ...]")
def func3(input_list):
def func4(a: tuple[str, *tuple[int, ...]], b: tuple[str, int]):
reveal_type(a + b, expected_text="tuple[str, *tuple[int, ...], str, int]")
def func5(input_list):
output_tuple = ()
for _, value in enumerate([]):