Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed an out-of-order quick info issue with contextual rest parameter #57580

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15122,11 +15122,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return symbol && withAugmentations ? getMergedSymbol(symbol) : symbol;
}

function hasEffectiveQuestionToken(node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag) {
return hasQuestionToken(node) || isOptionalJSDocPropertyLikeTag(node) || isParameter(node) && isJSDocOptionalParameter(node);
}

function isOptionalParameter(node: ParameterDeclaration | JSDocParameterTag | JSDocPropertyTag) {
if (hasQuestionToken(node) || isOptionalJSDocPropertyLikeTag(node) || isJSDocOptionalParameter(node)) {
if (hasEffectiveQuestionToken(node)) {
return true;
}

if (!isParameter(node)) {
return false;
}
if (node.initializer) {
const signature = getSignatureFromDeclaration(node.parent);
const parameterIndex = node.parent.parameters.indexOf(node);
Expand Down Expand Up @@ -15256,10 +15262,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

// Record a new minimum argument count if this is not an optional parameter
const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) ||
param.initializer || param.questionToken || isRestParameter(param) ||
iife && parameters.length > iife.arguments.length && !type ||
isJSDocOptionalParameter(param);
const isOptionalParameter = hasEffectiveQuestionToken(param) ||
isParameter(param) && param.initializer || isRestParameter(param) ||
iife && parameters.length > iife.arguments.length && !type;
if (!isOptionalParameter) {
minArgumentCount = parameters.length;
}
Expand Down Expand Up @@ -49601,7 +49606,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_cannot_have_an_initializer);
}
}
else if (isOptionalParameter(parameter)) {
else if (hasEffectiveQuestionToken(parameter)) {
seenOptionalParameter = true;
if (parameter.questionToken && parameter.initializer) {
return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer);
Expand Down
5 changes: 2 additions & 3 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,6 @@ import {
JSDocMemberName,
JSDocOverloadTag,
JSDocParameterTag,
JSDocPropertyLikeTag,
JSDocSatisfiesExpression,
JSDocSatisfiesTag,
JSDocSignature,
Expand Down Expand Up @@ -10485,7 +10484,7 @@ export function canHaveExportModifier(node: Node): node is Extract<HasModifiers,
}

/** @internal */
export function isOptionalJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag {
export function isOptionalJSDocPropertyLikeTag(node: Node): boolean {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken this function wasn't proving that the input is JSDocPropertyLikeTag - some extra checks on a variable with JSDocPropertyLikeTag type were done here and it could still return false for it. So this wasn't a correct return type annotation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's certainly not the first type guard we've had which has lied for convenience's sake. But it doesn't seem like it really helped here.

if (!isJSDocPropertyLikeTag(node)) {
return false;
}
Expand Down Expand Up @@ -10514,7 +10513,7 @@ export function isJSDocOptionalParameter(node: ParameterDeclaration) {
return isInJSFile(node) && (
// node.type should only be a JSDocOptionalType when node is a parameter of a JSDocFunctionType
node.type && node.type.kind === SyntaxKind.JSDocOptionalType
|| getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) => isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType)
|| getJSDocParameterTags(node).some(isOptionalJSDocPropertyLikeTag)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
// return curry(getStylingByKeys, 2)(mergedStyling, ...args);
// ^^^^
// | ----------------------------------------------------------------------
// | (parameter) args: any
// | (parameter) args: []
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the correct display that we can see when hovering at this location in the playground (after the playgrounds gets typechecked first): TS playground. If we make an edit and quickly hover over this location we can sometimes "catch" this any being displayed since then the quick info request happens before computing semantic diagnostics and this is exactly what this test is doing.

// | ----------------------------------------------------------------------
// },
// 3
Expand Down Expand Up @@ -135,8 +135,12 @@
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
"text": "[",
"kind": "punctuation"
},
{
"text": "]",
"kind": "punctuation"
}
],
"documentation": []
Expand Down
Loading