@@ -313,11 +313,11 @@ namespace ts {
313313
314314 getSuggestionDiagnostics: file => {
315315 return (suggestionDiagnostics.get(file.fileName) || emptyArray).concat(getUnusedDiagnostics());
316- function getUnusedDiagnostics(): ReadonlyArray<Diagnostic > {
316+ function getUnusedDiagnostics(): ReadonlyArray<DiagnosticWithLocation > {
317317 if (file.isDeclarationFile) return emptyArray;
318318
319319 checkSourceFile(file);
320- const diagnostics: Diagnostic [] = [];
320+ const diagnostics: DiagnosticWithLocation [] = [];
321321 Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked));
322322 checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (kind, diag) => {
323323 if (!unusedIsError(kind)) {
@@ -481,7 +481,7 @@ namespace ts {
481481
482482 const diagnostics = createDiagnosticCollection();
483483 // Suggestion diagnostics must have a file. Keyed by source file name.
484- const suggestionDiagnostics = createMultiMap<Diagnostic >();
484+ const suggestionDiagnostics = createMultiMap<DiagnosticWithLocation >();
485485
486486 const enum TypeFacts {
487487 None = 0,
@@ -628,7 +628,7 @@ namespace ts {
628628 Local,
629629 Parameter,
630630 }
631- type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: Diagnostic ) => void;
631+ type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: DiagnosticWithLocation ) => void;
632632
633633 const builtinGlobals = createSymbolTable();
634634 builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
@@ -824,7 +824,7 @@ namespace ts {
824824 diagnostics.add(diagnostic);
825825 }
826826
827- function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic ) {
827+ function addErrorOrSuggestion(isError: boolean, diagnostic: DiagnosticWithLocation ) {
828828 if (isError) {
829829 diagnostics.add(diagnostic);
830830 }
@@ -9286,8 +9286,10 @@ namespace ts {
92869286 return type;
92879287 }
92889288
9289- function getRegularTypeOfLiteralType(type: Type) {
9290- return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (<LiteralType>type).regularType : type;
9289+ function getRegularTypeOfLiteralType(type: Type): Type {
9290+ return type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral ? (<LiteralType>type).regularType :
9291+ type.flags & TypeFlags.Union ? getUnionType(sameMap((<UnionType>type).types, getRegularTypeOfLiteralType)) :
9292+ type;
92919293 }
92929294
92939295 function getLiteralType(value: string | number, enumId?: number, symbol?: Symbol) {
@@ -12774,10 +12776,12 @@ namespace ts {
1277412776 // all inferences were made to top-level occurrences of the type parameter, and
1277512777 // the type parameter has no constraint or its constraint includes no primitive or literal types, and
1277612778 // the type parameter was fixed during inference or does not occur at top-level in the return type.
12777- const widenLiteralTypes = inference.topLevel &&
12778- !hasPrimitiveConstraint( inference.typeParameter) &&
12779+ const primitiveConstraint = hasPrimitiveConstraint( inference.typeParameter);
12780+ const widenLiteralTypes = !primitiveConstraint && inference.topLevel &&
1277912781 (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
12780- const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates;
12782+ const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) :
12783+ widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) :
12784+ candidates;
1278112785 // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if
1278212786 // union types were requested or if all inferences were made from the return type position, infer a
1278312787 // union type. Otherwise, infer a common supertype.
@@ -15303,6 +15307,26 @@ namespace ts {
1530315307 }
1530415308 }
1530515309
15310+ // Return true if the given expression is possibly a discriminant value. We limit the kinds of
15311+ // expressions we check to those that don't depend on their contextual type in order not to cause
15312+ // recursive (and possibly infinite) invocations of getContextualType.
15313+ function isPossiblyDiscriminantValue(node: Expression): boolean {
15314+ switch (node.kind) {
15315+ case SyntaxKind.StringLiteral:
15316+ case SyntaxKind.NumericLiteral:
15317+ case SyntaxKind.NoSubstitutionTemplateLiteral:
15318+ case SyntaxKind.TrueKeyword:
15319+ case SyntaxKind.FalseKeyword:
15320+ case SyntaxKind.NullKeyword:
15321+ case SyntaxKind.Identifier:
15322+ return true;
15323+ case SyntaxKind.PropertyAccessExpression:
15324+ case SyntaxKind.ParenthesizedExpression:
15325+ return isPossiblyDiscriminantValue((<PropertyAccessExpression | ParenthesizedExpression>node).expression);
15326+ }
15327+ return false;
15328+ }
15329+
1530615330 // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
1530715331 // be "pushed" onto a node using the contextualType property.
1530815332 function getApparentTypeOfContextualType(node: Expression): Type {
@@ -15316,8 +15340,8 @@ namespace ts {
1531615340 propLoop: for (const prop of node.properties) {
1531715341 if (!prop.symbol) continue;
1531815342 if (prop.kind !== SyntaxKind.PropertyAssignment) continue;
15319- if (isDiscriminantProperty(contextualType, prop.symbol.escapedName)) {
15320- const discriminatingType = getTypeOfNode (prop.initializer);
15343+ if (isPossiblyDiscriminantValue(prop.initializer) && isDiscriminantProperty(contextualType, prop.symbol.escapedName)) {
15344+ const discriminatingType = checkExpression (prop.initializer);
1532115345 for (const type of (contextualType as UnionType).types) {
1532215346 const targetType = getTypeOfPropertyOfType(type, prop.symbol.escapedName);
1532315347 if (targetType && checkTypeAssignableTo(discriminatingType, targetType, /*errorNode*/ undefined)) {
0 commit comments