mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Fixed some string literal argument completions depending on resolved signature (#53996)
This commit is contained in:
committed by
GitHub
parent
2a37eb2e47
commit
c565827b4f
@@ -1641,8 +1641,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
getFullyQualifiedName,
|
||||
getResolvedSignature: (node, candidatesOutArray, argumentCount) =>
|
||||
getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal),
|
||||
getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray) =>
|
||||
runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, CheckMode.IsForStringLiteralArgumentCompletions)),
|
||||
getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray, checkMode = CheckMode.IsForStringLiteralArgumentCompletions) => {
|
||||
if (checkMode & CheckMode.IsForStringLiteralArgumentCompletions) {
|
||||
return runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions));
|
||||
}
|
||||
return runWithoutResolvedSignatureCaching(editingArgument, () => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions));
|
||||
},
|
||||
getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) =>
|
||||
runWithoutResolvedSignatureCaching(node, () => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp)),
|
||||
getExpandedParameters,
|
||||
@@ -25230,7 +25234,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const constraint = getConstraintOfTypeParameter(inference.typeParameter);
|
||||
if (constraint) {
|
||||
const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
|
||||
if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
|
||||
if (!inferredType || inferredType === wildcardType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
|
||||
// If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
|
||||
inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
|
||||
}
|
||||
@@ -32508,7 +32512,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
for (let i = 0; i < argCount; i++) {
|
||||
const arg = args[i];
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression && !(checkMode & CheckMode.IsForStringLiteralArgumentCompletions && hasSkipDirectInferenceFlag(arg))) {
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
const paramType = getTypeAtPosition(signature, i);
|
||||
if (couldContainTypeVariables(paramType)) {
|
||||
const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode);
|
||||
@@ -33152,7 +33156,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal;
|
||||
argCheckMode |= checkMode & CheckMode.IsForStringLiteralArgumentCompletions;
|
||||
|
||||
// The following variables are captured and modified by calls to chooseOverload.
|
||||
// If overload resolution or type argument inference fails, we want to report the
|
||||
@@ -33391,7 +33394,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// If one or more context sensitive arguments were excluded, we start including
|
||||
// them now (and keeping do so for any subsequent candidates) and perform a second
|
||||
// round of type inference and applicability checking for this particular candidate.
|
||||
argCheckMode = checkMode & CheckMode.IsForStringLiteralArgumentCompletions;
|
||||
argCheckMode = CheckMode.Normal;
|
||||
if (inferenceContext) {
|
||||
const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext);
|
||||
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters);
|
||||
@@ -37901,7 +37904,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
return hasSkipDirectInferenceFlag(node) ?
|
||||
anyType :
|
||||
wildcardType :
|
||||
getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text));
|
||||
case SyntaxKind.NumericLiteral:
|
||||
checkGrammarNumericLiteral(node as NumericLiteral);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
BaseNodeFactory,
|
||||
CheckMode,
|
||||
CreateSourceFileOptions,
|
||||
EmitHelperFactory,
|
||||
GetCanonicalFileName,
|
||||
@@ -5076,7 +5077,7 @@ export interface TypeChecker {
|
||||
*/
|
||||
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
|
||||
/** @internal */ getResolvedSignatureForSignatureHelp(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
|
||||
/** @internal */ getResolvedSignatureForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node, candidatesOutArray: Signature[]): Signature | undefined;
|
||||
/** @internal */ getResolvedSignatureForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node, candidatesOutArray: Signature[], checkMode?: CheckMode): Signature | undefined;
|
||||
/** @internal */ getExpandedParameters(sig: Signature): readonly (readonly Symbol[])[];
|
||||
/** @internal */ hasEffectiveRestParameter(sig: Signature): boolean;
|
||||
/** @internal */ containsArgumentsReference(declaration: SignatureDeclaration): boolean;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CaseClause,
|
||||
changeExtension,
|
||||
CharacterCodes,
|
||||
CheckMode,
|
||||
combinePaths,
|
||||
comparePaths,
|
||||
comparePatternKeys,
|
||||
@@ -388,7 +389,7 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
// f("/*completion position*/")
|
||||
return argumentInfo && getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || fromContextualType(ContextFlags.None);
|
||||
return argumentInfo && (getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker, CheckMode.Normal)) || fromContextualType(ContextFlags.None);
|
||||
}
|
||||
// falls through (is `require("")` or `require(""` or `import("")`)
|
||||
|
||||
@@ -479,12 +480,12 @@ function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current:
|
||||
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes | undefined {
|
||||
function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker, checkMode = CheckMode.IsForStringLiteralArgumentCompletions): StringLiteralCompletionsFromTypes | undefined {
|
||||
let isNewIdentifier = false;
|
||||
const uniques = new Map<string, true>();
|
||||
const candidates: Signature[] = [];
|
||||
const editingArgument = isJsxOpeningLikeElement(call) ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) : arg;
|
||||
checker.getResolvedSignatureForStringLiteralCompletions(call, editingArgument, candidates);
|
||||
checker.getResolvedSignatureForStringLiteralCompletions(call, editingArgument, candidates, checkMode);
|
||||
const types = flatMap(candidates, candidate => {
|
||||
if (!signatureHasRestParameter(candidate) && argumentInfo.argumentCount > candidate.parameters.length) return;
|
||||
let type = candidate.getTypeParameterAtPosition(argumentInfo.argumentIndex);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @strict: true
|
||||
//// type keyword = "foo" | "bar" | "baz"
|
||||
////
|
||||
//// type validateString<s> = s extends keyword
|
||||
//// ? s
|
||||
//// : s extends `${infer left extends keyword}|${infer right}`
|
||||
//// ? right extends keyword
|
||||
//// ? s
|
||||
//// : `${left}|${keyword}`
|
||||
//// : keyword
|
||||
////
|
||||
//// type isUnknown<t> = unknown extends t
|
||||
//// ? [t] extends [{}]
|
||||
//// ? false
|
||||
//// : true
|
||||
//// : false
|
||||
////
|
||||
//// type validate<def> = def extends string
|
||||
//// ? validateString<def>
|
||||
//// : isUnknown<def> extends true
|
||||
//// ? keyword
|
||||
//// : {
|
||||
//// [k in keyof def]: validate<def[k]>
|
||||
//// }
|
||||
//// const parse = <def>(def: validate<def>) => def
|
||||
//// const shallowExpression = parse("foo|/*ts*/")
|
||||
//// const nestedExpression = parse({ prop: "foo|/*ts2*/" })
|
||||
|
||||
verify.completions({ marker: ["ts", "ts2"], exact: ["foo|foo", "foo|bar", "foo|baz"] });
|
||||
Reference in New Issue
Block a user