From 486c12af195cc9505d699e4a1376bb5408da9700 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 25 Jul 2025 14:21:45 +0000 Subject: [PATCH] Fix isolated declarations to not flag function expressions in call arguments Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- src/compiler/transformers/declarations.ts | 30 +- .../transformers/declarations/diagnostics.ts | 277 +++++++++--------- ...rationsFunctionExpressionInCall.errors.txt | 37 +++ ...tedDeclarationsFunctionExpressionInCall.js | 38 +++ ...clarationsFunctionExpressionInCall.symbols | 49 ++++ ...DeclarationsFunctionExpressionInCall.types | 80 +++++ 6 files changed, 361 insertions(+), 150 deletions(-) create mode 100644 tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.errors.txt create mode 100644 tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.js create mode 100644 tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.symbols create mode 100644 tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.types diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 4b6941dc61f..51ddab79ae1 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -91,9 +91,10 @@ import { isAmbientModule, isArray, isArrayBindingElement, - isBinaryExpression, - isBindingElement, - isBindingPattern, + isBinaryExpression, + isBindingElement, + isBindingPattern, + isCallExpression, isClassDeclaration, isClassElement, isComputedPropertyName, @@ -324,15 +325,20 @@ export function transformDeclarations(context: TransformationContext): Transform } }); } - function reportInferenceFallback(node: Node) { - if (!isolatedDeclarations || isSourceFileJS(currentSourceFile)) return; - if (getSourceFileOfNode(node) !== currentSourceFile) return; // Nested error on a declaration in another file - ignore, will be reemitted if file is in the output file set - if (isVariableDeclaration(node) && resolver.isExpandoFunctionDeclaration(node)) { - reportExpandoFunctionErrors(node); - } - else { - context.addDiagnostic(getIsolatedDeclarationError(node)); - } + function reportInferenceFallback(node: Node) { + if (!isolatedDeclarations || isSourceFileJS(currentSourceFile)) return; + if (getSourceFileOfNode(node) !== currentSourceFile) return; // Nested error on a declaration in another file - ignore, will be reemitted if file is in the output file set + if (isVariableDeclaration(node) && resolver.isExpandoFunctionDeclaration(node)) { + reportExpandoFunctionErrors(node); + } + else { + // Don't report errors for function expressions that are arguments to call expressions + if ((node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction) && + isCallExpression(node.parent)) { + return; + } + context.addDiagnostic(getIsolatedDeclarationError(node)); + } } function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) { if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) { diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 873f23cbf79..e01da0b08ff 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -1,100 +1,101 @@ -import { - addRelatedInfo, - ArrayLiteralExpression, - ArrowFunction, - assertType, - BinaryExpression, - BindingElement, - CallSignatureDeclaration, - ClassExpression, - ComputedPropertyName, - ConstructorDeclaration, - ConstructSignatureDeclaration, - createDiagnosticForNode, - Debug, - Declaration, - DeclarationName, - DiagnosticMessage, - Diagnostics, - DiagnosticWithLocation, - ElementAccessExpression, - EmitResolver, - EntityNameOrEntityNameExpression, - ExportAssignment, - Expression, - ExpressionWithTypeArguments, - findAncestor, - FunctionDeclaration, - FunctionExpression, - FunctionLikeDeclaration, - GetAccessorDeclaration, - getAllAccessorDeclarations, - getNameOfDeclaration, - getTextOfNode, - hasSyntacticModifier, - ImportEqualsDeclaration, - IndexSignatureDeclaration, - isAsExpression, - isBinaryExpression, - isBindingElement, - isCallSignatureDeclaration, - isClassDeclaration, - isConstructorDeclaration, - isConstructSignatureDeclaration, - isElementAccessExpression, - isEntityName, - isEntityNameExpression, - isExportAssignment, - isExpressionWithTypeArguments, - isFunctionDeclaration, - isFunctionLikeDeclaration, - isGetAccessor, - isHeritageClause, - isImportEqualsDeclaration, - isIndexSignatureDeclaration, - isJSDocTypeAlias, - isMethodDeclaration, - isMethodSignature, - isParameter, - isParameterPropertyDeclaration, - isParenthesizedExpression, - isPartOfTypeNode, - isPropertyAccessExpression, - isPropertyDeclaration, - isPropertySignature, - isReturnStatement, - isSetAccessor, - isStatement, - isStatic, - isTypeAliasDeclaration, - isTypeAssertionExpression, - isTypeParameterDeclaration, - isTypeQueryNode, - isVariableDeclaration, - JSDocCallbackTag, - JSDocEnumTag, - JSDocTypedefTag, - MethodDeclaration, - MethodSignature, - ModifierFlags, - NamedDeclaration, - Node, - ParameterDeclaration, - PropertyAccessExpression, - PropertyAssignment, - PropertyDeclaration, - PropertySignature, - QualifiedName, - SetAccessorDeclaration, - ShorthandPropertyAssignment, - SpreadAssignment, - SpreadElement, - SymbolAccessibility, - SymbolAccessibilityResult, - SyntaxKind, - TypeAliasDeclaration, - TypeParameterDeclaration, - VariableDeclaration, +import { + addRelatedInfo, + ArrayLiteralExpression, + ArrowFunction, + assertType, + BinaryExpression, + BindingElement, + CallSignatureDeclaration, + ClassExpression, + ComputedPropertyName, + ConstructorDeclaration, + ConstructSignatureDeclaration, + createDiagnosticForNode, + Debug, + Declaration, + DeclarationName, + DiagnosticMessage, + Diagnostics, + DiagnosticWithLocation, + ElementAccessExpression, + EmitResolver, + EntityNameOrEntityNameExpression, + ExportAssignment, + Expression, + ExpressionWithTypeArguments, + findAncestor, + FunctionDeclaration, + FunctionExpression, + FunctionLikeDeclaration, + GetAccessorDeclaration, + getAllAccessorDeclarations, + getNameOfDeclaration, + getTextOfNode, + hasSyntacticModifier, + ImportEqualsDeclaration, + IndexSignatureDeclaration, + isAsExpression, + isBinaryExpression, + isBindingElement, + isCallExpression, + isCallSignatureDeclaration, + isClassDeclaration, + isConstructorDeclaration, + isConstructSignatureDeclaration, + isElementAccessExpression, + isEntityName, + isEntityNameExpression, + isExportAssignment, + isExpressionWithTypeArguments, + isFunctionDeclaration, + isFunctionLikeDeclaration, + isGetAccessor, + isHeritageClause, + isImportEqualsDeclaration, + isIndexSignatureDeclaration, + isJSDocTypeAlias, + isMethodDeclaration, + isMethodSignature, + isParameter, + isParameterPropertyDeclaration, + isParenthesizedExpression, + isPartOfTypeNode, + isPropertyAccessExpression, + isPropertyDeclaration, + isPropertySignature, + isReturnStatement, + isSetAccessor, + isStatement, + isStatic, + isTypeAliasDeclaration, + isTypeAssertionExpression, + isTypeParameterDeclaration, + isTypeQueryNode, + isVariableDeclaration, + JSDocCallbackTag, + JSDocEnumTag, + JSDocTypedefTag, + MethodDeclaration, + MethodSignature, + ModifierFlags, + NamedDeclaration, + Node, + ParameterDeclaration, + PropertyAccessExpression, + PropertyAssignment, + PropertyDeclaration, + PropertySignature, + QualifiedName, + SetAccessorDeclaration, + ShorthandPropertyAssignment, + SpreadAssignment, + SpreadElement, + SymbolAccessibility, + SymbolAccessibilityResult, + SyntaxKind, + TypeAliasDeclaration, + TypeParameterDeclaration, + VariableDeclaration, } from "../../_namespaces/ts.js"; /** @internal */ @@ -661,47 +662,47 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver): (nod | PropertyAssignment | ClassExpression; - function getDiagnostic(node: Node) { - const heritageClause = findAncestor(node, isHeritageClause); - if (heritageClause) { - return createDiagnosticForNode(node, Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations); - } - if ((isPartOfTypeNode(node) || isTypeQueryNode(node.parent)) && (isEntityName(node) || isEntityNameExpression(node))) { - return createEntityInTypeNodeError(node); - } - Debug.type(node); - switch (node.kind) { - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - return createAccessorTypeError(node); - case SyntaxKind.ComputedPropertyName: - case SyntaxKind.ShorthandPropertyAssignment: - case SyntaxKind.SpreadAssignment: - return createObjectLiteralError(node); - case SyntaxKind.ArrayLiteralExpression: - case SyntaxKind.SpreadElement: - return createArrayLiteralError(node); - case SyntaxKind.MethodDeclaration: - case SyntaxKind.ConstructSignature: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.FunctionDeclaration: - return createReturnTypeError(node); - case SyntaxKind.BindingElement: - return createBindingElementError(node); - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.VariableDeclaration: - return createVariableOrPropertyError(node); - case SyntaxKind.Parameter: - return createParameterError(node); - case SyntaxKind.PropertyAssignment: - return createExpressionError(node.initializer); - case SyntaxKind.ClassExpression: - return createClassExpressionError(node); - default: - assertType(node); - return createExpressionError(node as Expression); - } + function getDiagnostic(node: Node) { + const heritageClause = findAncestor(node, isHeritageClause); + if (heritageClause) { + return createDiagnosticForNode(node, Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations); + } + if ((isPartOfTypeNode(node) || isTypeQueryNode(node.parent)) && (isEntityName(node) || isEntityNameExpression(node))) { + return createEntityInTypeNodeError(node); + } + Debug.type(node); + switch (node.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return createAccessorTypeError(node); + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.SpreadAssignment: + return createObjectLiteralError(node); + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.SpreadElement: + return createArrayLiteralError(node); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.ConstructSignature: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + return createReturnTypeError(node); + case SyntaxKind.BindingElement: + return createBindingElementError(node); + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.VariableDeclaration: + return createVariableOrPropertyError(node); + case SyntaxKind.Parameter: + return createParameterError(node); + case SyntaxKind.PropertyAssignment: + return createExpressionError(node.initializer); + case SyntaxKind.ClassExpression: + return createClassExpressionError(node); + default: + assertType(node); + return createExpressionError(node as Expression); + } } function findNearestDeclaration(node: Node) { diff --git a/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.errors.txt b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.errors.txt new file mode 100644 index 00000000000..fd15b62fdaf --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.errors.txt @@ -0,0 +1,37 @@ +isolatedDeclarationsFunctionExpressionInCall.ts(4,14): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +isolatedDeclarationsFunctionExpressionInCall.ts(8,14): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +isolatedDeclarationsFunctionExpressionInCall.ts(12,14): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +isolatedDeclarationsFunctionExpressionInCall.ts(16,14): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. + + +==== isolatedDeclarationsFunctionExpressionInCall.ts (4 errors) ==== + declare function observer(fn: T): T; + declare function action(fn: T): T; + + export const Component = observer(() => { + ~~~~~~~~~ +!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +!!! related TS9027 isolatedDeclarationsFunctionExpressionInCall.ts:4:14: Add a type annotation to the variable Component. + return "hello"; + }); + + export const thing = action(function () { + ~~~~~ +!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +!!! related TS9027 isolatedDeclarationsFunctionExpressionInCall.ts:8:14: Add a type annotation to the variable thing. + return Component; + }); + + export const arrowWithType = observer((): string => { + ~~~~~~~~~~~~~ +!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +!!! related TS9027 isolatedDeclarationsFunctionExpressionInCall.ts:12:14: Add a type annotation to the variable arrowWithType. + return "typed"; + }); + + export const functionWithType = action(function (): typeof Component { + ~~~~~~~~~~~~~~~~ +!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations. +!!! related TS9027 isolatedDeclarationsFunctionExpressionInCall.ts:16:14: Add a type annotation to the variable functionWithType. + return Component; + }); \ No newline at end of file diff --git a/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.js b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.js new file mode 100644 index 00000000000..a564a4355c0 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.js @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] //// + +//// [isolatedDeclarationsFunctionExpressionInCall.ts] +declare function observer(fn: T): T; +declare function action(fn: T): T; + +export const Component = observer(() => { + return "hello"; +}); + +export const thing = action(function () { + return Component; +}); + +export const arrowWithType = observer((): string => { + return "typed"; +}); + +export const functionWithType = action(function (): typeof Component { + return Component; +}); + +//// [isolatedDeclarationsFunctionExpressionInCall.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.functionWithType = exports.arrowWithType = exports.thing = exports.Component = void 0; +exports.Component = observer(function () { + return "hello"; +}); +exports.thing = action(function () { + return exports.Component; +}); +exports.arrowWithType = observer(function () { + return "typed"; +}); +exports.functionWithType = action(function () { + return exports.Component; +}); diff --git a/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.symbols b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.symbols new file mode 100644 index 00000000000..f49dd100fd1 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.symbols @@ -0,0 +1,49 @@ +//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] //// + +=== isolatedDeclarationsFunctionExpressionInCall.ts === +declare function observer(fn: T): T; +>observer : Symbol(observer, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 0)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 26)) +>fn : Symbol(fn, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 29)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 26)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 26)) + +declare function action(fn: T): T; +>action : Symbol(action, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 39)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 1, 24)) +>fn : Symbol(fn, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 1, 27)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 1, 24)) +>T : Symbol(T, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 1, 24)) + +export const Component = observer(() => { +>Component : Symbol(Component, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 3, 12)) +>observer : Symbol(observer, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 0)) + + return "hello"; +}); + +export const thing = action(function () { +>thing : Symbol(thing, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 7, 12)) +>action : Symbol(action, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 39)) + + return Component; +>Component : Symbol(Component, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 3, 12)) + +}); + +export const arrowWithType = observer((): string => { +>arrowWithType : Symbol(arrowWithType, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 11, 12)) +>observer : Symbol(observer, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 0)) + + return "typed"; +}); + +export const functionWithType = action(function (): typeof Component { +>functionWithType : Symbol(functionWithType, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 15, 12)) +>action : Symbol(action, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 0, 39)) +>Component : Symbol(Component, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 3, 12)) + + return Component; +>Component : Symbol(Component, Decl(isolatedDeclarationsFunctionExpressionInCall.ts, 3, 12)) + +}); diff --git a/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.types b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.types new file mode 100644 index 00000000000..a56d8aa4144 --- /dev/null +++ b/tests/baselines/reference/isolatedDeclarationsFunctionExpressionInCall.types @@ -0,0 +1,80 @@ +//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] //// + +=== isolatedDeclarationsFunctionExpressionInCall.ts === +declare function observer(fn: T): T; +>observer : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>fn : T +> : ^ + +declare function action(fn: T): T; +>action : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>fn : T +> : ^ + +export const Component = observer(() => { +>Component : () => "hello" +> : ^^^^^^^^^^^^^ +>observer(() => { return "hello";}) : () => "hello" +> : ^^^^^^^^^^^^^ +>observer : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>() => { return "hello";} : () => "hello" +> : ^^^^^^^^^^^^^ + + return "hello"; +>"hello" : "hello" +> : ^^^^^^^ + +}); + +export const thing = action(function () { +>thing : () => () => "hello" +> : ^^^^^^^^^^^^^^^^^^^ +>action(function () { return Component;}) : () => () => "hello" +> : ^^^^^^^^^^^^^^^^^^^ +>action : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>function () { return Component;} : () => () => "hello" +> : ^^^^^^^^^^^^^^^^^^^ + + return Component; +>Component : () => "hello" +> : ^^^^^^^^^^^^^ + +}); + +export const arrowWithType = observer((): string => { +>arrowWithType : () => string +> : ^^^^^^ +>observer((): string => { return "typed";}) : () => string +> : ^^^^^^ +>observer : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>(): string => { return "typed";} : () => string +> : ^^^^^^ + + return "typed"; +>"typed" : "typed" +> : ^^^^^^^ + +}); + +export const functionWithType = action(function (): typeof Component { +>functionWithType : () => typeof Component +> : ^^^^^^ +>action(function (): typeof Component { return Component;}) : () => typeof Component +> : ^^^^^^ +>action : (fn: T) => T +> : ^ ^^ ^^ ^^^^^ +>function (): typeof Component { return Component;} : () => typeof Component +> : ^^^^^^ +>Component : () => "hello" +> : ^^^^^^^^^^^^^ + + return Component; +>Component : () => "hello" +> : ^^^^^^^^^^^^^ + +});