Infer fixed-size tuples from infer type parameters with extends clauses at variadic positions (#51157)

* Infer fixed-size tuples from infer type parameters with extends clauses at variadic positions

* Improve the fix to handle tuples with leading variadic elements

* Fixed indentation

* Infer rest element following a variadic element with a fixed-size constraint

* Infer rest element preceding a variadic element with a fixed-size constraint

* Rewrite the test to avoid accidental union reductions
This commit is contained in:
Mateusz Burzyński
2023-01-03 19:18:09 +01:00
committed by GitHub
parent 1a943d7b68
commit 31d1d63fc8
4 changed files with 370 additions and 7 deletions

View File

@@ -24303,13 +24303,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
else {
const middleLength = targetArity - startLength - endLength;
if (middleLength === 2 && elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...T, ...U] and source is tuple type
const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
if (targetInfo && targetInfo.impliedArity !== undefined) {
// Infer slices from source based on implied arity of T.
inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
if (middleLength === 2) {
if (elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...T, ...U] and source is tuple type
const targetInfo = getInferenceInfoForType(elementTypes[startLength]);
if (targetInfo && targetInfo.impliedArity !== undefined) {
// Infer slices from source based on implied arity of T.
inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]);
inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]);
}
}
else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) {
// Middle of target is [...T, ...rest] and source is tuple type
// if T is constrained by a fixed-size tuple we might be able to use its arity to infer T
const param = getInferenceInfoForType(elementTypes[startLength])?.typeParameter;
const constraint = param && getBaseConstraintOfType(param);
if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) {
const impliedArity = constraint.target.fixedLength;
inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]);
inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]);
}
}
else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic && isTupleType(source)) {
// Middle of target is [...rest, ...T] and source is tuple type
// if T is constrained by a fixed-size tuple we might be able to use its arity to infer T
const param = getInferenceInfoForType(elementTypes[startLength + 1])?.typeParameter;
const constraint = param && getBaseConstraintOfType(param);
if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) {
const impliedArity = constraint.target.fixedLength;
const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed);
const startIndex = endIndex - impliedArity;
const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex),
/*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex));
inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]);
inferFromTypes(trailingSlice, elementTypes[startLength + 1]);
}
}
}
else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) {