From f55c6a20f98a06eea96f2ac1c1ce1b339ac8d0ae Mon Sep 17 00:00:00 2001 From: Tanzim Hossain Romel Date: Tue, 16 Dec 2025 00:29:12 +0600 Subject: [PATCH 1/4] Report error for function declarations as statement children in strict mode Fixes #62896 In strict mode, function declarations can only appear at the top level of a script, module, or function body, or inside a block. Code like `if (true) function f() {}` is a syntax error in strict mode but TypeScript was not reporting it. This change adds a check in the binder to detect when a function declaration is a direct child of a statement node (IfStatement, WhileStatement, DoStatement, ForStatement, ForInStatement, ForOfStatement, WithStatement, or LabeledStatement) and reports error TS1256. --- src/compiler/binder.ts | 24 ++++ src/compiler/diagnosticMessages.json | 4 + ...larationAsStatementInStrictMode.errors.txt | 53 +++++++++ ...ctionDeclarationAsStatementInStrictMode.js | 75 ++++++++++++ ...DeclarationAsStatementInStrictMode.symbols | 63 ++++++++++ ...onDeclarationAsStatementInStrictMode.types | 108 ++++++++++++++++++ ...ctionDeclarationAsStatementInStrictMode.ts | 28 +++++ 7 files changed, 355 insertions(+) create mode 100644 tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt create mode 100644 tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js create mode 100644 tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols create mode 100644 tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types create mode 100644 tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b01352968eb42..ab5a14880e1db 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2705,6 +2705,30 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, getStrictModeBlockScopeFunctionDeclarationMessage(node))); } } + // In strict mode, function declarations are not allowed as the direct child of a statement. + // For example: `if (true) function f() {}` is a syntax error in strict mode. + // This applies regardless of the target version. + if (inStrictMode && isFunctionDeclarationStatementChild(node)) { + const errorSpan = getErrorSpanForNode(file, node); + file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, Diagnostics.In_strict_mode_code_functions_can_only_be_declared_at_top_level_or_inside_a_block)); + } + } + + function isFunctionDeclarationStatementChild(node: FunctionDeclaration): boolean { + const parent = node.parent; + switch (parent.kind) { + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.LabeledStatement: + return true; + default: + return false; + } } function checkStrictModePostfixUnaryExpression(node: PostfixUnaryExpression) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 03f5f19a69877..43b087c9a4a06 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -823,6 +823,10 @@ "category": "Error", "code": 1255 }, + "In strict mode code, functions can only be declared at top level or inside a block.": { + "category": "Error", + "code": 1256 + }, "A required element cannot follow an optional element.": { "category": "Error", "code": 1257 diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt new file mode 100644 index 0000000000000..8bb0f2a99ed24 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt @@ -0,0 +1,53 @@ +functionDeclarationAsStatementInStrictMode.ts(2,20): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(3,23): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(4,13): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(5,19): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(6,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(7,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(8,1): error TS1344: 'A label is not allowed here. +functionDeclarationAsStatementInStrictMode.ts(8,17): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + + +==== functionDeclarationAsStatementInStrictMode.ts (8 errors) ==== + // Error cases - function declarations as direct children of statements in strict mode + if (true) function f1() {} + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + while (true) function f2() {} + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + do function f3() {} while (false); + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + for (;;) function f4() {} + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + for (let x in {}) function f5() {} + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + for (let x of []) function f6() {} + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + label: function f7() {} + ~~~~~ +!!! error TS1344: 'A label is not allowed here. + ~~ +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. + + // Valid cases - function declarations inside blocks + if (true) { function g1() {} } + while (true) { function g2() {} } + do { function g3() {} } while (false); + for (;;) { function g4() {} } + for (let x in {}) { function g5() {} } + for (let x of []) { function g6() {} } + label: { function g7() {} } + + // Valid - top level + function topLevel() {} + + // Valid - inside function body + function outer() { + function inner() {} + } + \ No newline at end of file diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js new file mode 100644 index 0000000000000..b79687c2c7dd6 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// + +//// [functionDeclarationAsStatementInStrictMode.ts] +// Error cases - function declarations as direct children of statements in strict mode +if (true) function f1() {} +while (true) function f2() {} +do function f3() {} while (false); +for (;;) function f4() {} +for (let x in {}) function f5() {} +for (let x of []) function f6() {} +label: function f7() {} + +// Valid cases - function declarations inside blocks +if (true) { function g1() {} } +while (true) { function g2() {} } +do { function g3() {} } while (false); +for (;;) { function g4() {} } +for (let x in {}) { function g5() {} } +for (let x of []) { function g6() {} } +label: { function g7() {} } + +// Valid - top level +function topLevel() {} + +// Valid - inside function body +function outer() { + function inner() {} +} + + +//// [functionDeclarationAsStatementInStrictMode.js] +"use strict"; +// Error cases - function declarations as direct children of statements in strict mode +if (true) + function f1() { } +while (true) + function f2() { } +do + function f3() { } +while (false); +for (;;) + function f4() { } +for (let x in {}) + function f5() { } +for (let x of []) + function f6() { } +label: function f7() { } +// Valid cases - function declarations inside blocks +if (true) { + function g1() { } +} +while (true) { + function g2() { } +} +do { + function g3() { } +} while (false); +for (;;) { + function g4() { } +} +for (let x in {}) { + function g5() { } +} +for (let x of []) { + function g6() { } +} +label: { + function g7() { } +} +// Valid - top level +function topLevel() { } +// Valid - inside function body +function outer() { + function inner() { } +} diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols new file mode 100644 index 0000000000000..1f408d25375d2 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols @@ -0,0 +1,63 @@ +//// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// + +=== functionDeclarationAsStatementInStrictMode.ts === +// Error cases - function declarations as direct children of statements in strict mode +if (true) function f1() {} +>f1 : Symbol(f1, Decl(functionDeclarationAsStatementInStrictMode.ts, 1, 9)) + +while (true) function f2() {} +>f2 : Symbol(f2, Decl(functionDeclarationAsStatementInStrictMode.ts, 2, 12)) + +do function f3() {} while (false); +>f3 : Symbol(f3, Decl(functionDeclarationAsStatementInStrictMode.ts, 3, 2)) + +for (;;) function f4() {} +>f4 : Symbol(f4, Decl(functionDeclarationAsStatementInStrictMode.ts, 4, 8)) + +for (let x in {}) function f5() {} +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 8)) +>f5 : Symbol(f5, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 17)) + +for (let x of []) function f6() {} +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 8)) +>f6 : Symbol(f6, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 17)) + +label: function f7() {} +>f7 : Symbol(f7, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 6)) + +// Valid cases - function declarations inside blocks +if (true) { function g1() {} } +>g1 : Symbol(g1, Decl(functionDeclarationAsStatementInStrictMode.ts, 10, 11)) + +while (true) { function g2() {} } +>g2 : Symbol(g2, Decl(functionDeclarationAsStatementInStrictMode.ts, 11, 14)) + +do { function g3() {} } while (false); +>g3 : Symbol(g3, Decl(functionDeclarationAsStatementInStrictMode.ts, 12, 4)) + +for (;;) { function g4() {} } +>g4 : Symbol(g4, Decl(functionDeclarationAsStatementInStrictMode.ts, 13, 10)) + +for (let x in {}) { function g5() {} } +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 8)) +>g5 : Symbol(g5, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 19)) + +for (let x of []) { function g6() {} } +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 8)) +>g6 : Symbol(g6, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 19)) + +label: { function g7() {} } +>g7 : Symbol(g7, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 8)) + +// Valid - top level +function topLevel() {} +>topLevel : Symbol(topLevel, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 27)) + +// Valid - inside function body +function outer() { +>outer : Symbol(outer, Decl(functionDeclarationAsStatementInStrictMode.ts, 19, 22)) + + function inner() {} +>inner : Symbol(inner, Decl(functionDeclarationAsStatementInStrictMode.ts, 22, 18)) +} + diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types new file mode 100644 index 0000000000000..c5cbe73becb95 --- /dev/null +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types @@ -0,0 +1,108 @@ +//// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// + +=== functionDeclarationAsStatementInStrictMode.ts === +// Error cases - function declarations as direct children of statements in strict mode +if (true) function f1() {} +>true : true +> : ^^^^ +>f1 : () => void +> : ^^^^^^^^^^ + +while (true) function f2() {} +>true : true +> : ^^^^ +>f2 : () => void +> : ^^^^^^^^^^ + +do function f3() {} while (false); +>f3 : () => void +> : ^^^^^^^^^^ +>false : false +> : ^^^^^ + +for (;;) function f4() {} +>f4 : () => void +> : ^^^^^^^^^^ + +for (let x in {}) function f5() {} +>x : string +> : ^^^^^^ +>{} : {} +> : ^^ +>f5 : () => void +> : ^^^^^^^^^^ + +for (let x of []) function f6() {} +>x : never +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ +>f6 : () => void +> : ^^^^^^^^^^ + +label: function f7() {} +>label : any +> : ^^^ +>f7 : () => void +> : ^^^^^^^^^^ + +// Valid cases - function declarations inside blocks +if (true) { function g1() {} } +>true : true +> : ^^^^ +>g1 : () => void +> : ^^^^^^^^^^ + +while (true) { function g2() {} } +>true : true +> : ^^^^ +>g2 : () => void +> : ^^^^^^^^^^ + +do { function g3() {} } while (false); +>g3 : () => void +> : ^^^^^^^^^^ +>false : false +> : ^^^^^ + +for (;;) { function g4() {} } +>g4 : () => void +> : ^^^^^^^^^^ + +for (let x in {}) { function g5() {} } +>x : string +> : ^^^^^^ +>{} : {} +> : ^^ +>g5 : () => void +> : ^^^^^^^^^^ + +for (let x of []) { function g6() {} } +>x : never +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ +>g6 : () => void +> : ^^^^^^^^^^ + +label: { function g7() {} } +>label : any +> : ^^^ +>g7 : () => void +> : ^^^^^^^^^^ + +// Valid - top level +function topLevel() {} +>topLevel : () => void +> : ^^^^^^^^^^ + +// Valid - inside function body +function outer() { +>outer : () => void +> : ^^^^^^^^^^ + + function inner() {} +>inner : () => void +> : ^^^^^^^^^^ +} + diff --git a/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts new file mode 100644 index 0000000000000..83f8eb951e42d --- /dev/null +++ b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts @@ -0,0 +1,28 @@ +// @strict: true +// @target: ES2020 + +// Error cases - function declarations as direct children of statements in strict mode +if (true) function f1() {} +while (true) function f2() {} +do function f3() {} while (false); +for (;;) function f4() {} +for (let x in {}) function f5() {} +for (let x of []) function f6() {} +label: function f7() {} + +// Valid cases - function declarations inside blocks +if (true) { function g1() {} } +while (true) { function g2() {} } +do { function g3() {} } while (false); +for (;;) { function g4() {} } +for (let x in {}) { function g5() {} } +for (let x of []) { function g6() {} } +label: { function g7() {} } + +// Valid - top level +function topLevel() {} + +// Valid - inside function body +function outer() { + function inner() {} +} From 6a1ff4b3af3b18881e75f5d03d9c879baa241fbb Mon Sep 17 00:00:00 2001 From: Tanzim Hossain Romel Date: Tue, 16 Dec 2025 00:43:38 +0600 Subject: [PATCH 2/4] Report error unconditionally since TypeScript assumes strict mode Update the fix to report the error regardless of strict mode context, as TypeScript assumes strict mode at all times. Also improved the error message to be more helpful: "Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration." --- src/compiler/binder.ts | 21 +++++---- src/compiler/diagnosticMessages.json | 2 +- ...larationAsStatementInStrictMode.errors.txt | 36 +++++++-------- ...ctionDeclarationAsStatementInStrictMode.js | 7 +-- ...DeclarationAsStatementInStrictMode.symbols | 45 ++++++++++--------- ...onDeclarationAsStatementInStrictMode.types | 19 ++++---- ...ctionDeclarationAsStatementInStrictMode.ts | 4 +- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index ab5a14880e1db..07e8934903834 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2705,16 +2705,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, getStrictModeBlockScopeFunctionDeclarationMessage(node))); } } - // In strict mode, function declarations are not allowed as the direct child of a statement. - // For example: `if (true) function f() {}` is a syntax error in strict mode. - // This applies regardless of the target version. - if (inStrictMode && isFunctionDeclarationStatementChild(node)) { - const errorSpan = getErrorSpanForNode(file, node); - file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, Diagnostics.In_strict_mode_code_functions_can_only_be_declared_at_top_level_or_inside_a_block)); - } } - function isFunctionDeclarationStatementChild(node: FunctionDeclaration): boolean { + // Function declarations are not allowed as the direct child of a statement. + // For example: `if (true) function f() {}` is a syntax error in strict mode. + // Since TypeScript assumes strict mode at all times, this is always an error. + function checkFunctionDeclarationStatementChild(node: FunctionDeclaration) { const parent = node.parent; switch (parent.kind) { case SyntaxKind.IfStatement: @@ -2725,9 +2721,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.ForOfStatement: case SyntaxKind.WithStatement: case SyntaxKind.LabeledStatement: - return true; - default: - return false; + const errorSpan = getErrorSpanForNode(file, node); + file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, Diagnostics.Function_declarations_are_not_allowed_inside_statements_Use_a_block_statement_to_wrap_the_function_declaration)); + break; } } @@ -3737,6 +3733,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } checkStrictModeFunctionName(node); + // Function declarations as direct children of statements are always an error + // since TypeScript assumes strict mode at all times. + checkFunctionDeclarationStatementChild(node); if (inStrictMode) { checkStrictModeFunctionDeclaration(node); bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 43b087c9a4a06..2e5169c44ac1e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -823,7 +823,7 @@ "category": "Error", "code": 1255 }, - "In strict mode code, functions can only be declared at top level or inside a block.": { + "Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration.": { "category": "Error", "code": 1256 }, diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt index 8bb0f2a99ed24..c065544131229 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt @@ -1,38 +1,36 @@ -functionDeclarationAsStatementInStrictMode.ts(2,20): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(3,23): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(4,13): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(5,19): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(6,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(7,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -functionDeclarationAsStatementInStrictMode.ts(8,1): error TS1344: 'A label is not allowed here. -functionDeclarationAsStatementInStrictMode.ts(8,17): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(3,20): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(4,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(5,13): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(6,19): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(7,28): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(8,28): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(9,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -==== functionDeclarationAsStatementInStrictMode.ts (8 errors) ==== - // Error cases - function declarations as direct children of statements in strict mode +==== functionDeclarationAsStatementInStrictMode.ts (7 errors) ==== + // Error cases - function declarations as direct children of statements + // TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() {} ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. while (true) function f2() {} ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. do function f3() {} while (false); ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. for (;;) function f4() {} ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. for (let x in {}) function f5() {} ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. for (let x of []) function f6() {} ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function f7() {} - ~~~~~ -!!! error TS1344: 'A label is not allowed here. ~~ -!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. // Valid cases - function declarations inside blocks if (true) { function g1() {} } diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js index b79687c2c7dd6..27f8116232cc1 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js @@ -1,7 +1,8 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// //// [functionDeclarationAsStatementInStrictMode.ts] -// Error cases - function declarations as direct children of statements in strict mode +// Error cases - function declarations as direct children of statements +// TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() {} while (true) function f2() {} do function f3() {} while (false); @@ -29,8 +30,8 @@ function outer() { //// [functionDeclarationAsStatementInStrictMode.js] -"use strict"; -// Error cases - function declarations as direct children of statements in strict mode +// Error cases - function declarations as direct children of statements +// TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() { } while (true) diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols index 1f408d25375d2..728614ea75c9a 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols @@ -1,63 +1,64 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// === functionDeclarationAsStatementInStrictMode.ts === -// Error cases - function declarations as direct children of statements in strict mode +// Error cases - function declarations as direct children of statements +// TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() {} ->f1 : Symbol(f1, Decl(functionDeclarationAsStatementInStrictMode.ts, 1, 9)) +>f1 : Symbol(f1, Decl(functionDeclarationAsStatementInStrictMode.ts, 2, 9)) while (true) function f2() {} ->f2 : Symbol(f2, Decl(functionDeclarationAsStatementInStrictMode.ts, 2, 12)) +>f2 : Symbol(f2, Decl(functionDeclarationAsStatementInStrictMode.ts, 3, 12)) do function f3() {} while (false); ->f3 : Symbol(f3, Decl(functionDeclarationAsStatementInStrictMode.ts, 3, 2)) +>f3 : Symbol(f3, Decl(functionDeclarationAsStatementInStrictMode.ts, 4, 2)) for (;;) function f4() {} ->f4 : Symbol(f4, Decl(functionDeclarationAsStatementInStrictMode.ts, 4, 8)) +>f4 : Symbol(f4, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 8)) for (let x in {}) function f5() {} ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 8)) ->f5 : Symbol(f5, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 17)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 8)) +>f5 : Symbol(f5, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 17)) for (let x of []) function f6() {} ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 8)) ->f6 : Symbol(f6, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 17)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 8)) +>f6 : Symbol(f6, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 17)) label: function f7() {} ->f7 : Symbol(f7, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 6)) +>f7 : Symbol(f7, Decl(functionDeclarationAsStatementInStrictMode.ts, 8, 6)) // Valid cases - function declarations inside blocks if (true) { function g1() {} } ->g1 : Symbol(g1, Decl(functionDeclarationAsStatementInStrictMode.ts, 10, 11)) +>g1 : Symbol(g1, Decl(functionDeclarationAsStatementInStrictMode.ts, 11, 11)) while (true) { function g2() {} } ->g2 : Symbol(g2, Decl(functionDeclarationAsStatementInStrictMode.ts, 11, 14)) +>g2 : Symbol(g2, Decl(functionDeclarationAsStatementInStrictMode.ts, 12, 14)) do { function g3() {} } while (false); ->g3 : Symbol(g3, Decl(functionDeclarationAsStatementInStrictMode.ts, 12, 4)) +>g3 : Symbol(g3, Decl(functionDeclarationAsStatementInStrictMode.ts, 13, 4)) for (;;) { function g4() {} } ->g4 : Symbol(g4, Decl(functionDeclarationAsStatementInStrictMode.ts, 13, 10)) +>g4 : Symbol(g4, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 10)) for (let x in {}) { function g5() {} } ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 8)) ->g5 : Symbol(g5, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 19)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 8)) +>g5 : Symbol(g5, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 19)) for (let x of []) { function g6() {} } ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 8)) ->g6 : Symbol(g6, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 19)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 8)) +>g6 : Symbol(g6, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 19)) label: { function g7() {} } ->g7 : Symbol(g7, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 8)) +>g7 : Symbol(g7, Decl(functionDeclarationAsStatementInStrictMode.ts, 17, 8)) // Valid - top level function topLevel() {} ->topLevel : Symbol(topLevel, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 27)) +>topLevel : Symbol(topLevel, Decl(functionDeclarationAsStatementInStrictMode.ts, 17, 27)) // Valid - inside function body function outer() { ->outer : Symbol(outer, Decl(functionDeclarationAsStatementInStrictMode.ts, 19, 22)) +>outer : Symbol(outer, Decl(functionDeclarationAsStatementInStrictMode.ts, 20, 22)) function inner() {} ->inner : Symbol(inner, Decl(functionDeclarationAsStatementInStrictMode.ts, 22, 18)) +>inner : Symbol(inner, Decl(functionDeclarationAsStatementInStrictMode.ts, 23, 18)) } diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types index c5cbe73becb95..1c514f29a26e8 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types @@ -1,7 +1,8 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// === functionDeclarationAsStatementInStrictMode.ts === -// Error cases - function declarations as direct children of statements in strict mode +// Error cases - function declarations as direct children of statements +// TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() {} >true : true > : ^^^^ @@ -33,10 +34,10 @@ for (let x in {}) function f5() {} > : ^^^^^^^^^^ for (let x of []) function f6() {} ->x : never -> : ^^^^^ ->[] : never[] -> : ^^^^^^^ +>x : any +> : ^^^ +>[] : undefined[] +> : ^^^^^^^^^^^ >f6 : () => void > : ^^^^^^^^^^ @@ -78,10 +79,10 @@ for (let x in {}) { function g5() {} } > : ^^^^^^^^^^ for (let x of []) { function g6() {} } ->x : never -> : ^^^^^ ->[] : never[] -> : ^^^^^^^ +>x : any +> : ^^^ +>[] : undefined[] +> : ^^^^^^^^^^^ >g6 : () => void > : ^^^^^^^^^^ diff --git a/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts index 83f8eb951e42d..c1e410fcf820d 100644 --- a/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts +++ b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts @@ -1,7 +1,7 @@ -// @strict: true // @target: ES2020 -// Error cases - function declarations as direct children of statements in strict mode +// Error cases - function declarations as direct children of statements +// TypeScript assumes strict mode at all times, so these are always errors if (true) function f1() {} while (true) function f2() {} do function f3() {} while (false); From e1078ddd5ec3812302a5924875faa8eb00b625d3 Mon Sep 17 00:00:00 2001 From: Tanzim Hossain Romel Date: Tue, 16 Dec 2025 01:50:21 +0600 Subject: [PATCH 3/4] Update baselines for labeled function declaration errors --- .../reference/labeledStatementWithLabel.errors.txt | 11 ++++++++++- .../labeledStatementWithLabel_es2015.errors.txt | 11 ++++++++++- .../labeledStatementWithLabel_strict.errors.txt | 11 ++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/labeledStatementWithLabel.errors.txt b/tests/baselines/reference/labeledStatementWithLabel.errors.txt index 9ec3413158f35..ed923469b9434 100644 --- a/tests/baselines/reference/labeledStatementWithLabel.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel.errors.txt @@ -1,11 +1,20 @@ +labeledStatementWithLabel.ts(1,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel.ts(2,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel.ts(3,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel.ts(11,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. labeledStatementWithLabel.ts(12,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. -==== labeledStatementWithLabel.ts (2 errors) ==== +==== labeledStatementWithLabel.ts (5 errors) ==== label: function fn() { } + ~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function* gen() { } + ~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: async function gen1() { } + ~~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: enum E {} label: interface I {} label: class C { } diff --git a/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt b/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt index 7b0207d9a76b7..67591b42c72bb 100644 --- a/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt @@ -1,11 +1,20 @@ +labeledStatementWithLabel_es2015.ts(1,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel_es2015.ts(2,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel_es2015.ts(3,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel_es2015.ts(11,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. labeledStatementWithLabel_es2015.ts(12,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. -==== labeledStatementWithLabel_es2015.ts (2 errors) ==== +==== labeledStatementWithLabel_es2015.ts (5 errors) ==== label: function fn() { } + ~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function* gen() { } + ~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: async function gen1() { } + ~~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: enum E {} label: interface I {} label: class C { } diff --git a/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt b/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt index 4aaa73d420b0e..86564f70d1592 100644 --- a/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt @@ -1,6 +1,9 @@ labeledStatementWithLabel_strict.ts(2,1): error TS1344: 'A label is not allowed here. +labeledStatementWithLabel_strict.ts(2,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel_strict.ts(3,1): error TS1344: 'A label is not allowed here. +labeledStatementWithLabel_strict.ts(3,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel_strict.ts(4,1): error TS1344: 'A label is not allowed here. +labeledStatementWithLabel_strict.ts(4,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel_strict.ts(5,1): error TS1344: 'A label is not allowed here. labeledStatementWithLabel_strict.ts(6,1): error TS1344: 'A label is not allowed here. labeledStatementWithLabel_strict.ts(7,1): error TS1344: 'A label is not allowed here. @@ -14,17 +17,23 @@ labeledStatementWithLabel_strict.ts(13,8): error TS1235: A namespace declaration labeledStatementWithLabel_strict.ts(14,1): error TS1344: 'A label is not allowed here. -==== labeledStatementWithLabel_strict.ts (14 errors) ==== +==== labeledStatementWithLabel_strict.ts (17 errors) ==== "use strict" label: function fn() { } ~~~~~ !!! error TS1344: 'A label is not allowed here. + ~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function* gen() { } ~~~~~ !!! error TS1344: 'A label is not allowed here. + ~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: async function gen1() { } ~~~~~ !!! error TS1344: 'A label is not allowed here. + ~~~~ +!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: enum E {} ~~~~~ !!! error TS1344: 'A label is not allowed here. From 3b6c85980f6ed6f750e9df23a28e3a8e382985b2 Mon Sep 17 00:00:00 2001 From: Tanzim Hossain Romel Date: Tue, 16 Dec 2025 09:15:50 +0600 Subject: [PATCH 4/4] Only report error in strict mode as per review feedback Per @jakebailey's feedback, TypeScript does not assume strict mode at all times. The error should only be reported when inStrictMode is true, consistent with other strict mode checks like 'with' statements. Updated the error message to mention strict mode and updated baselines accordingly. --- src/compiler/binder.ts | 14 +++--- src/compiler/diagnosticMessages.json | 2 +- ...larationAsStatementInStrictMode.errors.txt | 36 ++++++++------- ...ctionDeclarationAsStatementInStrictMode.js | 7 ++- ...DeclarationAsStatementInStrictMode.symbols | 45 +++++++++---------- ...onDeclarationAsStatementInStrictMode.types | 19 ++++---- .../labeledStatementWithLabel.errors.txt | 11 +---- ...abeledStatementWithLabel_es2015.errors.txt | 11 +---- ...abeledStatementWithLabel_strict.errors.txt | 12 ++--- ...ctionDeclarationAsStatementInStrictMode.ts | 4 +- 10 files changed, 71 insertions(+), 90 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 07e8934903834..1ab005dd99c73 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2707,10 +2707,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } - // Function declarations are not allowed as the direct child of a statement. + // Function declarations are not allowed as the direct child of a statement in strict mode. // For example: `if (true) function f() {}` is a syntax error in strict mode. - // Since TypeScript assumes strict mode at all times, this is always an error. - function checkFunctionDeclarationStatementChild(node: FunctionDeclaration) { + function checkStrictModeFunctionDeclarationAsStatementChild(node: FunctionDeclaration) { + if (!inStrictMode) { + return; + } const parent = node.parent; switch (parent.kind) { case SyntaxKind.IfStatement: @@ -2722,7 +2724,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.WithStatement: case SyntaxKind.LabeledStatement: const errorSpan = getErrorSpanForNode(file, node); - file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, Diagnostics.Function_declarations_are_not_allowed_inside_statements_Use_a_block_statement_to_wrap_the_function_declaration)); + file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, Diagnostics.In_strict_mode_code_functions_can_only_be_declared_at_top_level_or_inside_a_block)); break; } } @@ -3733,9 +3735,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } checkStrictModeFunctionName(node); - // Function declarations as direct children of statements are always an error - // since TypeScript assumes strict mode at all times. - checkFunctionDeclarationStatementChild(node); + checkStrictModeFunctionDeclarationAsStatementChild(node); if (inStrictMode) { checkStrictModeFunctionDeclaration(node); bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 2e5169c44ac1e..43b087c9a4a06 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -823,7 +823,7 @@ "category": "Error", "code": 1255 }, - "Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration.": { + "In strict mode code, functions can only be declared at top level or inside a block.": { "category": "Error", "code": 1256 }, diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt index c065544131229..8bb0f2a99ed24 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.errors.txt @@ -1,36 +1,38 @@ -functionDeclarationAsStatementInStrictMode.ts(3,20): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(4,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(5,13): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(6,19): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(7,28): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(8,28): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -functionDeclarationAsStatementInStrictMode.ts(9,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +functionDeclarationAsStatementInStrictMode.ts(2,20): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(3,23): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(4,13): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(5,19): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(6,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(7,28): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. +functionDeclarationAsStatementInStrictMode.ts(8,1): error TS1344: 'A label is not allowed here. +functionDeclarationAsStatementInStrictMode.ts(8,17): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. -==== functionDeclarationAsStatementInStrictMode.ts (7 errors) ==== - // Error cases - function declarations as direct children of statements - // TypeScript assumes strict mode at all times, so these are always errors +==== functionDeclarationAsStatementInStrictMode.ts (8 errors) ==== + // Error cases - function declarations as direct children of statements in strict mode if (true) function f1() {} ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. while (true) function f2() {} ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. do function f3() {} while (false); ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. for (;;) function f4() {} ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. for (let x in {}) function f5() {} ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. for (let x of []) function f6() {} ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. label: function f7() {} + ~~~~~ +!!! error TS1344: 'A label is not allowed here. ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. // Valid cases - function declarations inside blocks if (true) { function g1() {} } diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js index 27f8116232cc1..b79687c2c7dd6 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.js @@ -1,8 +1,7 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// //// [functionDeclarationAsStatementInStrictMode.ts] -// Error cases - function declarations as direct children of statements -// TypeScript assumes strict mode at all times, so these are always errors +// Error cases - function declarations as direct children of statements in strict mode if (true) function f1() {} while (true) function f2() {} do function f3() {} while (false); @@ -30,8 +29,8 @@ function outer() { //// [functionDeclarationAsStatementInStrictMode.js] -// Error cases - function declarations as direct children of statements -// TypeScript assumes strict mode at all times, so these are always errors +"use strict"; +// Error cases - function declarations as direct children of statements in strict mode if (true) function f1() { } while (true) diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols index 728614ea75c9a..1f408d25375d2 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.symbols @@ -1,64 +1,63 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// === functionDeclarationAsStatementInStrictMode.ts === -// Error cases - function declarations as direct children of statements -// TypeScript assumes strict mode at all times, so these are always errors +// Error cases - function declarations as direct children of statements in strict mode if (true) function f1() {} ->f1 : Symbol(f1, Decl(functionDeclarationAsStatementInStrictMode.ts, 2, 9)) +>f1 : Symbol(f1, Decl(functionDeclarationAsStatementInStrictMode.ts, 1, 9)) while (true) function f2() {} ->f2 : Symbol(f2, Decl(functionDeclarationAsStatementInStrictMode.ts, 3, 12)) +>f2 : Symbol(f2, Decl(functionDeclarationAsStatementInStrictMode.ts, 2, 12)) do function f3() {} while (false); ->f3 : Symbol(f3, Decl(functionDeclarationAsStatementInStrictMode.ts, 4, 2)) +>f3 : Symbol(f3, Decl(functionDeclarationAsStatementInStrictMode.ts, 3, 2)) for (;;) function f4() {} ->f4 : Symbol(f4, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 8)) +>f4 : Symbol(f4, Decl(functionDeclarationAsStatementInStrictMode.ts, 4, 8)) for (let x in {}) function f5() {} ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 8)) ->f5 : Symbol(f5, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 17)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 8)) +>f5 : Symbol(f5, Decl(functionDeclarationAsStatementInStrictMode.ts, 5, 17)) for (let x of []) function f6() {} ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 8)) ->f6 : Symbol(f6, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 17)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 8)) +>f6 : Symbol(f6, Decl(functionDeclarationAsStatementInStrictMode.ts, 6, 17)) label: function f7() {} ->f7 : Symbol(f7, Decl(functionDeclarationAsStatementInStrictMode.ts, 8, 6)) +>f7 : Symbol(f7, Decl(functionDeclarationAsStatementInStrictMode.ts, 7, 6)) // Valid cases - function declarations inside blocks if (true) { function g1() {} } ->g1 : Symbol(g1, Decl(functionDeclarationAsStatementInStrictMode.ts, 11, 11)) +>g1 : Symbol(g1, Decl(functionDeclarationAsStatementInStrictMode.ts, 10, 11)) while (true) { function g2() {} } ->g2 : Symbol(g2, Decl(functionDeclarationAsStatementInStrictMode.ts, 12, 14)) +>g2 : Symbol(g2, Decl(functionDeclarationAsStatementInStrictMode.ts, 11, 14)) do { function g3() {} } while (false); ->g3 : Symbol(g3, Decl(functionDeclarationAsStatementInStrictMode.ts, 13, 4)) +>g3 : Symbol(g3, Decl(functionDeclarationAsStatementInStrictMode.ts, 12, 4)) for (;;) { function g4() {} } ->g4 : Symbol(g4, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 10)) +>g4 : Symbol(g4, Decl(functionDeclarationAsStatementInStrictMode.ts, 13, 10)) for (let x in {}) { function g5() {} } ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 8)) ->g5 : Symbol(g5, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 19)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 8)) +>g5 : Symbol(g5, Decl(functionDeclarationAsStatementInStrictMode.ts, 14, 19)) for (let x of []) { function g6() {} } ->x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 8)) ->g6 : Symbol(g6, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 19)) +>x : Symbol(x, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 8)) +>g6 : Symbol(g6, Decl(functionDeclarationAsStatementInStrictMode.ts, 15, 19)) label: { function g7() {} } ->g7 : Symbol(g7, Decl(functionDeclarationAsStatementInStrictMode.ts, 17, 8)) +>g7 : Symbol(g7, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 8)) // Valid - top level function topLevel() {} ->topLevel : Symbol(topLevel, Decl(functionDeclarationAsStatementInStrictMode.ts, 17, 27)) +>topLevel : Symbol(topLevel, Decl(functionDeclarationAsStatementInStrictMode.ts, 16, 27)) // Valid - inside function body function outer() { ->outer : Symbol(outer, Decl(functionDeclarationAsStatementInStrictMode.ts, 20, 22)) +>outer : Symbol(outer, Decl(functionDeclarationAsStatementInStrictMode.ts, 19, 22)) function inner() {} ->inner : Symbol(inner, Decl(functionDeclarationAsStatementInStrictMode.ts, 23, 18)) +>inner : Symbol(inner, Decl(functionDeclarationAsStatementInStrictMode.ts, 22, 18)) } diff --git a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types index 1c514f29a26e8..c5cbe73becb95 100644 --- a/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types +++ b/tests/baselines/reference/functionDeclarationAsStatementInStrictMode.types @@ -1,8 +1,7 @@ //// [tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts] //// === functionDeclarationAsStatementInStrictMode.ts === -// Error cases - function declarations as direct children of statements -// TypeScript assumes strict mode at all times, so these are always errors +// Error cases - function declarations as direct children of statements in strict mode if (true) function f1() {} >true : true > : ^^^^ @@ -34,10 +33,10 @@ for (let x in {}) function f5() {} > : ^^^^^^^^^^ for (let x of []) function f6() {} ->x : any -> : ^^^ ->[] : undefined[] -> : ^^^^^^^^^^^ +>x : never +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ >f6 : () => void > : ^^^^^^^^^^ @@ -79,10 +78,10 @@ for (let x in {}) { function g5() {} } > : ^^^^^^^^^^ for (let x of []) { function g6() {} } ->x : any -> : ^^^ ->[] : undefined[] -> : ^^^^^^^^^^^ +>x : never +> : ^^^^^ +>[] : never[] +> : ^^^^^^^ >g6 : () => void > : ^^^^^^^^^^ diff --git a/tests/baselines/reference/labeledStatementWithLabel.errors.txt b/tests/baselines/reference/labeledStatementWithLabel.errors.txt index ed923469b9434..9ec3413158f35 100644 --- a/tests/baselines/reference/labeledStatementWithLabel.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel.errors.txt @@ -1,20 +1,11 @@ -labeledStatementWithLabel.ts(1,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -labeledStatementWithLabel.ts(2,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -labeledStatementWithLabel.ts(3,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel.ts(11,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. labeledStatementWithLabel.ts(12,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. -==== labeledStatementWithLabel.ts (5 errors) ==== +==== labeledStatementWithLabel.ts (2 errors) ==== label: function fn() { } - ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function* gen() { } - ~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: async function gen1() { } - ~~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: enum E {} label: interface I {} label: class C { } diff --git a/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt b/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt index 67591b42c72bb..7b0207d9a76b7 100644 --- a/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel_es2015.errors.txt @@ -1,20 +1,11 @@ -labeledStatementWithLabel_es2015.ts(1,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -labeledStatementWithLabel_es2015.ts(2,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. -labeledStatementWithLabel_es2015.ts(3,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. labeledStatementWithLabel_es2015.ts(11,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. labeledStatementWithLabel_es2015.ts(12,8): error TS1235: A namespace declaration is only allowed at the top level of a namespace or module. -==== labeledStatementWithLabel_es2015.ts (5 errors) ==== +==== labeledStatementWithLabel_es2015.ts (2 errors) ==== label: function fn() { } - ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: function* gen() { } - ~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: async function gen1() { } - ~~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. label: enum E {} label: interface I {} label: class C { } diff --git a/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt b/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt index 86564f70d1592..be2b820a17341 100644 --- a/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt +++ b/tests/baselines/reference/labeledStatementWithLabel_strict.errors.txt @@ -1,9 +1,9 @@ labeledStatementWithLabel_strict.ts(2,1): error TS1344: 'A label is not allowed here. -labeledStatementWithLabel_strict.ts(2,17): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel_strict.ts(2,17): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. labeledStatementWithLabel_strict.ts(3,1): error TS1344: 'A label is not allowed here. -labeledStatementWithLabel_strict.ts(3,18): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel_strict.ts(3,18): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. labeledStatementWithLabel_strict.ts(4,1): error TS1344: 'A label is not allowed here. -labeledStatementWithLabel_strict.ts(4,23): error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +labeledStatementWithLabel_strict.ts(4,23): error TS1256: In strict mode code, functions can only be declared at top level or inside a block. labeledStatementWithLabel_strict.ts(5,1): error TS1344: 'A label is not allowed here. labeledStatementWithLabel_strict.ts(6,1): error TS1344: 'A label is not allowed here. labeledStatementWithLabel_strict.ts(7,1): error TS1344: 'A label is not allowed here. @@ -23,17 +23,17 @@ labeledStatementWithLabel_strict.ts(14,1): error TS1344: 'A label is not allowed ~~~~~ !!! error TS1344: 'A label is not allowed here. ~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. label: function* gen() { } ~~~~~ !!! error TS1344: 'A label is not allowed here. ~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. label: async function gen1() { } ~~~~~ !!! error TS1344: 'A label is not allowed here. ~~~~ -!!! error TS1256: Function declarations are not allowed inside statements. Use a block statement to wrap the function declaration. +!!! error TS1256: In strict mode code, functions can only be declared at top level or inside a block. label: enum E {} ~~~~~ !!! error TS1344: 'A label is not allowed here. diff --git a/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts index c1e410fcf820d..83f8eb951e42d 100644 --- a/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts +++ b/tests/cases/compiler/functionDeclarationAsStatementInStrictMode.ts @@ -1,7 +1,7 @@ +// @strict: true // @target: ES2020 -// Error cases - function declarations as direct children of statements -// TypeScript assumes strict mode at all times, so these are always errors +// Error cases - function declarations as direct children of statements in strict mode if (true) function f1() {} while (true) function f2() {} do function f3() {} while (false);