@@ -701,6 +701,11 @@ namespace ts {
701
701
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
702
702
}
703
703
704
+ const enum ContextFlags {
705
+ None = 0,
706
+ Signature = 1 << 0, // Obtaining contextual signature
707
+ }
708
+
704
709
const enum CallbackCheck {
705
710
None,
706
711
Bivariant,
@@ -17751,7 +17756,7 @@ namespace ts {
17751
17756
return undefined;
17752
17757
}
17753
17758
17754
- function getContextualTypeForBinaryOperand(node: Expression): Type | undefined {
17759
+ function getContextualTypeForBinaryOperand(node: Expression, contextFlags?: ContextFlags ): Type | undefined {
17755
17760
const binaryExpression = <BinaryExpression>node.parent;
17756
17761
const { left, operatorToken, right } = binaryExpression;
17757
17762
switch (operatorToken.kind) {
@@ -17768,12 +17773,12 @@ namespace ts {
17768
17773
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
17769
17774
// expression has no contextual type, the right operand is contextually typed by the type of the left operand,
17770
17775
// except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}`
17771
- const type = getContextualType(binaryExpression);
17776
+ const type = getContextualType(binaryExpression, contextFlags );
17772
17777
return !type && node === right && !isDefaultedExpandoInitializer(binaryExpression) ?
17773
17778
getTypeOfExpression(left) : type;
17774
17779
case SyntaxKind.AmpersandAmpersandToken:
17775
17780
case SyntaxKind.CommaToken:
17776
- return node === right ? getContextualType(binaryExpression) : undefined;
17781
+ return node === right ? getContextualType(binaryExpression, contextFlags ) : undefined;
17777
17782
default:
17778
17783
return undefined;
17779
17784
}
@@ -17882,19 +17887,18 @@ namespace ts {
17882
17887
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
17883
17888
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
17884
17889
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
17885
- function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration): Type | undefined {
17890
+ function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags?: ContextFlags ): Type | undefined {
17886
17891
Debug.assert(isObjectLiteralMethod(node));
17887
17892
if (node.flags & NodeFlags.InWithStatement) {
17888
17893
// We cannot answer semantic questions within a with block, do not proceed any further
17889
17894
return undefined;
17890
17895
}
17891
-
17892
- return getContextualTypeForObjectLiteralElement(node);
17896
+ return getContextualTypeForObjectLiteralElement(node, contextFlags);
17893
17897
}
17894
17898
17895
- function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike) {
17899
+ function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags?: ContextFlags ) {
17896
17900
const objectLiteral = <ObjectLiteralExpression>element.parent;
17897
- const type = getApparentTypeOfContextualType(objectLiteral);
17901
+ const type = getApparentTypeOfContextualType(objectLiteral, contextFlags );
17898
17902
if (type) {
17899
17903
if (!hasNonBindableDynamicName(element)) {
17900
17904
// For a (non-symbol) computed property, there is no reason to look up the name
@@ -17906,11 +17910,9 @@ namespace ts {
17906
17910
return propertyType;
17907
17911
}
17908
17912
}
17909
-
17910
17913
return isNumericName(element.name!) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
17911
17914
getIndexTypeOfContextualType(type, IndexKind.String);
17912
17915
}
17913
-
17914
17916
return undefined;
17915
17917
}
17916
17918
@@ -17925,9 +17927,9 @@ namespace ts {
17925
17927
}
17926
17928
17927
17929
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
17928
- function getContextualTypeForConditionalOperand(node: Expression): Type | undefined {
17930
+ function getContextualTypeForConditionalOperand(node: Expression, contextFlags?: ContextFlags ): Type | undefined {
17929
17931
const conditional = <ConditionalExpression>node.parent;
17930
- return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
17932
+ return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags ) : undefined;
17931
17933
}
17932
17934
17933
17935
function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild) {
@@ -18022,8 +18024,8 @@ namespace ts {
18022
18024
18023
18025
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
18024
18026
// be "pushed" onto a node using the contextualType property.
18025
- function getApparentTypeOfContextualType(node: Expression): Type | undefined {
18026
- const contextualType = instantiateContextualType(getContextualType(node), node);
18027
+ function getApparentTypeOfContextualType(node: Expression, contextFlags?: ContextFlags ): Type | undefined {
18028
+ const contextualType = instantiateContextualType(getContextualType(node, contextFlags ), node, contextFlags );
18027
18029
if (contextualType) {
18028
18030
const apparentType = mapType(contextualType, getApparentType, /*noReductions*/ true);
18029
18031
if (apparentType.flags & TypeFlags.Union) {
@@ -18040,13 +18042,19 @@ namespace ts {
18040
18042
18041
18043
// If the given contextual type contains instantiable types and if a mapper representing
18042
18044
// return type inferences is available, instantiate those types using that mapper.
18043
- function instantiateContextualType(contextualType: Type | undefined, node: Expression): Type | undefined {
18045
+ function instantiateContextualType(contextualType: Type | undefined, node: Expression, contextFlags?: ContextFlags ): Type | undefined {
18044
18046
if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) {
18045
18047
const inferenceContext = getInferenceContext(node);
18046
- if (inferenceContext) {
18047
- if ((isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node)) && isContextSensitive(node)) {
18048
+ // If no inferences have been made, nothing is gained from instantiating as type parameters
18049
+ // would just be replaced with their defaults similar to the apparent type.
18050
+ if (inferenceContext && some(inferenceContext.inferences, hasInferenceCandidates)) {
18051
+ // For contextual signatures we incorporate all inferences made so far, e.g. from return
18052
+ // types as well as arguments to the left in a function call.
18053
+ if (contextFlags && contextFlags & ContextFlags.Signature) {
18048
18054
return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper);
18049
18055
}
18056
+ // For other purposes (e.g. determining whether to produce literal types) we only
18057
+ // incorporate inferences made from the return type in a function call.
18050
18058
if (inferenceContext.returnMapper) {
18051
18059
return instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper);
18052
18060
}
@@ -18088,7 +18096,7 @@ namespace ts {
18088
18096
* @param node the expression whose contextual type will be returned.
18089
18097
* @returns the contextual type of an expression.
18090
18098
*/
18091
- function getContextualType(node: Expression): Type | undefined {
18099
+ function getContextualType(node: Expression, contextFlags?: ContextFlags ): Type | undefined {
18092
18100
if (node.flags & NodeFlags.InWithStatement) {
18093
18101
// We cannot answer semantic questions within a with block, do not proceed any further
18094
18102
return undefined;
@@ -18118,26 +18126,26 @@ namespace ts {
18118
18126
case SyntaxKind.AsExpression:
18119
18127
return isConstTypeReference((<AssertionExpression>parent).type) ? undefined : getTypeFromTypeNode((<AssertionExpression>parent).type);
18120
18128
case SyntaxKind.BinaryExpression:
18121
- return getContextualTypeForBinaryOperand(node);
18129
+ return getContextualTypeForBinaryOperand(node, contextFlags );
18122
18130
case SyntaxKind.PropertyAssignment:
18123
18131
case SyntaxKind.ShorthandPropertyAssignment:
18124
- return getContextualTypeForObjectLiteralElement(<PropertyAssignment | ShorthandPropertyAssignment>parent);
18132
+ return getContextualTypeForObjectLiteralElement(<PropertyAssignment | ShorthandPropertyAssignment>parent, contextFlags );
18125
18133
case SyntaxKind.SpreadAssignment:
18126
- return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression);
18134
+ return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression, contextFlags );
18127
18135
case SyntaxKind.ArrayLiteralExpression: {
18128
18136
const arrayLiteral = <ArrayLiteralExpression>parent;
18129
- const type = getApparentTypeOfContextualType(arrayLiteral);
18137
+ const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags );
18130
18138
return getContextualTypeForElementExpression(type, indexOfNode(arrayLiteral.elements, node));
18131
18139
}
18132
18140
case SyntaxKind.ConditionalExpression:
18133
- return getContextualTypeForConditionalOperand(node);
18141
+ return getContextualTypeForConditionalOperand(node, contextFlags );
18134
18142
case SyntaxKind.TemplateSpan:
18135
18143
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
18136
18144
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
18137
18145
case SyntaxKind.ParenthesizedExpression: {
18138
18146
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
18139
18147
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
18140
- return tag ? getTypeFromTypeNode(tag.typeExpression!.type) : getContextualType(<ParenthesizedExpression>parent);
18148
+ return tag ? getTypeFromTypeNode(tag.typeExpression!.type) : getContextualType(<ParenthesizedExpression>parent, contextFlags );
18141
18149
}
18142
18150
case SyntaxKind.JsxExpression:
18143
18151
return getContextualTypeForJsxExpression(<JsxExpression>parent);
@@ -18328,12 +18336,6 @@ namespace ts {
18328
18336
: undefined;
18329
18337
}
18330
18338
18331
- function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | ArrowFunction | MethodDeclaration) {
18332
- return isObjectLiteralMethod(node) ?
18333
- getContextualTypeForObjectLiteralMethod(node) :
18334
- getApparentTypeOfContextualType(node);
18335
- }
18336
-
18337
18339
// Return the contextual signature for a given expression node. A contextual type provides a
18338
18340
// contextual signature if it has a single call signature and if that call signature is non-generic.
18339
18341
// If the contextual type is a union type, get the signature from each type possible and if they are
@@ -18345,7 +18347,9 @@ namespace ts {
18345
18347
if (typeTagSignature) {
18346
18348
return typeTagSignature;
18347
18349
}
18348
- const type = getContextualTypeForFunctionLikeDeclaration(node);
18350
+ const type = isObjectLiteralMethod(node) ?
18351
+ getContextualTypeForObjectLiteralMethod(node, ContextFlags.Signature) :
18352
+ getApparentTypeOfContextualType(node, ContextFlags.Signature);
18349
18353
if (!type) {
18350
18354
return undefined;
18351
18355
}
@@ -20249,7 +20253,7 @@ namespace ts {
20249
20253
return type;
20250
20254
}
20251
20255
20252
- function getSpreadArgumentType(args: ReadonlyArray<Expression>, index: number, argCount: number, restType: TypeParameter , context: InferenceContext | undefined) {
20256
+ function getSpreadArgumentType(args: ReadonlyArray<Expression>, index: number, argCount: number, restType: Type , context: InferenceContext | undefined) {
20253
20257
if (index >= argCount - 1) {
20254
20258
const arg = args[argCount - 1];
20255
20259
if (isSpreadArgument(arg)) {
@@ -20260,7 +20264,7 @@ namespace ts {
20260
20264
getArrayifiedType(checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context, CheckMode.Normal));
20261
20265
}
20262
20266
}
20263
- const contextualType = getIndexTypeOfType (restType, IndexKind.Number) || anyType ;
20267
+ const contextualType = getIndexedAccessType (restType, numberType) ;
20264
20268
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
20265
20269
const types = [];
20266
20270
let spreadIndex = -1;
0 commit comments