Skip to content

Commit 3258424

Browse files
committed
Union array literals in inference similar to object literals
1 parent 36aa101 commit 3258424

File tree

2 files changed

+40
-21
lines changed

2 files changed

+40
-21
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,7 +5481,7 @@ namespace ts {
54815481
function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type {
54825482
const members = createSymbolTable();
54835483
let stringIndexInfo: IndexInfo | undefined;
5484-
let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectLiteral;
5484+
let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
54855485
forEach(pattern.elements, e => {
54865486
const name = e.propertyName || <Identifier>e.name;
54875487
if (e.dotDotDotToken) {
@@ -10803,7 +10803,7 @@ namespace ts {
1080310803
emptyArray,
1080410804
getIndexInfoWithReadonly(stringIndexInfo, readonly),
1080510805
getIndexInfoWithReadonly(numberIndexInfo, readonly));
10806-
spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectLiteral | ObjectFlags.ContainsSpread | objectFlags;
10806+
spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags;
1080710807
return spread;
1080810808
}
1080910809

@@ -15644,12 +15644,16 @@ namespace ts {
1564415644
return !!(getObjectFlags(type) & ObjectFlags.ObjectLiteral);
1564515645
}
1564615646

15647-
function widenObjectLiteralCandidates(candidates: Type[]): Type[] {
15647+
function isObjectOrArrayLiteralType(type: Type) {
15648+
return !!(getObjectFlags(type) & (ObjectFlags.ObjectLiteral | ObjectFlags.ArrayLiteral));
15649+
}
15650+
15651+
function unionObjectAndArrayLiteralCandidates(candidates: Type[]): Type[] {
1564815652
if (candidates.length > 1) {
15649-
const objectLiterals = filter(candidates, isObjectLiteralType);
15653+
const objectLiterals = filter(candidates, isObjectOrArrayLiteralType);
1565015654
if (objectLiterals.length) {
15651-
const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, UnionReduction.Subtype));
15652-
return concatenate(filter(candidates, t => !isObjectLiteralType(t)), [objectLiteralsType]);
15655+
const literalsType = getUnionType(objectLiterals, UnionReduction.Subtype);
15656+
return concatenate(filter(candidates, t => !isObjectOrArrayLiteralType(t)), [literalsType]);
1565315657
}
1565415658
}
1565515659
return candidates;
@@ -15660,8 +15664,8 @@ namespace ts {
1566015664
}
1566115665

1566215666
function getCovariantInference(inference: InferenceInfo, signature: Signature) {
15663-
// Extract all object literal types and replace them with a single widened and normalized type.
15664-
const candidates = widenObjectLiteralCandidates(inference.candidates!);
15667+
// Extract all object and array literal types and replace them with a single widened and normalized type.
15668+
const candidates = unionObjectAndArrayLiteralCandidates(inference.candidates!);
1566515669
// We widen inferred literal types if
1566615670
// all inferences were made to top-level occurrences of the type parameter, and
1566715671
// the type parameter has no constraint or its constraint includes no primitive or literal types, and
@@ -19147,22 +19151,34 @@ namespace ts {
1914719151
const minLength = elementCount - (hasRestElement ? 1 : 0);
1914819152
// If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
1914919153
// that we get the same behavior for "var [x, y] = []" and "[x, y] = []".
19150-
let tupleResult: Type | undefined;
19154+
let tupleResult;
1915119155
if (inDestructuringPattern && minLength > 0) {
1915219156
const type = cloneTypeReference(<TypeReference>createTupleType(elementTypes, minLength, hasRestElement));
1915319157
type.pattern = node;
1915419158
return type;
1915519159
}
1915619160
else if (tupleResult = getArrayLiteralTupleTypeIfApplicable(elementTypes, contextualType, hasRestElement, elementCount, inConstContext)) {
19157-
return tupleResult;
19161+
return createArrayLiteralType(tupleResult);
1915819162
}
1915919163
else if (forceTuple) {
19160-
return createTupleType(elementTypes, minLength, hasRestElement);
19164+
return createArrayLiteralType(createTupleType(elementTypes, minLength, hasRestElement));
1916119165
}
1916219166
}
19163-
return createArrayType(elementTypes.length ?
19167+
return createArrayLiteralType(createArrayType(elementTypes.length ?
1916419168
getUnionType(elementTypes, UnionReduction.Subtype) :
19165-
strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext);
19169+
strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext));
19170+
}
19171+
19172+
function createArrayLiteralType(type: ObjectType) {
19173+
if (!(getObjectFlags(type) & ObjectFlags.Reference)) {
19174+
return type;
19175+
}
19176+
let literalType = (<TypeReference>type).literalType;
19177+
if (!literalType) {
19178+
literalType = (<TypeReference>type).literalType = cloneTypeReference(<TypeReference>type);
19179+
literalType.objectFlags |= ObjectFlags.ArrayLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
19180+
}
19181+
return literalType;
1916619182
}
1916719183

1916819184
function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length, readonly = false) {
@@ -19447,7 +19463,7 @@ namespace ts {
1944719463
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, offset, propertiesArray, IndexKind.String) : undefined;
1944819464
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, offset, propertiesArray, IndexKind.Number) : undefined;
1944919465
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
19450-
result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectLiteral;
19466+
result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
1945119467
if (isJSObjectLiteral) {
1945219468
result.objectFlags |= ObjectFlags.JSLiteral;
1945319469
}
@@ -19643,7 +19659,7 @@ namespace ts {
1964319659
function createJsxAttributesType() {
1964419660
objectFlags |= freshObjectLiteralFlag;
1964519661
const result = createAnonymousType(attributes.symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
19646-
result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectLiteral;
19662+
result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
1964719663
return result;
1964819664
}
1964919665
}

src/compiler/types.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4089,19 +4089,20 @@ namespace ts {
40894089
MarkerType = 1 << 13, // Marker type used for variance probing
40904090
JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members
40914091
FreshLiteral = 1 << 15, // Fresh object literal
4092+
ArrayLiteral = 1 << 16, // Originates in an array literal
40924093
/* @internal */
4093-
PrimitiveUnion = 1 << 16, // Union of only primitive types
4094+
PrimitiveUnion = 1 << 17, // Union of only primitive types
40944095
/* @internal */
4095-
ContainsWideningType = 1 << 17, // Type is or contains undefined or null widening type
4096+
ContainsWideningType = 1 << 18, // Type is or contains undefined or null widening type
40964097
/* @internal */
4097-
ContainsObjectLiteral = 1 << 18, // Type is or contains object literal type
4098+
ContainsObjectOrArrayLiteral = 1 << 19, // Type is or contains object literal type
40984099
/* @internal */
4099-
NonInferrableType = 1 << 19, // Type is or contains anyFunctionType or silentNeverType
4100+
NonInferrableType = 1 << 20, // Type is or contains anyFunctionType or silentNeverType
41004101
ClassOrInterface = Class | Interface,
41014102
/* @internal */
4102-
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
4103+
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
41034104
/* @internal */
4104-
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | NonInferrableType
4105+
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType
41054106
}
41064107

41074108
/* @internal */
@@ -4154,6 +4155,8 @@ namespace ts {
41544155
export interface TypeReference extends ObjectType {
41554156
target: GenericType; // Type reference target
41564157
typeArguments?: ReadonlyArray<Type>; // Type reference type arguments (undefined if none)
4158+
/* @internal */
4159+
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
41574160
}
41584161

41594162
/* @internal */

0 commit comments

Comments
 (0)