From cf89f5cf589213510ab9b30f67050592118b60be Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 13 Oct 2014 20:54:26 -0700 Subject: [PATCH] Add binder support for block scoped variable declarations --- src/compiler/binder.ts | 112 +++++-- src/compiler/types.ts | 12 +- .../constDeclarations-errors.errors.txt | 11 +- .../constDeclarations-scopes.errors.txt | 153 +++++++++ .../reference/constDeclarations-scopes.js | 276 +++++++++++++++++ ...tDeclarations-scopes-duplicates.errors.txt | 152 +++++++++ .../letDeclarations-scopes-duplicates.js | 140 +++++++++ .../letDeclarations-scopes.errors.txt | 161 ++++++++++ .../reference/letDeclarations-scopes.js | 290 ++++++++++++++++++ .../letDeclarations-scopes2.errors.txt | 42 +++ .../reference/letDeclarations-scopes2.js | 49 +++ .../compiler/constDeclarations-scopes.ts | 148 +++++++++ .../letDeclarations-scopes-duplicates.ts | 77 +++++ .../cases/compiler/letDeclarations-scopes.ts | 156 ++++++++++ .../cases/compiler/letDeclarations-scopes2.ts | 27 ++ 15 files changed, 1766 insertions(+), 40 deletions(-) create mode 100644 tests/baselines/reference/constDeclarations-scopes.errors.txt create mode 100644 tests/baselines/reference/constDeclarations-scopes.js create mode 100644 tests/baselines/reference/letDeclarations-scopes-duplicates.errors.txt create mode 100644 tests/baselines/reference/letDeclarations-scopes-duplicates.js create mode 100644 tests/baselines/reference/letDeclarations-scopes.errors.txt create mode 100644 tests/baselines/reference/letDeclarations-scopes.js create mode 100644 tests/baselines/reference/letDeclarations-scopes2.errors.txt create mode 100644 tests/baselines/reference/letDeclarations-scopes2.js create mode 100644 tests/cases/compiler/constDeclarations-scopes.ts create mode 100644 tests/cases/compiler/letDeclarations-scopes-duplicates.ts create mode 100644 tests/cases/compiler/letDeclarations-scopes.ts create mode 100644 tests/cases/compiler/letDeclarations-scopes2.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c9f9d6bf6e3..0760f33ce67 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -31,13 +31,14 @@ module ts { var parent: Node; var container: Declaration; + var blockScopeContainer: Node; var lastContainer: Declaration; var symbolCount = 0; var Symbol = objectAllocator.getSymbolConstructor(); if (!file.locals) { file.locals = {}; - container = file; + container = blockScopeContainer = file; bind(file); file.symbolCount = symbolCount; } @@ -167,12 +168,13 @@ module ts { // All container nodes are kept on a linked list in declaration order. This list is used by the getLocalNameOfContainer function // in the type checker to validate that the local name used for a container is unique. - function bindChildren(node: Declaration, symbolKind: SymbolFlags) { + function bindChildren(node: Declaration, symbolKind: SymbolFlags, isBlockScopeContainer: boolean) { if (symbolKind & SymbolFlags.HasLocals) { node.locals = {}; } var saveParent = parent; var saveContainer = container; + var savedBlockScopeContainer = blockScopeContainer; parent = node; if (symbolKind & SymbolFlags.IsContainer) { container = node; @@ -184,12 +186,16 @@ module ts { lastContainer = container; } } + if (isBlockScopeContainer) { + blockScopeContainer = node; + } forEachChild(node, bind); container = saveContainer; parent = saveParent; + blockScopeContainer = savedBlockScopeContainer; } - function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) { + function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) { switch (container.kind) { case SyntaxKind.ModuleDeclaration: declareModuleMember(node, symbolKind, symbolExcludes); @@ -225,126 +231,168 @@ module ts { declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); break; } - bindChildren(node, symbolKind); + bindChildren(node, symbolKind, isBlockScopeContainer); } function bindConstructorDeclaration(node: ConstructorDeclaration) { - bindDeclaration(node, SymbolFlags.Constructor, 0); + bindDeclaration(node, SymbolFlags.Constructor, 0, /*isBlockScopeContainer*/ true); forEach(node.parameters, p => { if (p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) { - bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); } }); } function bindModuleDeclaration(node: ModuleDeclaration) { if (node.name.kind === SyntaxKind.StringLiteral) { - bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); + bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true); } else if (isInstantiated(node)) { - bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); + bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true); } else { - bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes); + bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true); } } - function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string) { + function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) { var symbol = createSymbol(symbolKind, name); addDeclarationToSymbol(symbol, node, symbolKind); - bindChildren(node, symbolKind); + bindChildren(node, symbolKind, isBlockScopeContainer); } function bindCatchVariableDeclaration(node: CatchBlock) { var symbol = createSymbol(SymbolFlags.Variable, node.variable.text || "__missing"); addDeclarationToSymbol(symbol, node, SymbolFlags.Variable); var saveParent = parent; - parent = node; + var savedBlockScopeContainer = blockScopeContainer; + parent = blockScopeContainer = node; forEachChild(node, bind); parent = saveParent; + blockScopeContainer = savedBlockScopeContainer; + } + + function bindBlockScopedVariableDeclaration(node: Declaration) { + var symbolKind = SymbolFlags.Variable | SymbolFlags.BlockScoped; + switch (blockScopeContainer.kind) { + case SyntaxKind.ModuleDeclaration: + declareModuleMember(node, symbolKind, SymbolFlags.BlockScopedExcludes); + break; + case SyntaxKind.SourceFile: + if (isExternalModule(container)) { + declareModuleMember(node, symbolKind, SymbolFlags.BlockScopedExcludes); + break; + } + default: + if (!blockScopeContainer.locals) { + blockScopeContainer.locals = {}; + } + declareSymbol(blockScopeContainer.locals, undefined, node, symbolKind, SymbolFlags.BlockScopedExcludes); + } + + bindChildren(node, symbolKind, /*isBlockScopeContainer*/ false); } function bind(node: Node) { + var isBlockScopeContainer: boolean; node.parent = parent; switch (node.kind) { case SyntaxKind.TypeParameter: - bindDeclaration(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + bindDeclaration(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.Parameter: - bindDeclaration(node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes); + bindDeclaration(node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.VariableDeclaration: - bindDeclaration(node, SymbolFlags.Variable, SymbolFlags.VariableExcludes); + if (node.flags & NodeFlags.BlockScoped) { + bindBlockScopedVariableDeclaration(node); + } + else { + bindDeclaration(node, SymbolFlags.Variable, SymbolFlags.VariableExcludes, /*isBlockScopeContainer*/ false); + } break; case SyntaxKind.Property: case SyntaxKind.PropertyAssignment: - bindDeclaration(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + bindDeclaration(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.EnumMember: - bindDeclaration(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); + bindDeclaration(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.CallSignature: - bindDeclaration(node, SymbolFlags.CallSignature, 0); + bindDeclaration(node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false); break; case SyntaxKind.Method: - bindDeclaration(node, SymbolFlags.Method, SymbolFlags.MethodExcludes); + bindDeclaration(node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.ConstructSignature: - bindDeclaration(node, SymbolFlags.ConstructSignature, 0); + bindDeclaration(node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true); break; case SyntaxKind.IndexSignature: - bindDeclaration(node, SymbolFlags.IndexSignature, 0); + bindDeclaration(node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false); break; case SyntaxKind.FunctionDeclaration: - bindDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes); + bindDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.Constructor: bindConstructorDeclaration(node); break; case SyntaxKind.GetAccessor: - bindDeclaration(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes); + bindDeclaration(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.SetAccessor: - bindDeclaration(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes); + bindDeclaration(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.TypeLiteral: - bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type"); + bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false); break; case SyntaxKind.ObjectLiteral: - bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object"); + bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object", /*isBlockScopeContainer*/ false); break; case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - bindAnonymousDeclaration(node, SymbolFlags.Function, "__function"); + bindAnonymousDeclaration(node, SymbolFlags.Function, "__function", /*isBlockScopeContainer*/ true); break; case SyntaxKind.CatchBlock: bindCatchVariableDeclaration(node); break; case SyntaxKind.ClassDeclaration: - bindDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); + bindDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.InterfaceDeclaration: - bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); + bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.EnumDeclaration: - bindDeclaration(node, SymbolFlags.Enum, SymbolFlags.EnumExcludes); + bindDeclaration(node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.ModuleDeclaration: bindModuleDeclaration(node); break; case SyntaxKind.ImportDeclaration: - bindDeclaration(node, SymbolFlags.Import, SymbolFlags.ImportExcludes); + bindDeclaration(node, SymbolFlags.Import, SymbolFlags.ImportExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.SourceFile: if (isExternalModule(node)) { - bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((node).filename) + '"'); + bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((node).filename) + '"', /*isBlockScopeContainer*/ true); break; } + + case SyntaxKind.Block: + case SyntaxKind.TryBlock: + case SyntaxKind.CatchBlock: + case SyntaxKind.FinallyBlock: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.SwitchStatement: + isBlockScopeContainer = true; + default: var saveParent = parent; + var savedBlockScopeContainer = blockScopeContainer; parent = node; + if (isBlockScopeContainer) blockScopeContainer = node; forEachChild(node, bind); parent = saveParent; + blockScopeContainer = savedBlockScopeContainer; } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4218d4f4011..09cd613e8f3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -245,11 +245,12 @@ module ts { MultiLine = 0x00000100, // Multi-line array or object literal Synthetic = 0x00000200, // Synthetic node (for full fidelity) DeclarationFile = 0x00000400, // Node is a .d.ts file - Let = 0x00000800, - Const = 0x00001000, + Let = 0x00000800, // Variable declaration + Const = 0x00001000, // Variable declaration Modifier = Export | Ambient | Public | Private | Protected | Static, - AccessibilityModifier = Public | Private | Protected + AccessibilityModifier = Public | Private | Protected, + BlockScoped = Let | Const } export interface Node extends TextRange { @@ -768,6 +769,8 @@ module ts { Undefined = 0x08000000, // Symbol for the undefined + BlockScoped = 0x10000000, + Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter, Namespace = ValueModule | NamespaceModule, @@ -776,7 +779,8 @@ module ts { Signature = CallSignature | ConstructSignature | IndexSignature, ParameterExcludes = Value, - VariableExcludes = Value & ~Variable, + VariableExcludes = (Value | BlockScoped) & ~Variable, + BlockScopedExcludes = Value, PropertyExcludes = Value, EnumMemberExcludes = Value, FunctionExcludes = Value & ~(Function | ValueModule), diff --git a/tests/baselines/reference/constDeclarations-errors.errors.txt b/tests/baselines/reference/constDeclarations-errors.errors.txt index 79d56ade878..9a922ac93a9 100644 --- a/tests/baselines/reference/constDeclarations-errors.errors.txt +++ b/tests/baselines/reference/constDeclarations-errors.errors.txt @@ -13,10 +13,11 @@ tests/cases/compiler/constDeclarations-errors.ts(8,18): error TS1128: Declaratio tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1109: Expression expected. tests/cases/compiler/constDeclarations-errors.ts(10,5): error TS1156: const must be declared inside a block. tests/cases/compiler/constDeclarations-errors.ts(10,28): error TS1005: ';' expected. -tests/cases/compiler/constDeclarations-errors.ts(10,11): error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'. +tests/cases/compiler/constDeclarations-errors.ts(10,18): error TS2304: Cannot find name 'c'. +tests/cases/compiler/constDeclarations-errors.ts(10,25): error TS2304: Cannot find name 'c'. -==== tests/cases/compiler/constDeclarations-errors.ts (16 errors) ==== +==== tests/cases/compiler/constDeclarations-errors.ts (17 errors) ==== // error, missing intialicer const c1; @@ -57,6 +58,8 @@ tests/cases/compiler/constDeclarations-errors.ts(10,11): error TS2403: Subsequen !!! error TS1156: const must be declared inside a block. ~ !!! error TS1005: ';' expected. - ~ -!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'c' must be of type 'any', but here has type 'number'. + ~ +!!! error TS2304: Cannot find name 'c'. + ~ +!!! error TS2304: Cannot find name 'c'. \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-scopes.errors.txt b/tests/baselines/reference/constDeclarations-scopes.errors.txt new file mode 100644 index 00000000000..138acd9b16d --- /dev/null +++ b/tests/baselines/reference/constDeclarations-scopes.errors.txt @@ -0,0 +1,153 @@ +tests/cases/compiler/constDeclarations-scopes.ts(28,7): error TS2410: All symbols within a 'with' block will be resolved to 'any'. + + +==== tests/cases/compiler/constDeclarations-scopes.ts (1 errors) ==== + + // global + const c = "string"; + + var n: number; + + // Control flow statements with blocks + if (true) { + const c = 0; + n = c; + } + else { + const c = 0; + n = c; + } + + while (true) { + const c = 0; + n = c; + } + + do { + const c = 0; + n = c; + } while (true); + + var obj; + with (obj) { + ~~~ +!!! error TS2410: All symbols within a 'with' block will be resolved to 'any'. + const c = 0; + n = c; + } + + for (var i = 0; i < 10; i++) { + const c = 0; + n = c; + } + + for (var i2 in {}) { + const c = 0; + n = c; + } + + if (true) { + label: const c = 0; + n = c; + } + + while (false) { + label2: label3: label4: const c = 0; + n = c; + } + + // Try/catch/finally + try { + const c = 0; + n = c; + } + catch (e) { + const c = 0; + n = c; + } + finally { + const c = 0; + n = c; + } + + // Switch + switch (0) { + case 0: + const c = 0; + n = c; + break; + } + + // blocks + { + const c = 0; + n = c; + { + const c = false; + var b: boolean = c; + } + } + + // functions + + function F() { + const c = 0; + n = c; + } + + var F2 = () => { + const c = 0; + n = c; + }; + + var F3 = function () { + const c = 0; + n = c; + }; + + // modules + module m { + const c = 0; + n = c; + + { + const c = false; + var b2: boolean = c; + } + } + + // methods + class C { + constructor() { + const c = 0; + n = c; + } + + method() { + const c = 0; + n = c; + } + + get v() { + const c = 0; + n = c; + return n; + } + + set v(value) { + const c = 0; + n = c; + } + } + + // object literals + var o = { + f() { + const c = 0; + n = c; + }, + f2: () => { + const c = 0; + n = c; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-scopes.js b/tests/baselines/reference/constDeclarations-scopes.js new file mode 100644 index 00000000000..800dd856422 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-scopes.js @@ -0,0 +1,276 @@ +//// [constDeclarations-scopes.ts] + +// global +const c = "string"; + +var n: number; + +// Control flow statements with blocks +if (true) { + const c = 0; + n = c; +} +else { + const c = 0; + n = c; +} + +while (true) { + const c = 0; + n = c; +} + +do { + const c = 0; + n = c; +} while (true); + +var obj; +with (obj) { + const c = 0; + n = c; +} + +for (var i = 0; i < 10; i++) { + const c = 0; + n = c; +} + +for (var i2 in {}) { + const c = 0; + n = c; +} + +if (true) { + label: const c = 0; + n = c; +} + +while (false) { + label2: label3: label4: const c = 0; + n = c; +} + +// Try/catch/finally +try { + const c = 0; + n = c; +} +catch (e) { + const c = 0; + n = c; +} +finally { + const c = 0; + n = c; +} + +// Switch +switch (0) { + case 0: + const c = 0; + n = c; + break; +} + +// blocks +{ + const c = 0; + n = c; + { + const c = false; + var b: boolean = c; + } +} + +// functions + +function F() { + const c = 0; + n = c; +} + +var F2 = () => { + const c = 0; + n = c; +}; + +var F3 = function () { + const c = 0; + n = c; +}; + +// modules +module m { + const c = 0; + n = c; + + { + const c = false; + var b2: boolean = c; + } +} + +// methods +class C { + constructor() { + const c = 0; + n = c; + } + + method() { + const c = 0; + n = c; + } + + get v() { + const c = 0; + n = c; + return n; + } + + set v(value) { + const c = 0; + n = c; + } +} + +// object literals +var o = { + f() { + const c = 0; + n = c; + }, + f2: () => { + const c = 0; + n = c; + } +} + +//// [constDeclarations-scopes.js] +// global +const c = "string"; +var n; +// Control flow statements with blocks +if (true) { + const c = 0; + n = c; +} +else { + const c = 0; + n = c; +} +while (true) { + const c = 0; + n = c; +} +do { + const c = 0; + n = c; +} while (true); +var obj; +with (obj) { + const c = 0; + n = c; +} +for (var i = 0; i < 10; i++) { + const c = 0; + n = c; +} +for (var i2 in {}) { + const c = 0; + n = c; +} +if (true) { + label: const c = 0; + n = c; +} +while (false) { + label2: label3: label4: const c = 0; + n = c; +} +try { + const c = 0; + n = c; +} +catch (e) { + const c = 0; + n = c; +} +finally { + const c = 0; + n = c; +} +switch (0) { + case 0: + const c = 0; + n = c; + break; +} +{ + const c = 0; + n = c; + { + const c = false; + var b = c; + } +} +// functions +function F() { + const c = 0; + n = c; +} +var F2 = function () { + const c = 0; + n = c; +}; +var F3 = function () { + const c = 0; + n = c; +}; +// modules +var m; +(function (m) { + const c = 0; + n = c; + { + const c = false; + var b2 = c; + } +})(m || (m = {})); +// methods +var C = (function () { + function C() { + const c = 0; + n = c; + } + C.prototype.method = function () { + const c = 0; + n = c; + }; + Object.defineProperty(C.prototype, "v", { + get: function () { + const c = 0; + n = c; + return n; + }, + set: function (value) { + const c = 0; + n = c; + }, + enumerable: true, + configurable: true + }); + return C; +})(); +// object literals +var o = { + f: function () { + const c = 0; + n = c; + }, + f2: function () { + const c = 0; + n = c; + } +}; diff --git a/tests/baselines/reference/letDeclarations-scopes-duplicates.errors.txt b/tests/baselines/reference/letDeclarations-scopes-duplicates.errors.txt new file mode 100644 index 00000000000..41d2813f7c4 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes-duplicates.errors.txt @@ -0,0 +1,152 @@ +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(3,5): error TS2300: Duplicate identifier 'var1'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(4,5): error TS2300: Duplicate identifier 'var1'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(6,5): error TS2300: Duplicate identifier 'var2'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(7,7): error TS2300: Duplicate identifier 'var2'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(9,7): error TS2300: Duplicate identifier 'var3'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(10,5): error TS2300: Duplicate identifier 'var3'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(12,7): error TS2300: Duplicate identifier 'var4'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(13,7): error TS2300: Duplicate identifier 'var4'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(15,5): error TS2300: Duplicate identifier 'var5'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(16,5): error TS2300: Duplicate identifier 'var5'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(18,5): error TS2300: Duplicate identifier 'var6'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(19,5): error TS2300: Duplicate identifier 'var6'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(22,9): error TS2300: Duplicate identifier 'var7'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(23,9): error TS2300: Duplicate identifier 'var7'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(25,13): error TS2300: Duplicate identifier 'var8'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(26,15): error TS2300: Duplicate identifier 'var8'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(32,13): error TS2300: Duplicate identifier 'var9'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(33,13): error TS2300: Duplicate identifier 'var9'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(37,11): error TS2300: Duplicate identifier 'var10'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(38,11): error TS2300: Duplicate identifier 'var10'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(41,9): error TS2300: Duplicate identifier 'var11'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(42,9): error TS2300: Duplicate identifier 'var11'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(46,9): error TS2300: Duplicate identifier 'var12'. +tests/cases/compiler/letDeclarations-scopes-duplicates.ts(47,9): error TS2300: Duplicate identifier 'var12'. + + +==== tests/cases/compiler/letDeclarations-scopes-duplicates.ts (24 errors) ==== + + // Errors: redeclaration + let var1 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var1'. + let var1 = 0; // error + ~~~~ +!!! error TS2300: Duplicate identifier 'var1'. + + let var2 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var2'. + const var2 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var2'. + + const var3 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var3'. + let var3 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var3'. + + const var4 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var4'. + const var4 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var4'. + + var var5 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var5'. + let var5 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var5'. + + let var6 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var6'. + var var6 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var6'. + + { + let var7 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var7'. + let var7 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var7'. + { + let var8 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var8'. + const var8 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var8'. + } + } + + switch (0) { + default: + let var9 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var9'. + let var9 = 0; + ~~~~ +!!! error TS2300: Duplicate identifier 'var9'. + } + + try { + const var10 = 0; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var10'. + const var10 = 0; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var10'. + } + catch (e) { + let var11 = 0; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var11'. + let var11 = 0; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var11'. + } + + function F1() { + let var12; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var12'. + let var12; + ~~~~~ +!!! error TS2300: Duplicate identifier 'var12'. + } + + // OK + var var20 = 0; + + var var20 = 0 + { + let var20 = 0; + { + let var20 = 0; + } + } + + switch (0) { + default: + let var20 = 0; + } + + try { + let var20 = 0; + } + catch (e) { + let var20 = 0; + } + + function F() { + let var20; + } + + \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-scopes-duplicates.js b/tests/baselines/reference/letDeclarations-scopes-duplicates.js new file mode 100644 index 00000000000..c7d2ef9863a --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes-duplicates.js @@ -0,0 +1,140 @@ +//// [letDeclarations-scopes-duplicates.ts] + +// Errors: redeclaration +let var1 = 0; +let var1 = 0; // error + +let var2 = 0; +const var2 = 0; + +const var3 = 0; +let var3 = 0; + +const var4 = 0; +const var4 = 0; + +var var5 = 0; +let var5 = 0; + +let var6 = 0; +var var6 = 0; + +{ + let var7 = 0; + let var7 = 0; + { + let var8 = 0; + const var8 = 0; + } +} + +switch (0) { + default: + let var9 = 0; + let var9 = 0; +} + +try { + const var10 = 0; + const var10 = 0; +} +catch (e) { + let var11 = 0; + let var11 = 0; +} + +function F1() { + let var12; + let var12; +} + +// OK +var var20 = 0; + +var var20 = 0 +{ + let var20 = 0; + { + let var20 = 0; + } +} + +switch (0) { + default: + let var20 = 0; +} + +try { + let var20 = 0; +} +catch (e) { + let var20 = 0; +} + +function F() { + let var20; +} + + + +//// [letDeclarations-scopes-duplicates.js] +// Errors: redeclaration +let var1 = 0; +let var1 = 0; // error +let var2 = 0; +const var2 = 0; +const var3 = 0; +let var3 = 0; +const var4 = 0; +const var4 = 0; +var var5 = 0; +let var5 = 0; +let var6 = 0; +var var6 = 0; +{ + let var7 = 0; + let var7 = 0; + { + let var8 = 0; + const var8 = 0; + } +} +switch (0) { + default: + let var9 = 0; + let var9 = 0; +} +try { + const var10 = 0; + const var10 = 0; +} +catch (e) { + let var11 = 0; + let var11 = 0; +} +function F1() { + let var12; + let var12; +} +// OK +var var20 = 0; +var var20 = 0; +{ + let var20 = 0; + { + let var20 = 0; + } +} +switch (0) { + default: + let var20 = 0; +} +try { + let var20 = 0; +} +catch (e) { + let var20 = 0; +} +function F() { + let var20; +} diff --git a/tests/baselines/reference/letDeclarations-scopes.errors.txt b/tests/baselines/reference/letDeclarations-scopes.errors.txt new file mode 100644 index 00000000000..df54e0fc3c4 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes.errors.txt @@ -0,0 +1,161 @@ +tests/cases/compiler/letDeclarations-scopes.ts(28,7): error TS2410: All symbols within a 'with' block will be resolved to 'any'. + + +==== tests/cases/compiler/letDeclarations-scopes.ts (1 errors) ==== + + // global + let l = "string"; + + var n: number; + + // Control flow statements with blocks + if (true) { + let l = 0; + n = l; + } + else { + let l = 0; + n = l; + } + + while (true) { + let l = 0; + n = l; + } + + do { + let l = 0; + n = l; + } while (true); + + var obj; + with (obj) { + ~~~ +!!! error TS2410: All symbols within a 'with' block will be resolved to 'any'. + let l = 0; + n = l; + } + + for (var i = 0; i < 10; i++) { + let l = 0; + n = l; + } + + for (var i2 in {}) { + let l = 0; + n = l; + } + + if (true) { + label: let l = 0; + n = l; + } + + while (false) { + label2: label3: label4: let l = 0; + n = l; + } + + for (let l = 0; n = l; l++) { + let l = true; + var b3: boolean = l; + } + + for (let l in {}) { + + } + + // Try/catch/finally + try { + let l = 0; + n = l; + } + catch (e) { + let l = 0; + n = l; + } + finally { + let l = 0; + n = l; + } + + // Switch + switch (0) { + case 0: + let l = 0; + n = l; + break; + } + + // blocks + { + let l = 0; + n = l; + { + let l = false; + var b: boolean = l; + } + } + + // functions + function F() { + let l = 0; + n = l; + } + + var F2 = () => { + let l = 0; + n = l; + }; + + var F3 = function () { + let l = 0; + n = l; + }; + + // modules + module m { + let l = 0; + n = l; + + { + let l = false; + var b2: boolean = l; + } + } + + // methods + class C { + constructor() { + let l = 0; + n = l; + } + + method() { + let l = 0; + n = l; + } + + get v() { + let l = 0; + n = l; + return n; + } + + set v(value) { + let l = 0; + n = l; + } + } + + // object literals + var o = { + f() { + let l = 0; + n = l; + }, + f2: () => { + let l = 0; + n = l; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-scopes.js b/tests/baselines/reference/letDeclarations-scopes.js new file mode 100644 index 00000000000..59d42368b6c --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes.js @@ -0,0 +1,290 @@ +//// [letDeclarations-scopes.ts] + +// global +let l = "string"; + +var n: number; + +// Control flow statements with blocks +if (true) { + let l = 0; + n = l; +} +else { + let l = 0; + n = l; +} + +while (true) { + let l = 0; + n = l; +} + +do { + let l = 0; + n = l; +} while (true); + +var obj; +with (obj) { + let l = 0; + n = l; +} + +for (var i = 0; i < 10; i++) { + let l = 0; + n = l; +} + +for (var i2 in {}) { + let l = 0; + n = l; +} + +if (true) { + label: let l = 0; + n = l; +} + +while (false) { + label2: label3: label4: let l = 0; + n = l; +} + +for (let l = 0; n = l; l++) { + let l = true; + var b3: boolean = l; +} + +for (let l in {}) { + +} + +// Try/catch/finally +try { + let l = 0; + n = l; +} +catch (e) { + let l = 0; + n = l; +} +finally { + let l = 0; + n = l; +} + +// Switch +switch (0) { + case 0: + let l = 0; + n = l; + break; +} + +// blocks +{ + let l = 0; + n = l; + { + let l = false; + var b: boolean = l; + } +} + +// functions +function F() { + let l = 0; + n = l; +} + +var F2 = () => { + let l = 0; +n = l; +}; + +var F3 = function () { + let l = 0; +n = l; +}; + +// modules +module m { + let l = 0; + n = l; + + { + let l = false; + var b2: boolean = l; + } +} + +// methods +class C { + constructor() { + let l = 0; + n = l; + } + + method() { + let l = 0; + n = l; + } + + get v() { + let l = 0; + n = l; + return n; + } + + set v(value) { + let l = 0; + n = l; + } +} + +// object literals +var o = { + f() { + let l = 0; +n = l; + }, +f2: () => { + let l = 0; + n = l; + } +} + +//// [letDeclarations-scopes.js] +// global +let l = "string"; +var n; +// Control flow statements with blocks +if (true) { + let l = 0; + n = l; +} +else { + let l = 0; + n = l; +} +while (true) { + let l = 0; + n = l; +} +do { + let l = 0; + n = l; +} while (true); +var obj; +with (obj) { + let l = 0; + n = l; +} +for (var i = 0; i < 10; i++) { + let l = 0; + n = l; +} +for (var i2 in {}) { + let l = 0; + n = l; +} +if (true) { + label: let l = 0; + n = l; +} +while (false) { + label2: label3: label4: let l = 0; + n = l; +} +for (let l = 0; n = l; l++) { + let l = true; + var b3 = l; +} +for (let l in {}) { +} +try { + let l = 0; + n = l; +} +catch (e) { + let l = 0; + n = l; +} +finally { + let l = 0; + n = l; +} +switch (0) { + case 0: + let l = 0; + n = l; + break; +} +{ + let l = 0; + n = l; + { + let l = false; + var b = l; + } +} +// functions +function F() { + let l = 0; + n = l; +} +var F2 = function () { + let l = 0; + n = l; +}; +var F3 = function () { + let l = 0; + n = l; +}; +// modules +var m; +(function (m) { + let l = 0; + n = l; + { + let l = false; + var b2 = l; + } +})(m || (m = {})); +// methods +var C = (function () { + function C() { + let l = 0; + n = l; + } + C.prototype.method = function () { + let l = 0; + n = l; + }; + Object.defineProperty(C.prototype, "v", { + get: function () { + let l = 0; + n = l; + return n; + }, + set: function (value) { + let l = 0; + n = l; + }, + enumerable: true, + configurable: true + }); + return C; +})(); +// object literals +var o = { + f: function () { + let l = 0; + n = l; + }, + f2: function () { + let l = 0; + n = l; + } +}; diff --git a/tests/baselines/reference/letDeclarations-scopes2.errors.txt b/tests/baselines/reference/letDeclarations-scopes2.errors.txt new file mode 100644 index 00000000000..a786db1104b --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes2.errors.txt @@ -0,0 +1,42 @@ +tests/cases/compiler/letDeclarations-scopes2.ts(9,5): error TS2304: Cannot find name 'local2'. +tests/cases/compiler/letDeclarations-scopes2.ts(21,5): error TS2304: Cannot find name 'local2'. +tests/cases/compiler/letDeclarations-scopes2.ts(24,1): error TS2304: Cannot find name 'local'. +tests/cases/compiler/letDeclarations-scopes2.ts(26,1): error TS2304: Cannot find name 'local2'. + + +==== tests/cases/compiler/letDeclarations-scopes2.ts (4 errors) ==== + + let global = 0; + + { + let local = 0; + + local; // OK + global; // OK + local2; // Error + ~~~~~~ +!!! error TS2304: Cannot find name 'local2'. + + { + let local2 = 0; + + local; // OK + global; // OK + local2; // OK + } + + local; // OK + global; // OK + local2; // Error + ~~~~~~ +!!! error TS2304: Cannot find name 'local2'. + } + + local; // Error + ~~~~~ +!!! error TS2304: Cannot find name 'local'. + global; // OK + local2; // Error + ~~~~~~ +!!! error TS2304: Cannot find name 'local2'. + \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-scopes2.js b/tests/baselines/reference/letDeclarations-scopes2.js new file mode 100644 index 00000000000..98d0e791832 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-scopes2.js @@ -0,0 +1,49 @@ +//// [letDeclarations-scopes2.ts] + +let global = 0; + +{ + let local = 0; + + local; // OK + global; // OK + local2; // Error + + { + let local2 = 0; + + local; // OK + global; // OK + local2; // OK + } + + local; // OK + global; // OK + local2; // Error +} + +local; // Error +global; // OK +local2; // Error + + +//// [letDeclarations-scopes2.js] +let global = 0; +{ + let local = 0; + local; // OK + global; // OK + local2; // Error + { + let local2 = 0; + local; // OK + global; // OK + local2; // OK + } + local; // OK + global; // OK + local2; // Error +} +local; // Error +global; // OK +local2; // Error diff --git a/tests/cases/compiler/constDeclarations-scopes.ts b/tests/cases/compiler/constDeclarations-scopes.ts new file mode 100644 index 00000000000..d0c1df425b6 --- /dev/null +++ b/tests/cases/compiler/constDeclarations-scopes.ts @@ -0,0 +1,148 @@ +// @target: ES6 + +// global +const c = "string"; + +var n: number; + +// Control flow statements with blocks +if (true) { + const c = 0; + n = c; +} +else { + const c = 0; + n = c; +} + +while (true) { + const c = 0; + n = c; +} + +do { + const c = 0; + n = c; +} while (true); + +var obj; +with (obj) { + const c = 0; + n = c; +} + +for (var i = 0; i < 10; i++) { + const c = 0; + n = c; +} + +for (var i2 in {}) { + const c = 0; + n = c; +} + +if (true) { + label: const c = 0; + n = c; +} + +while (false) { + label2: label3: label4: const c = 0; + n = c; +} + +// Try/catch/finally +try { + const c = 0; + n = c; +} +catch (e) { + const c = 0; + n = c; +} +finally { + const c = 0; + n = c; +} + +// Switch +switch (0) { + case 0: + const c = 0; + n = c; + break; +} + +// blocks +{ + const c = 0; + n = c; + { + const c = false; + var b: boolean = c; + } +} + +// functions + +function F() { + const c = 0; + n = c; +} + +var F2 = () => { + const c = 0; + n = c; +}; + +var F3 = function () { + const c = 0; + n = c; +}; + +// modules +module m { + const c = 0; + n = c; + + { + const c = false; + var b2: boolean = c; + } +} + +// methods +class C { + constructor() { + const c = 0; + n = c; + } + + method() { + const c = 0; + n = c; + } + + get v() { + const c = 0; + n = c; + return n; + } + + set v(value) { + const c = 0; + n = c; + } +} + +// object literals +var o = { + f() { + const c = 0; + n = c; + }, + f2: () => { + const c = 0; + n = c; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/letDeclarations-scopes-duplicates.ts b/tests/cases/compiler/letDeclarations-scopes-duplicates.ts new file mode 100644 index 00000000000..841b55af168 --- /dev/null +++ b/tests/cases/compiler/letDeclarations-scopes-duplicates.ts @@ -0,0 +1,77 @@ +// @target: ES6 + +// Errors: redeclaration +let var1 = 0; +let var1 = 0; // error + +let var2 = 0; +const var2 = 0; + +const var3 = 0; +let var3 = 0; + +const var4 = 0; +const var4 = 0; + +var var5 = 0; +let var5 = 0; + +let var6 = 0; +var var6 = 0; + +{ + let var7 = 0; + let var7 = 0; + { + let var8 = 0; + const var8 = 0; + } +} + +switch (0) { + default: + let var9 = 0; + let var9 = 0; +} + +try { + const var10 = 0; + const var10 = 0; +} +catch (e) { + let var11 = 0; + let var11 = 0; +} + +function F1() { + let var12; + let var12; +} + +// OK +var var20 = 0; + +var var20 = 0 +{ + let var20 = 0; + { + let var20 = 0; + } +} + +switch (0) { + default: + let var20 = 0; +} + +try { + let var20 = 0; +} +catch (e) { + let var20 = 0; +} + +function F() { + let var20; +} + diff --git a/tests/cases/compiler/letDeclarations-scopes.ts b/tests/cases/compiler/letDeclarations-scopes.ts new file mode 100644 index 00000000000..0393f0f295b --- /dev/null +++ b/tests/cases/compiler/letDeclarations-scopes.ts @@ -0,0 +1,156 @@ +// @target: ES6 + +// global +let l = "string"; + +var n: number; + +// Control flow statements with blocks +if (true) { + let l = 0; + n = l; +} +else { + let l = 0; + n = l; +} + +while (true) { + let l = 0; + n = l; +} + +do { + let l = 0; + n = l; +} while (true); + +var obj; +with (obj) { + let l = 0; + n = l; +} + +for (var i = 0; i < 10; i++) { + let l = 0; + n = l; +} + +for (var i2 in {}) { + let l = 0; + n = l; +} + +if (true) { + label: let l = 0; + n = l; +} + +while (false) { + label2: label3: label4: let l = 0; + n = l; +} + +for (let l = 0; n = l; l++) { + let l = true; + var b3: boolean = l; +} + +for (let l in {}) { + +} + +// Try/catch/finally +try { + let l = 0; + n = l; +} +catch (e) { + let l = 0; + n = l; +} +finally { + let l = 0; + n = l; +} + +// Switch +switch (0) { + case 0: + let l = 0; + n = l; + break; +} + +// blocks +{ + let l = 0; + n = l; + { + let l = false; + var b: boolean = l; + } +} + +// functions +function F() { + let l = 0; + n = l; +} + +var F2 = () => { + let l = 0; +n = l; +}; + +var F3 = function () { + let l = 0; +n = l; +}; + +// modules +module m { + let l = 0; + n = l; + + { + let l = false; + var b2: boolean = l; + } +} + +// methods +class C { + constructor() { + let l = 0; + n = l; + } + + method() { + let l = 0; + n = l; + } + + get v() { + let l = 0; + n = l; + return n; + } + + set v(value) { + let l = 0; + n = l; + } +} + +// object literals +var o = { + f() { + let l = 0; +n = l; + }, +f2: () => { + let l = 0; + n = l; + } +} \ No newline at end of file diff --git a/tests/cases/compiler/letDeclarations-scopes2.ts b/tests/cases/compiler/letDeclarations-scopes2.ts new file mode 100644 index 00000000000..6f1200a0cb2 --- /dev/null +++ b/tests/cases/compiler/letDeclarations-scopes2.ts @@ -0,0 +1,27 @@ +// @target: ES6 + +let global = 0; + +{ + let local = 0; + + local; // OK + global; // OK + local2; // Error + + { + let local2 = 0; + + local; // OK + global; // OK + local2; // OK + } + + local; // OK + global; // OK + local2; // Error +} + +local; // Error +global; // OK +local2; // Error