Fix isolated declarations to not flag function expressions in call arguments

Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-07-25 14:21:45 +00:00
parent 655637f611
commit 486c12af19
6 changed files with 361 additions and 150 deletions

View File

@ -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) {

View File

@ -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<WithIsolatedDeclarationDiagnostic>(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<never>(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<WithIsolatedDeclarationDiagnostic>(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<never>(node);
return createExpressionError(node as Expression);
}
}
function findNearestDeclaration(node: Node) {

View File

@ -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<T>(fn: T): T;
declare function action<T>(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;
});

View File

@ -0,0 +1,38 @@
//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] ////
//// [isolatedDeclarationsFunctionExpressionInCall.ts]
declare function observer<T>(fn: T): T;
declare function action<T>(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;
});

View File

@ -0,0 +1,49 @@
//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] ////
=== isolatedDeclarationsFunctionExpressionInCall.ts ===
declare function observer<T>(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<T>(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))
});

View File

@ -0,0 +1,80 @@
//// [tests/cases/compiler/isolatedDeclarationsFunctionExpressionInCall.ts] ////
=== isolatedDeclarationsFunctionExpressionInCall.ts ===
declare function observer<T>(fn: T): T;
>observer : <T>(fn: T) => T
> : ^ ^^ ^^ ^^^^^
>fn : T
> : ^
declare function action<T>(fn: T): T;
>action : <T>(fn: T) => T
> : ^ ^^ ^^ ^^^^^
>fn : T
> : ^
export const Component = observer(() => {
>Component : () => "hello"
> : ^^^^^^^^^^^^^
>observer(() => { return "hello";}) : () => "hello"
> : ^^^^^^^^^^^^^
>observer : <T>(fn: T) => T
> : ^ ^^ ^^ ^^^^^
>() => { return "hello";} : () => "hello"
> : ^^^^^^^^^^^^^
return "hello";
>"hello" : "hello"
> : ^^^^^^^
});
export const thing = action(function () {
>thing : () => () => "hello"
> : ^^^^^^^^^^^^^^^^^^^
>action(function () { return Component;}) : () => () => "hello"
> : ^^^^^^^^^^^^^^^^^^^
>action : <T>(fn: T) => T
> : ^ ^^ ^^ ^^^^^
>function () { return Component;} : () => () => "hello"
> : ^^^^^^^^^^^^^^^^^^^
return Component;
>Component : () => "hello"
> : ^^^^^^^^^^^^^
});
export const arrowWithType = observer((): string => {
>arrowWithType : () => string
> : ^^^^^^
>observer((): string => { return "typed";}) : () => string
> : ^^^^^^
>observer : <T>(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 : <T>(fn: T) => T
> : ^ ^^ ^^ ^^^^^
>function (): typeof Component { return Component;} : () => typeof Component
> : ^^^^^^
>Component : () => "hello"
> : ^^^^^^^^^^^^^
return Component;
>Component : () => "hello"
> : ^^^^^^^^^^^^^
});