Skip to content

Commit 0c38f21

Browse files
committed
fixes #30507
1 parent ea73093 commit 0c38f21

File tree

7 files changed

+70
-32
lines changed

7 files changed

+70
-32
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,9 @@ namespace ts {
267267
},
268268
getAugmentedPropertiesOfType,
269269
getRootSymbols,
270-
getContextualType: nodeIn => {
270+
getContextualType: (nodeIn, contextFlags) => {
271271
const node = getParseTreeNode(nodeIn, isExpression);
272-
return node ? getContextualType(node) : undefined;
272+
return node ? getContextualType(node, contextFlags) : undefined;
273273
},
274274
getContextualTypeForObjectLiteralElement: nodeIn => {
275275
const node = getParseTreeNode(nodeIn, isObjectLiteralElementLike);
@@ -805,11 +805,6 @@ namespace ts {
805805
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
806806
}
807807

808-
const enum ContextFlags {
809-
None = 0,
810-
Signature = 1 << 0, // Obtaining contextual signature
811-
}
812-
813808
const enum AccessFlags {
814809
None = 0,
815810
NoIndexSignatures = 1 << 0,
@@ -15978,7 +15973,7 @@ namespace ts {
1597815973
return getWidenedType(unwidenedType);
1597915974
}
1598015975

15981-
function getInferredType(context: InferenceContext, index: number): Type {
15976+
function getInferredType(context: InferenceContext, index: number, contextFlags?: ContextFlags): Type {
1598215977
const inference = context.inferences[index];
1598315978
if (!inference.inferredType) {
1598415979
let inferredType: Type | undefined;
@@ -16023,7 +16018,8 @@ namespace ts {
1602316018
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
1602416019
if (constraint) {
1602516020
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
16026-
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
16021+
const isCompletionContext = contextFlags && ((contextFlags | ContextFlags.Completion) === contextFlags);
16022+
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType)) || isCompletionContext) {
1602716023
inference.inferredType = inferredType = instantiatedConstraint;
1602816024
}
1602916025
}
@@ -16036,10 +16032,10 @@ namespace ts {
1603616032
return isInJavaScriptFile ? anyType : unknownType;
1603716033
}
1603816034

16039-
function getInferredTypes(context: InferenceContext): Type[] {
16035+
function getInferredTypes(context: InferenceContext, contextFlags?: ContextFlags): Type[] {
1604016036
const result: Type[] = [];
1604116037
for (let i = 0; i < context.inferences.length; i++) {
16042-
result.push(getInferredType(context, i));
16038+
result.push(getInferredType(context, i, contextFlags));
1604316039
}
1604416040
return result;
1604516041
}
@@ -18737,16 +18733,16 @@ namespace ts {
1873718733
}
1873818734

1873918735
// In a typed function call, an argument or substitution expression is contextually typed by the type of the corresponding parameter.
18740-
function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression): Type | undefined {
18736+
function getContextualTypeForArgument(callTarget: CallLikeExpression, arg: Expression, contextFlags?: ContextFlags): Type | undefined {
1874118737
const args = getEffectiveCallArguments(callTarget);
1874218738
const argIndex = args.indexOf(arg); // -1 for e.g. the expression of a CallExpression, or the tag of a TaggedTemplateExpression
18743-
return argIndex === -1 ? undefined : getContextualTypeForArgumentAtIndex(callTarget, argIndex);
18739+
return argIndex === -1 ? undefined : getContextualTypeForArgumentAtIndex(callTarget, argIndex, contextFlags);
1874418740
}
1874518741

18746-
function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type {
18742+
function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number, contextFlags?: ContextFlags): Type {
1874718743
// If we're already in the process of resolving the given signature, don't resolve again as
1874818744
// that could cause infinite recursion. Instead, return anySignature.
18749-
const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
18745+
const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget, /*candidatesOutArray*/ undefined, /*checkMode*/ undefined, contextFlags);
1875018746
if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) {
1875118747
return getEffectiveFirstArgumentForJsxSignature(signature, callTarget);
1875218748
}
@@ -19133,7 +19129,7 @@ namespace ts {
1913319129
}
1913419130
/* falls through */
1913519131
case SyntaxKind.NewExpression:
19136-
return getContextualTypeForArgument(<CallExpression | NewExpression>parent, node);
19132+
return getContextualTypeForArgument(<CallExpression | NewExpression>parent, node, contextFlags);
1913719133
case SyntaxKind.TypeAssertionExpression:
1913819134
case SyntaxKind.AsExpression:
1913919135
return isConstTypeReference((<AssertionExpression>parent).type) ? undefined : getTypeFromTypeNode((<AssertionExpression>parent).type);
@@ -21240,7 +21236,7 @@ namespace ts {
2124021236
return getInferredTypes(context);
2124121237
}
2124221238

21243-
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, checkMode: CheckMode, context: InferenceContext): Type[] {
21239+
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, checkMode: CheckMode, context: InferenceContext, contextFlags?: ContextFlags): Type[] {
2124421240
if (isJsxOpeningLikeElement(node)) {
2124521241
return inferJsxTypeArguments(node, signature, checkMode, context);
2124621242
}
@@ -21306,7 +21302,7 @@ namespace ts {
2130621302
inferTypes(context.inferences, spreadType, restType);
2130721303
}
2130821304

21309-
return getInferredTypes(context);
21305+
return getInferredTypes(context, contextFlags);
2131021306
}
2131121307

2131221308
function getArrayifiedType(type: Type) {
@@ -21742,7 +21738,7 @@ namespace ts {
2174221738
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
2174321739
}
2174421740

21745-
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, fallbackError?: DiagnosticMessage): Signature {
21741+
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, fallbackError?: DiagnosticMessage, contextFlags?: ContextFlags): Signature {
2174621742
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
2174721743
const isDecorator = node.kind === SyntaxKind.Decorator;
2174821744
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -21831,7 +21827,7 @@ namespace ts {
2183121827
result = chooseOverload(candidates, subtypeRelation, signatureHelpTrailingComma);
2183221828
}
2183321829
if (!result) {
21834-
result = chooseOverload(candidates, assignableRelation, signatureHelpTrailingComma);
21830+
result = chooseOverload(candidates, assignableRelation, signatureHelpTrailingComma, contextFlags);
2183521831
}
2183621832
if (result) {
2183721833
return result;
@@ -21923,7 +21919,7 @@ namespace ts {
2192321919

2192421920
return produceDiagnostics || !args ? resolveErrorCall(node) : getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
2192521921

21926-
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
21922+
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false, contextFlags?: ContextFlags) {
2192721923
candidatesForArgumentError = undefined;
2192821924
candidateForArgumentArityError = undefined;
2192921925
candidateForTypeArgumentError = undefined;
@@ -21960,7 +21956,7 @@ namespace ts {
2196021956
}
2196121957
else {
2196221958
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
21963-
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
21959+
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext, contextFlags);
2196421960
argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
2196521961
}
2196621962
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
@@ -22130,7 +22126,7 @@ namespace ts {
2213022126
return maxParamsIndex;
2213122127
}
2213222128

22133-
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
22129+
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, contextFlags?: ContextFlags): Signature {
2213422130
if (node.expression.kind === SyntaxKind.SuperKeyword) {
2213522131
const superType = checkSuperExpression(node.expression);
2213622132
if (isTypeAny(superType)) {
@@ -22226,7 +22222,7 @@ namespace ts {
2222622222
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
2222722223
return resolveErrorCall(node);
2222822224
}
22229-
return resolveCall(node, callSignatures, candidatesOutArray, checkMode);
22225+
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*fallbackError*/ undefined, contextFlags);
2223022226
}
2223122227

2223222228
function isGenericFunctionReturningFunction(signature: Signature) {
@@ -22652,10 +22648,10 @@ namespace ts {
2265222648
signature.parameters.length < getDecoratorArgumentCount(decorator, signature));
2265322649
}
2265422650

22655-
function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
22651+
function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, contextFlags?: ContextFlags): Signature {
2265622652
switch (node.kind) {
2265722653
case SyntaxKind.CallExpression:
22658-
return resolveCallExpression(node, candidatesOutArray, checkMode);
22654+
return resolveCallExpression(node, candidatesOutArray, checkMode, contextFlags);
2265922655
case SyntaxKind.NewExpression:
2266022656
return resolveNewExpression(node, candidatesOutArray, checkMode);
2266122657
case SyntaxKind.TaggedTemplateExpression:
@@ -22676,7 +22672,7 @@ namespace ts {
2267622672
* the function will fill it up with appropriate candidate signatures
2267722673
* @return a signature of the call-like expression or undefined if one can't be found
2267822674
*/
22679-
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature {
22675+
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode, contextFlags?: ContextFlags): Signature {
2268022676
const links = getNodeLinks(node);
2268122677
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
2268222678
// However, it is possible that either candidatesOutArray was not passed in the first time,
@@ -22687,7 +22683,7 @@ namespace ts {
2268722683
return cached;
2268822684
}
2268922685
links.resolvedSignature = resolvingSignature;
22690-
const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
22686+
const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal, contextFlags);
2269122687
// When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call
2269222688
// resolution should be deferred.
2269322689
if (result !== resolvingSignature) {

src/compiler/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3180,7 +3180,7 @@ namespace ts {
31803180
getFullyQualifiedName(symbol: Symbol): string;
31813181
getAugmentedPropertiesOfType(type: Type): Symbol[];
31823182
getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
3183-
getContextualType(node: Expression): Type | undefined;
3183+
getContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined;
31843184
/* @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined;
31853185
/* @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined;
31863186
/* @internal */ getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute): Type | undefined;
@@ -3338,6 +3338,12 @@ namespace ts {
33383338
Subtype
33393339
}
33403340

3341+
export const enum ContextFlags {
3342+
None = 0,
3343+
Signature = 1 << 0, // Obtaining contextual signature
3344+
Completion = 1 << 1, // Obtaining constraint type for completion
3345+
}
3346+
33413347
// NOTE: If modifying this enum, must modify `TypeFormatFlags` too!
33423348
export const enum NodeBuilderFlags {
33433349
None = 0,

src/services/completions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ namespace ts.Completions {
14541454
let existingMembers: ReadonlyArray<Declaration> | undefined;
14551455

14561456
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
1457-
const typeForObject = typeChecker.getContextualType(objectLikeContainer);
1457+
const typeForObject = typeChecker.getContextualType(objectLikeContainer, ContextFlags.Completion);
14581458
if (!typeForObject) return GlobalsSearch.Fail;
14591459
isNewIdentifierLocation = hasIndexSignature(typeForObject);
14601460
typeMembers = getPropertiesForObjectExpression(typeForObject, objectLikeContainer, typeChecker);

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ declare namespace ts {
19841984
getFullyQualifiedName(symbol: Symbol): string;
19851985
getAugmentedPropertiesOfType(type: Type): Symbol[];
19861986
getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
1987-
getContextualType(node: Expression): Type | undefined;
1987+
getContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined;
19881988
/**
19891989
* returns unknownSignature in the case of an error.
19901990
* returns undefined if the node is not valid.
@@ -2015,6 +2015,11 @@ declare namespace ts {
20152015
*/
20162016
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
20172017
}
2018+
enum ContextFlags {
2019+
None = 0,
2020+
Signature = 1,
2021+
Completion = 2
2022+
}
20182023
enum NodeBuilderFlags {
20192024
None = 0,
20202025
NoTruncation = 1,

tests/baselines/reference/api/typescript.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ declare namespace ts {
19841984
getFullyQualifiedName(symbol: Symbol): string;
19851985
getAugmentedPropertiesOfType(type: Type): Symbol[];
19861986
getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
1987-
getContextualType(node: Expression): Type | undefined;
1987+
getContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined;
19881988
/**
19891989
* returns unknownSignature in the case of an error.
19901990
* returns undefined if the node is not valid.
@@ -2015,6 +2015,11 @@ declare namespace ts {
20152015
*/
20162016
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
20172017
}
2018+
enum ContextFlags {
2019+
None = 0,
2020+
Signature = 1,
2021+
Completion = 2
2022+
}
20182023
enum NodeBuilderFlags {
20192024
None = 0,
20202025
NoTruncation = 1,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path="fourslash.ts" />
2+
// @strict: true
3+
4+
//// interface MyOptions {
5+
//// hello?: boolean;
6+
//// world?: boolean;
7+
//// }
8+
//// declare function bar<T extends MyOptions>(options?: Partial<T>): void;
9+
//// bar({ hello, /*1*/ });
10+
11+
verify.completions({ marker: '1', includes: ['world'] })
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="fourslash.ts" />
2+
// @strict: true
3+
4+
//// interface DeepOptions {
5+
//// another?: boolean;
6+
//// }
7+
//// interface MyOptions {
8+
//// hello?: boolean;
9+
//// world?: boolean;
10+
//// deep?: DeepOptions
11+
//// }
12+
//// declare function bar<T extends MyOptions>(options?: Partial<T>): void;
13+
//// bar({ deep: {/*1*/} });
14+
15+
verify.completions({ marker: '1', includes: ['another'] })

0 commit comments

Comments
 (0)