Remove logic that pads array literals contextually typed by tuple types

This commit is contained in:
Anders Hejlsberg 2019-06-28 16:54:42 -10:00
parent 2af8ac73ff
commit 2e5249835d

View File

@ -722,6 +722,7 @@ namespace ts {
NoIndexSignatures = 1 << 0,
Writing = 1 << 1,
CacheSymbol = 1 << 2,
NoTupleBoundsCheck = 1 << 3,
}
const enum CallbackCheck {
@ -5115,21 +5116,25 @@ namespace ts {
}
else if (isArrayLikeType(parentType)) {
const indexType = getLiteralType(index);
const declaredType = getConstraintForLocation(getIndexedAccessType(parentType, indexType, declaration.name), declaration.name);
const accessFlags = hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0;
const declaredType = getConstraintForLocation(getIndexedAccessTypeOrUndefined(parentType, indexType, declaration.name, accessFlags) || errorType, declaration.name);
type = getFlowTypeOfDestructuring(declaration, declaredType);
}
else {
type = elementType;
}
}
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
if (strictNullChecks && declaration.initializer && !(getFalsyFlags(checkDeclarationInitializer(declaration)) & TypeFlags.Undefined)) {
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
if (!declaration.initializer) {
return type;
}
return declaration.initializer && !getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration)) ?
getUnionType([type, checkDeclarationInitializer(declaration)], UnionReduction.Subtype) :
type;
if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) {
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
return strictNullChecks && !(getFalsyFlags(checkDeclarationInitializer(declaration)) & TypeFlags.Undefined) ?
getTypeWithFacts(type, TypeFacts.NEUndefined) :
type;
}
return getUnionType([getTypeWithFacts(type, TypeFacts.NEUndefined), checkDeclarationInitializer(declaration)], UnionReduction.Subtype);
}
function getTypeForDeclarationFromJSDocComment(declaration: Node) {
@ -10131,7 +10136,7 @@ namespace ts {
propType;
}
if (everyType(objectType, isTupleType) && isNumericLiteralName(propName) && +propName >= 0) {
if (accessNode && everyType(objectType, t => !(<TupleTypeReference>t).target.hasRestElement)) {
if (accessNode && everyType(objectType, t => !(<TupleTypeReference>t).target.hasRestElement) && !(accessFlags & AccessFlags.NoTupleBoundsCheck)) {
const indexNode = getIndexNodeForAccessExpression(accessNode);
if (isTupleType(objectType)) {
error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2,
@ -19196,26 +19201,7 @@ namespace ts {
function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length, readonly = false) {
// Infer a tuple type when the contextual type is or contains a tuple-like type
if (readonly || (contextualType && forEachType(contextualType, isTupleLikeType))) {
const minLength = elementCount - (hasRestElement ? 1 : 0);
const pattern = contextualType && contextualType.pattern;
// If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting
// tuple type with the corresponding binding or assignment element types to make the lengths equal.
if (!hasRestElement && pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) {
const patternElements = (<BindingPattern | ArrayLiteralExpression>pattern).elements;
for (let i = elementCount; i < patternElements.length; i++) {
const e = patternElements[i];
if (hasDefaultValue(e)) {
elementTypes.push((<TypeReference>contextualType).typeArguments![i]);
}
else if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && (<BindingElement>e).dotDotDotToken || e.kind === SyntaxKind.SpreadElement)) {
if (e.kind !== SyntaxKind.OmittedExpression) {
error(e, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value);
}
elementTypes.push(strictNullChecks ? implicitNeverType : undefinedWideningType);
}
}
}
return createTupleType(elementTypes, minLength, hasRestElement, readonly);
return createTupleType(elementTypes, elementCount - (hasRestElement ? 1 : 0), hasRestElement, readonly);
}
}
@ -23655,8 +23641,10 @@ namespace ts {
if (isArrayLikeType(sourceType)) {
// We create a synthetic expression so that getIndexedAccessType doesn't get confused
// when the element is a SyntaxKind.ElementAccessExpression.
const elementType = getIndexedAccessType(sourceType, indexType, createSyntheticExpression(element, indexType));
const type = getFlowTypeOfDestructuring(element, elementType);
const accessFlags = hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0;
const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, createSyntheticExpression(element, indexType), accessFlags) || errorType;
const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType;
const type = getFlowTypeOfDestructuring(element, assignedType);
return checkDestructuringAssignment(element, type, checkMode);
}
return checkDestructuringAssignment(element, elementType, checkMode);