Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2707,6 +2707,28 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
}
}

// 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.
function checkStrictModeFunctionDeclarationAsStatementChild(node: FunctionDeclaration) {
if (!inStrictMode) {
return;
}
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:
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));
break;
}
}

function checkStrictModePostfixUnaryExpression(node: PostfixUnaryExpression) {
// Grammar checking
// The identifier eval or arguments may not appear as the LeftHandSideExpression of an
Expand Down Expand Up @@ -3713,6 +3735,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
}

checkStrictModeFunctionName(node);
checkStrictModeFunctionDeclarationAsStatementChild(node);
if (inStrictMode) {
checkStrictModeFunctionDeclaration(node);
bindBlockScopedDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
}

Original file line number Diff line number Diff line change
@@ -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() { }
}
Original file line number Diff line number Diff line change
@@ -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))
}

Original file line number Diff line number Diff line change
@@ -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
> : ^^^^^^^^^^
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
labeledStatementWithLabel_strict.ts(2,1): error TS1344: 'A label is not allowed here.
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: 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: 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.
Expand All @@ -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: 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: 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: 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.
Expand Down
Loading