Disallow type and interface declarations in statements with blockless bodies (#60183)

This commit is contained in:
Mateusz Burzyński 2024-10-18 18:24:33 +02:00 коммит произвёл GitHub
Родитель 2e4f2c72db
Коммит c07da583af
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 364 добавлений и 3 удалений

Просмотреть файл

@ -46774,6 +46774,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function checkInterfaceDeclaration(node: InterfaceDeclaration) {
// Grammar checking
if (!checkGrammarModifiers(node)) checkGrammarInterfaceDeclaration(node);
if (!allowBlockDeclarations(node.parent)) {
grammarErrorOnNode(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, "interface");
}
checkTypeParameters(node.typeParameters);
addLazyDiagnostic(() => {
@ -46817,6 +46820,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Grammar checking
checkGrammarModifiers(node);
checkTypeNameIsReserved(node.name, Diagnostics.Type_alias_name_cannot_be_0);
if (!allowBlockDeclarations(node.parent)) {
grammarErrorOnNode(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, "type");
}
checkExportsOnMergedDeclarations(node);
checkTypeParameters(node.typeParameters);
if (node.type.kind === SyntaxKind.IntrinsicKeyword) {
@ -52051,7 +52057,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return false;
}
function allowLetAndConstDeclarations(parent: Node): boolean {
function allowBlockDeclarations(parent: Node): boolean {
switch (parent.kind) {
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
@ -52062,14 +52068,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.ForOfStatement:
return false;
case SyntaxKind.LabeledStatement:
return allowLetAndConstDeclarations(parent.parent);
return allowBlockDeclarations(parent.parent);
}
return true;
}
function checkGrammarForDisallowedBlockScopedVariableStatement(node: VariableStatement) {
if (!allowLetAndConstDeclarations(node.parent)) {
if (!allowBlockDeclarations(node.parent)) {
const blockScopeKind = getCombinedNodeFlagsCached(node.declarationList) & NodeFlags.BlockScoped;
if (blockScopeKind) {
const keyword = blockScopeKind === NodeFlags.Let ? "let" :

Просмотреть файл

@ -0,0 +1,30 @@
typeAliasDeclarationEmit3.ts(3,14): error TS1156: 'type' declarations can only be declared inside a block.
typeAliasDeclarationEmit3.ts(9,14): error TS1156: 'type' declarations can only be declared inside a block.
typeAliasDeclarationEmit3.ts(15,14): error TS1156: 'type' declarations can only be declared inside a block.
==== typeAliasDeclarationEmit3.ts (3 errors) ====
function f1(): void {
for (let i = 0; i < 1; i++)
type foo = [];
~~~
!!! error TS1156: 'type' declarations can only be declared inside a block.
console.log('f1');
}
function f2(): void {
while (true)
type foo = [];
~~~
!!! error TS1156: 'type' declarations can only be declared inside a block.
console.log('f2');
}
function f3(): void {
if (true)
type foo = [];
~~~
!!! error TS1156: 'type' declarations can only be declared inside a block.
console.log('f3');
}

Просмотреть файл

@ -0,0 +1,46 @@
typeInterfaceDeclarationsInBlockStatements1.ts(4,18): error TS1156: 'type' declarations can only be declared inside a block.
typeInterfaceDeclarationsInBlockStatements1.ts(12,21): error TS2304: Cannot find name 's'.
typeInterfaceDeclarationsInBlockStatements1.ts(17,15): error TS1156: 'interface' declarations can only be declared inside a block.
typeInterfaceDeclarationsInBlockStatements1.ts(29,21): error TS2304: Cannot find name 's'.
==== typeInterfaceDeclarationsInBlockStatements1.ts (4 errors) ====
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
if (true) type s = string;
~
!!! error TS1156: 'type' declarations can only be declared inside a block.
console.log("" as s);
}
function f2() {
if (true) {
type s = string;
}
console.log("" as s);
~
!!! error TS2304: Cannot find name 's'.
}
function f3() {
if (true)
interface s {
~
!!! error TS1156: 'interface' declarations can only be declared inside a block.
length: number;
}
console.log("" as s);
}
function f4() {
if (true) {
interface s {
length: number;
}
}
console.log("" as s);
~
!!! error TS2304: Cannot find name 's'.
}

Просмотреть файл

@ -0,0 +1,65 @@
//// [tests/cases/compiler/typeInterfaceDeclarationsInBlockStatements1.ts] ////
//// [typeInterfaceDeclarationsInBlockStatements1.ts]
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
if (true) type s = string;
console.log("" as s);
}
function f2() {
if (true) {
type s = string;
}
console.log("" as s);
}
function f3() {
if (true)
interface s {
length: number;
}
console.log("" as s);
}
function f4() {
if (true) {
interface s {
length: number;
}
}
console.log("" as s);
}
//// [typeInterfaceDeclarationsInBlockStatements1.js]
"use strict";
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
if (true)
;
console.log("");
}
function f2() {
if (true) {
}
console.log("");
}
function f3() {
if (true)
;
console.log("");
}
function f4() {
if (true) {
}
console.log("");
}
//// [typeInterfaceDeclarationsInBlockStatements1.d.ts]
declare function f1(): void;
declare function f2(): void;
declare function f3(): void;
declare function f4(): void;

Просмотреть файл

@ -0,0 +1,67 @@
//// [tests/cases/compiler/typeInterfaceDeclarationsInBlockStatements1.ts] ////
=== typeInterfaceDeclarationsInBlockStatements1.ts ===
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
>f1 : Symbol(f1, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 0, 0))
if (true) type s = string;
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 3, 11))
console.log("" as s);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 3, 11))
}
function f2() {
>f2 : Symbol(f2, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 5, 1))
if (true) {
type s = string;
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 8, 13))
}
console.log("" as s);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>s : Symbol(s)
}
function f3() {
>f3 : Symbol(f3, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 12, 1))
if (true)
interface s {
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 15, 11))
length: number;
>length : Symbol(s.length, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 16, 17))
}
console.log("" as s);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 15, 11))
}
function f4() {
>f4 : Symbol(f4, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 20, 1))
if (true) {
interface s {
>s : Symbol(s, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 23, 13))
length: number;
>length : Symbol(s.length, Decl(typeInterfaceDeclarationsInBlockStatements1.ts, 24, 17))
}
}
console.log("" as s);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>s : Symbol(s)
}

Просмотреть файл

@ -0,0 +1,114 @@
//// [tests/cases/compiler/typeInterfaceDeclarationsInBlockStatements1.ts] ////
=== typeInterfaceDeclarationsInBlockStatements1.ts ===
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
>f1 : () => void
> : ^^^^^^^^^^
if (true) type s = string;
>true : true
> : ^^^^
>s : string
> : ^^^^^^
console.log("" as s);
>console.log("" as s) : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"" as s : string
> : ^^^^^^
>"" : ""
> : ^^
}
function f2() {
>f2 : () => void
> : ^^^^^^^^^^
if (true) {
>true : true
> : ^^^^
type s = string;
>s : string
> : ^^^^^^
}
console.log("" as s);
>console.log("" as s) : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"" as s : s
> : ^
>"" : ""
> : ^^
}
function f3() {
>f3 : () => void
> : ^^^^^^^^^^
if (true)
>true : true
> : ^^^^
interface s {
length: number;
>length : number
> : ^^^^^^
}
console.log("" as s);
>console.log("" as s) : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"" as s : s
> : ^
>"" : ""
> : ^^
}
function f4() {
>f4 : () => void
> : ^^^^^^^^^^
if (true) {
>true : true
> : ^^^^
interface s {
length: number;
>length : number
> : ^^^^^^
}
}
console.log("" as s);
>console.log("" as s) : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"" as s : s
> : ^
>"" : ""
> : ^^
}

Просмотреть файл

@ -0,0 +1,33 @@
// @strict: true
// @declaration: true
// https://github.com/microsoft/TypeScript/issues/60175
function f1() {
if (true) type s = string;
console.log("" as s);
}
function f2() {
if (true) {
type s = string;
}
console.log("" as s);
}
function f3() {
if (true)
interface s {
length: number;
}
console.log("" as s);
}
function f4() {
if (true) {
interface s {
length: number;
}
}
console.log("" as s);
}