diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 201913a50b465..0e6954ad07b8e 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -126,7 +126,7 @@ module ts { var name = getDeclarationName(node); if (name !== undefined) { - var symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name)); + var symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(SymbolFlags.None, name)); if (symbol.flags & excludes) { if (node.name) { node.name.parent = node; @@ -143,11 +143,11 @@ module ts { }); file.semanticDiagnostics.push(createDiagnosticForNode(node.name, message, getDisplayName(node))); - symbol = createSymbol(0, name); + symbol = createSymbol(SymbolFlags.None, name); } } else { - symbol = createSymbol(0, "__missing"); + symbol = createSymbol(SymbolFlags.None, "__missing"); } addDeclarationToSymbol(symbol, node, includes); symbol.parent = parent; @@ -192,7 +192,7 @@ module ts { // 2. When we checkIdentifier in the checker, we set its resolved symbol to the local symbol, // but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way // when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope. - var exportKind = 0; + var exportKind = SymbolFlags.None; if (symbolKind & SymbolFlags.Value) { exportKind |= SymbolFlags.ExportValue; } @@ -384,7 +384,7 @@ module ts { case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: if (isBindingPattern((node).name)) { - bindChildren(node, 0, /*isBlockScopeContainer*/ false); + bindChildren(node, SymbolFlags.None, /*isBlockScopeContainer*/ false); } else if (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) { bindBlockScopedVariableDeclaration(node); @@ -395,7 +395,7 @@ module ts { break; case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - bindDeclaration(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); + bindDeclaration(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false); break; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: @@ -407,7 +407,7 @@ module ts { case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.IndexSignature: - bindDeclaration(node, SymbolFlags.Signature, 0, /*isBlockScopeContainer*/ false); + bindDeclaration(node, SymbolFlags.Signature, /*excludes*/ SymbolFlags.None, /*isBlockScopeContainer*/ false); break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: @@ -415,14 +415,14 @@ module ts { // as other properties in the object literal. So we use SymbolFlags.PropertyExcludes // so that it will conflict with any other object literal members with the same // name. - bindDeclaration(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : 0), + bindDeclaration(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.FunctionDeclaration: bindDeclaration(node, SymbolFlags.Function, SymbolFlags.FunctionExcludes, /*isBlockScopeContainer*/ true); break; case SyntaxKind.Constructor: - bindDeclaration(node, SymbolFlags.Constructor, /*symbolExcludes:*/ 0, /*isBlockScopeContainer:*/ true); + bindDeclaration(node, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None, /*isBlockScopeContainer:*/ true); break; case SyntaxKind.GetAccessor: bindDeclaration(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true); @@ -482,7 +482,7 @@ module ts { case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.SwitchStatement: - bindChildren(node, 0, /*isBlockScopeContainer*/ true); + bindChildren(node, SymbolFlags.None, /*isBlockScopeContainer*/ true); break; default: var saveParent = parent; @@ -493,7 +493,9 @@ module ts { } function bindParameter(node: ParameterDeclaration) { - if (isBindingPattern(node.name)) { + var isBinding = isBindingPattern(node.name); + + if (isBinding) { bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node), /*isBlockScopeContainer*/ false); } else { @@ -502,12 +504,25 @@ module ts { // If this is a property-parameter, then also declare the property symbol into the // containing class. - if (node.flags & NodeFlags.AccessibilityModifier && + if ((node.flags & NodeFlags.AccessibilityModifier) && node.parent.kind === SyntaxKind.Constructor && node.parent.parent.kind === SyntaxKind.ClassDeclaration) { var classDeclaration = node.parent.parent; - declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + + if (isBinding) { + forEach((node.name).elements, function declareBindingParameterProperties(curr: BindingElement) { + if (isBindingPattern(curr.name)) { + forEach((curr.name).elements, declareBindingParameterProperties) + } + else if (curr.name.kind === SyntaxKind.Identifier) { + declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, curr, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + } + }); + } + else { + declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + } } } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7604c709fbc71..58f86fccb5396 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -122,7 +122,7 @@ module ts { } function getExcludedSymbolFlags(flags: SymbolFlags): SymbolFlags { - var result: SymbolFlags = 0; + var result = SymbolFlags.None; if (flags & SymbolFlags.BlockScopedVariable) result |= SymbolFlags.BlockScopedVariableExcludes; if (flags & SymbolFlags.FunctionScopedVariable) result |= SymbolFlags.FunctionScopedVariableExcludes; if (flags & SymbolFlags.Property) result |= SymbolFlags.PropertyExcludes; @@ -1745,7 +1745,7 @@ module ts { function getTypeFromObjectBindingPattern(pattern: BindingPattern): Type { var members: SymbolTable = {}; forEach(pattern.elements, e => { - var flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); + var flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : SymbolFlags.None); var name = e.propertyName || e.name; var symbol = createSymbol(flags, name.text); symbol.type = getTypeFromBindingElement(e); @@ -5481,7 +5481,7 @@ module ts { } function getDeclarationFlagsFromSymbol(s: Symbol) { - return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; + return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? (NodeFlags.Public | NodeFlags.Static) : SymbolFlags.None; } function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol) { @@ -7189,7 +7189,7 @@ module ts { checkVariableLikeDeclaration(node); var func = getContainingFunction(node); - if (node.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) { + if (node.flags & NodeFlags.AccessibilityModifier) { func = getContainingFunction(node); if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); @@ -7208,17 +7208,20 @@ module ts { checkGrammarIndexSignature(node); } // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled - else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || + else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ConstructSignature){ checkGrammarFunctionLikeDeclaration(node); } checkTypeParameters(node.typeParameters); + forEach(node.parameters, checkParameter); + if (node.type) { checkSourceElement(node.type); } + if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); if (compilerOptions.noImplicitAny && !node.type) { @@ -7769,8 +7772,8 @@ module ts { // we use SymbolFlags.ExportValue, SymbolFlags.ExportType and SymbolFlags.ExportNamespace // to denote disjoint declarationSpaces (without making new enum type). - var exportedDeclarationSpaces: SymbolFlags = 0; - var nonExportedDeclarationSpaces: SymbolFlags = 0; + var exportedDeclarationSpaces = SymbolFlags.None; + var nonExportedDeclarationSpaces = SymbolFlags.None; forEach(symbol.declarations, d => { var declarationSpaces = getDeclarationSpaces(d); if (getEffectiveDeclarationFlags(d, NodeFlags.Export)) { @@ -7804,7 +7807,7 @@ module ts { case SyntaxKind.EnumDeclaration: return SymbolFlags.ExportType | SymbolFlags.ExportValue; case SyntaxKind.ImportDeclaration: - var result: SymbolFlags = 0; + var result = SymbolFlags.None; var target = resolveImport(getSymbolOfNode(d)); forEach(target.declarations, d => { result |= getDeclarationSpaces(d); }); return result; @@ -9105,9 +9108,9 @@ module ts { } if (target !== unknownSymbol) { var excludedMeanings = - (symbol.flags & SymbolFlags.Value ? SymbolFlags.Value : 0) | - (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | - (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + (symbol.flags & SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.None) | + (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : SymbolFlags.None) | + (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : SymbolFlags.None); if (target.flags & excludedMeanings) { error(node, Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0, symbolToString(symbol)); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d82e577971d5e..01419f71e3705 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3053,7 +3053,7 @@ module ts { } } - function emitBindingElement(target: BindingElement, value: Expression) { + function emitBindingElement(target: BindingElement, value?: Expression) { if (target.initializer) { // Combine value and initializer value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer; @@ -3369,18 +3369,26 @@ module ts { } function emitParameterPropertyAssignments(node: ConstructorDeclaration) { - forEach(node.parameters, param => { - if (param.flags & NodeFlags.AccessibilityModifier) { - writeLine(); - emitStart(param); - emitStart(param.name); - write("this."); - emitNode(param.name); - emitEnd(param.name); - write(" = "); - emit(param.name); - write(";"); - emitEnd(param); + forEach(node.parameters, function emitBoundProperty(binding: ParameterDeclaration | BindingElement) { + if (binding.flags & NodeFlags.AccessibilityModifier) { + if (isBindingPattern(binding.name)) { + emitStart(binding); + forEach((binding.name).elements, emitBoundProperty); + emitEnd(binding.name); + } + else { + writeLine(); + emitStart(binding); + emitStart(binding.name); + write("this."); + emitNode(binding.name); + emitEnd(binding.name); + write(" = "); + emit(binding.name); + write(";"); + emitEnd(binding); + } + } }); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b70c4a7a1d5cb..fbc73de19fd24 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1395,7 +1395,10 @@ module ts { } function canFollowModifier(): boolean { - return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName(); + return token === SyntaxKind.OpenBracketToken + || token === SyntaxKind.OpenBraceToken + || token === SyntaxKind.AsteriskToken + || isLiteralPropertyName(); } // True if positioned at the start of a list element @@ -2152,7 +2155,8 @@ module ts { function parseParameter(): ParameterDeclaration { var node = createNode(SyntaxKind.Parameter); - setModifiers(node, parseModifiers()); + var modifiers = parseModifiers(); + setModifiers(node, modifiers); node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); // SingleNameBinding[Yield,GeneratorParameter] : See 13.2.3 @@ -2161,6 +2165,10 @@ module ts { node.name = inGeneratorParameterContext() ? doInYieldContext(parseIdentifierOrPattern) : parseIdentifierOrPattern(); + if (isBindingPattern(node.name)) { + propagateModifiersToBindingElements(node.name, modifiers); + } + if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { // in cases like // 'use strict' @@ -2188,6 +2196,18 @@ module ts { return finishNode(node); } + function propagateModifiersToBindingElements(bindingPattern: BindingPattern, modifiers: ModifiersArray): void { + forEach(bindingPattern.elements, propagate); + + function propagate(node: BindingElement): void { + setModifiers(node, modifiers); + + if (isBindingPattern(node.name)) { + forEach((node.name).elements, propagate); + } + } + } + function parseParameterInitializer() { return parseInitializer(/*inParameter*/ true); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9ebab8dc2207c..a9ee10a9090f1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1129,6 +1129,7 @@ module ts { } export const enum SymbolFlags { + None = 0x00000000, // None FunctionScopedVariable = 0x00000001, // Variable (var) or parameter BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const) Property = 0x00000004, // Property or enum member diff --git a/tests/baselines/reference/destructuringParameterProperties1.js b/tests/baselines/reference/destructuringParameterProperties1.js new file mode 100644 index 0000000000000..cdcac8f77c4c9 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties1.js @@ -0,0 +1,67 @@ +//// [destructuringParameterProperties1.ts] +class C1 { + constructor(public [x, y, z]: string[]) { + } +} + +type TupleType1 = [string, number, boolean]; + +class C2 { + constructor(public [x, y, z]: TupleType1) { + } +} + +type ObjType1 = { x: number; y: string; z: boolean } + +class C3 { + constructor(public { x, y, z }: ObjType1) { + } +} + +var c1 = new C1([]); +c1 = new C1(["larry", "{curly}", "moe"]); +var useC1Properties = c1.x === c1.y && c1.y === c1.z; + +var c2 = new C2(["10", 10, !!10]); +var [c2_x, c2_y, c2_z] = [c2.x, c2.y, c2.z]; + +var c3 = new C3({x: 0, y: "", z: false}); +c3 = new C3({x: 0, "y": "y", z: true}); +var [c3_x, c3_y, c3_z] = [c3.x, c3.y, c3.z]; + +//// [destructuringParameterProperties1.js] +var C1 = (function () { + function C1(_a) { + var x = _a[0], y = _a[1], z = _a[2]; + this.x = x; + this.y = y; + this.z = z; + } + return C1; +})(); +var C2 = (function () { + function C2(_a) { + var x = _a[0], y = _a[1], z = _a[2]; + this.x = x; + this.y = y; + this.z = z; + } + return C2; +})(); +var C3 = (function () { + function C3(_a) { + var x = _a.x, y = _a.y, z = _a.z; + this.x = x; + this.y = y; + this.z = z; + } + return C3; +})(); +var c1 = new C1([]); +c1 = new C1(["larry", "{curly}", "moe"]); +var useC1Properties = c1.x === c1.y && c1.y === c1.z; +var c2 = new C2(["10", 10, !!10]); +var _a = [c2.x, c2.y, c2.z], c2_x = _a[0], c2_y = _a[1], c2_z = _a[2]; +var c3 = new C3({ x: 0, y: "", z: false }); +c3 = new C3({ x: 0, "y": "y", z: true }); +var _b = [c3.x, c3.y, c3.z], c3_x = _b[0], c3_y = _b[1], c3_z = _b[2]; diff --git a/tests/baselines/reference/destructuringParameterProperties1.types b/tests/baselines/reference/destructuringParameterProperties1.types new file mode 100644 index 0000000000000..81c325aed9274 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties1.types @@ -0,0 +1,129 @@ +=== tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts === +class C1 { +>C1 : C1 + + constructor(public [x, y, z]: string[]) { +>x : string +>y : string +>z : string + } +} + +type TupleType1 = [string, number, boolean]; +>TupleType1 : [string, number, boolean] + +class C2 { +>C2 : C2 + + constructor(public [x, y, z]: TupleType1) { +>x : string +>y : number +>z : boolean +>TupleType1 : [string, number, boolean] + } +} + +type ObjType1 = { x: number; y: string; z: boolean } +>ObjType1 : { x: number; y: string; z: boolean; } +>x : number +>y : string +>z : boolean + +class C3 { +>C3 : C3 + + constructor(public { x, y, z }: ObjType1) { +>x : number +>y : string +>z : boolean +>ObjType1 : { x: number; y: string; z: boolean; } + } +} + +var c1 = new C1([]); +>c1 : C1 +>new C1([]) : C1 +>C1 : typeof C1 +>[] : undefined[] + +c1 = new C1(["larry", "{curly}", "moe"]); +>c1 = new C1(["larry", "{curly}", "moe"]) : C1 +>c1 : C1 +>new C1(["larry", "{curly}", "moe"]) : C1 +>C1 : typeof C1 +>["larry", "{curly}", "moe"] : string[] + +var useC1Properties = c1.x === c1.y && c1.y === c1.z; +>useC1Properties : boolean +>c1.x === c1.y && c1.y === c1.z : boolean +>c1.x === c1.y : boolean +>c1.x : string +>c1 : C1 +>x : string +>c1.y : string +>c1 : C1 +>y : string +>c1.y === c1.z : boolean +>c1.y : string +>c1 : C1 +>y : string +>c1.z : string +>c1 : C1 +>z : string + +var c2 = new C2(["10", 10, !!10]); +>c2 : C2 +>new C2(["10", 10, !!10]) : C2 +>C2 : typeof C2 +>["10", 10, !!10] : [string, number, boolean] +>!!10 : boolean +>!10 : boolean + +var [c2_x, c2_y, c2_z] = [c2.x, c2.y, c2.z]; +>c2_x : string +>c2_y : number +>c2_z : boolean +>[c2.x, c2.y, c2.z] : [string, number, boolean] +>c2.x : string +>c2 : C2 +>x : string +>c2.y : number +>c2 : C2 +>y : number +>c2.z : boolean +>c2 : C2 +>z : boolean + +var c3 = new C3({x: 0, y: "", z: false}); +>c3 : C3 +>new C3({x: 0, y: "", z: false}) : C3 +>C3 : typeof C3 +>{x: 0, y: "", z: false} : { x: number; y: string; z: boolean; } +>x : number +>y : string +>z : boolean + +c3 = new C3({x: 0, "y": "y", z: true}); +>c3 = new C3({x: 0, "y": "y", z: true}) : C3 +>c3 : C3 +>new C3({x: 0, "y": "y", z: true}) : C3 +>C3 : typeof C3 +>{x: 0, "y": "y", z: true} : { x: number; "y": string; z: boolean; } +>x : number +>z : boolean + +var [c3_x, c3_y, c3_z] = [c3.x, c3.y, c3.z]; +>c3_x : number +>c3_y : string +>c3_z : boolean +>[c3.x, c3.y, c3.z] : [number, string, boolean] +>c3.x : number +>c3 : C3 +>x : number +>c3.y : string +>c3 : C3 +>y : string +>c3.z : boolean +>c3 : C3 +>z : boolean + diff --git a/tests/baselines/reference/destructuringParameterProperties2.errors.txt b/tests/baselines/reference/destructuringParameterProperties2.errors.txt new file mode 100644 index 0000000000000..c963b6d1acc86 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties2.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts(21,27): error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'. + + +==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts (1 errors) ==== + class C1 { + constructor(private k: number, private [a, b, c]: [number, string, boolean]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } + } + + var x = new C1(undefined, [0, undefined, ""]); + ~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '[number, undefined, string]' is not assignable to parameter of type '[number, string, boolean]'. + var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; + + var y = new C1(10, [0, "", true]); + var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; + + var z = new C1(10, [undefined, "", null]); + var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringParameterProperties2.js b/tests/baselines/reference/destructuringParameterProperties2.js new file mode 100644 index 0000000000000..8b88fa39fcb4a --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties2.js @@ -0,0 +1,60 @@ +//// [destructuringParameterProperties2.ts] +class C1 { + constructor(private k: number, private [a, b, c]: [number, string, boolean]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +var x = new C1(undefined, [0, undefined, ""]); +var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; + +var y = new C1(10, [0, "", true]); +var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; + +var z = new C1(10, [undefined, "", null]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; + + +//// [destructuringParameterProperties2.js] +var C1 = (function () { + function C1(k, _a) { + var a = _a[0], b = _a[1], c = _a[2]; + this.k = k; + this.a = a; + this.b = b; + this.c = c; + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + C1.prototype.getA = function () { + return this.a; + }; + C1.prototype.getB = function () { + return this.b; + }; + C1.prototype.getC = function () { + return this.c; + }; + return C1; +})(); +var x = new C1(undefined, [0, undefined, ""]); +var _a = [x.getA(), x.getB(), x.getC()], x_a = _a[0], x_b = _a[1], x_c = _a[2]; +var y = new C1(10, [0, "", true]); +var _b = [y.getA(), y.getB(), y.getC()], y_a = _b[0], y_b = _b[1], y_c = _b[2]; +var z = new C1(10, [undefined, "", null]); +var _c = [z.getA(), z.getB(), z.getC()], z_a = _c[0], z_b = _c[1], z_c = _c[2]; diff --git a/tests/baselines/reference/destructuringParameterProperties3.js b/tests/baselines/reference/destructuringParameterProperties3.js new file mode 100644 index 0000000000000..7a54b09f0b655 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties3.js @@ -0,0 +1,65 @@ +//// [destructuringParameterProperties3.ts] +class C1 { + constructor(private k: T, private [a, b, c]: [T,U,V]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +var x = new C1(undefined, [0, true, ""]); +var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; + +var y = new C1(10, [0, true, true]); +var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; + +var z = new C1(10, [undefined, "", ""]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; + +var w = new C1(10, [undefined, undefined, undefined]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; + + +//// [destructuringParameterProperties3.js] +var C1 = (function () { + function C1(k, _a) { + var a = _a[0], b = _a[1], c = _a[2]; + this.k = k; + this.a = a; + this.b = b; + this.c = c; + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + C1.prototype.getA = function () { + return this.a; + }; + C1.prototype.getB = function () { + return this.b; + }; + C1.prototype.getC = function () { + return this.c; + }; + return C1; +})(); +var x = new C1(undefined, [0, true, ""]); +var _a = [x.getA(), x.getB(), x.getC()], x_a = _a[0], x_b = _a[1], x_c = _a[2]; +var y = new C1(10, [0, true, true]); +var _b = [y.getA(), y.getB(), y.getC()], y_a = _b[0], y_b = _b[1], y_c = _b[2]; +var z = new C1(10, [undefined, "", ""]); +var _c = [z.getA(), z.getB(), z.getC()], z_a = _c[0], z_b = _c[1], z_c = _c[2]; +var w = new C1(10, [undefined, undefined, undefined]); +var _d = [z.getA(), z.getB(), z.getC()], z_a = _d[0], z_b = _d[1], z_c = _d[2]; diff --git a/tests/baselines/reference/destructuringParameterProperties3.types b/tests/baselines/reference/destructuringParameterProperties3.types new file mode 100644 index 0000000000000..19b8b266ddc76 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties3.types @@ -0,0 +1,180 @@ +=== tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts === +class C1 { +>C1 : C1 +>T : T +>U : U +>V : V + + constructor(private k: T, private [a, b, c]: [T,U,V]) { +>k : T +>T : T +>a : T +>b : U +>c : V +>T : T +>U : U +>V : V + + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { +>(b === undefined && c === undefined) || (this.b === undefined && this.c === undefined) : boolean +>(b === undefined && c === undefined) : boolean +>b === undefined && c === undefined : boolean +>b === undefined : boolean +>b : U +>undefined : undefined +>c === undefined : boolean +>c : V +>undefined : undefined +>(this.b === undefined && this.c === undefined) : boolean +>this.b === undefined && this.c === undefined : boolean +>this.b === undefined : boolean +>this.b : U +>this : C1 +>b : U +>undefined : undefined +>this.c === undefined : boolean +>this.c : V +>this : C1 +>c : V +>undefined : undefined + + this.a = a || k; +>this.a = a || k : T +>this.a : T +>this : C1 +>a : T +>a || k : T +>a : T +>k : T + } + } + + public getA() { +>getA : () => T + + return this.a +>this.a : T +>this : C1 +>a : T + } + + public getB() { +>getB : () => U + + return this.b +>this.b : U +>this : C1 +>b : U + } + + public getC() { +>getC : () => V + + return this.c; +>this.c : V +>this : C1 +>c : V + } +} + +var x = new C1(undefined, [0, true, ""]); +>x : C1 +>new C1(undefined, [0, true, ""]) : C1 +>C1 : typeof C1 +>undefined : undefined +>[0, true, ""] : [number, boolean, string] + +var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; +>x_a : number +>x_b : boolean +>x_c : string +>[x.getA(), x.getB(), x.getC()] : [number, boolean, string] +>x.getA() : number +>x.getA : () => number +>x : C1 +>getA : () => number +>x.getB() : boolean +>x.getB : () => boolean +>x : C1 +>getB : () => boolean +>x.getC() : string +>x.getC : () => string +>x : C1 +>getC : () => string + +var y = new C1(10, [0, true, true]); +>y : C1 +>new C1(10, [0, true, true]) : C1 +>C1 : typeof C1 +>[0, true, true] : [number, boolean, boolean] + +var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; +>y_a : number +>y_b : boolean +>y_c : boolean +>[y.getA(), y.getB(), y.getC()] : [number, boolean, boolean] +>y.getA() : number +>y.getA : () => number +>y : C1 +>getA : () => number +>y.getB() : boolean +>y.getB : () => boolean +>y : C1 +>getB : () => boolean +>y.getC() : boolean +>y.getC : () => boolean +>y : C1 +>getC : () => boolean + +var z = new C1(10, [undefined, "", ""]); +>z : C1 +>new C1(10, [undefined, "", ""]) : C1 +>C1 : typeof C1 +>[undefined, "", ""] : [undefined, string, string] +>undefined : undefined + +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; +>z_a : number +>z_b : string +>z_c : string +>[z.getA(), z.getB(), z.getC()] : [number, string, string] +>z.getA() : number +>z.getA : () => number +>z : C1 +>getA : () => number +>z.getB() : string +>z.getB : () => string +>z : C1 +>getB : () => string +>z.getC() : string +>z.getC : () => string +>z : C1 +>getC : () => string + +var w = new C1(10, [undefined, undefined, undefined]); +>w : C1 +>new C1(10, [undefined, undefined, undefined]) : C1 +>C1 : typeof C1 +>[undefined, undefined, undefined] : [undefined, undefined, undefined] +>undefined : undefined +>undefined : undefined +>undefined : undefined + +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; +>z_a : number +>z_b : string +>z_c : string +>[z.getA(), z.getB(), z.getC()] : [number, string, string] +>z.getA() : number +>z.getA : () => number +>z : C1 +>getA : () => number +>z.getB() : string +>z.getB : () => string +>z : C1 +>getB : () => string +>z.getC() : string +>z.getC : () => string +>z : C1 +>getC : () => string + diff --git a/tests/baselines/reference/destructuringParameterProperties4.js b/tests/baselines/reference/destructuringParameterProperties4.js new file mode 100644 index 0000000000000..8dd7029aa2d06 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties4.js @@ -0,0 +1,67 @@ +//// [destructuringParameterProperties4.ts] + +class C1 { + constructor(private k: T, protected [a, b, c]: [T,U,V]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +class C2 extends C1 { + public doSomethingWithSuperProperties() { + return `${this.a} ${this.b} ${this.c}`; + } +} + + +//// [destructuringParameterProperties4.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C1 = (function () { + function C1(k, [a, b, c]) { + this.k = k; + this.a = a; + this.b = b; + this.c = c; + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + C1.prototype.getA = function () { + return this.a; + }; + C1.prototype.getB = function () { + return this.b; + }; + C1.prototype.getC = function () { + return this.c; + }; + return C1; +})(); +var C2 = (function (_super) { + __extends(C2, _super); + function C2() { + _super.apply(this, arguments); + } + C2.prototype.doSomethingWithSuperProperties = function () { + return `${this.a} ${this.b} ${this.c}`; + }; + return C2; +})(C1); diff --git a/tests/baselines/reference/destructuringParameterProperties4.types b/tests/baselines/reference/destructuringParameterProperties4.types new file mode 100644 index 0000000000000..86c5b52e20f42 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties4.types @@ -0,0 +1,100 @@ +=== tests/cases/conformance/es6/destructuring/destructuringParameterProperties4.ts === + +class C1 { +>C1 : C1 +>T : T +>U : U +>V : V + + constructor(private k: T, protected [a, b, c]: [T,U,V]) { +>k : T +>T : T +>a : T +>b : U +>c : V +>T : T +>U : U +>V : V + + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { +>(b === undefined && c === undefined) || (this.b === undefined && this.c === undefined) : boolean +>(b === undefined && c === undefined) : boolean +>b === undefined && c === undefined : boolean +>b === undefined : boolean +>b : U +>undefined : undefined +>c === undefined : boolean +>c : V +>undefined : undefined +>(this.b === undefined && this.c === undefined) : boolean +>this.b === undefined && this.c === undefined : boolean +>this.b === undefined : boolean +>this.b : U +>this : C1 +>b : U +>undefined : undefined +>this.c === undefined : boolean +>this.c : V +>this : C1 +>c : V +>undefined : undefined + + this.a = a || k; +>this.a = a || k : T +>this.a : T +>this : C1 +>a : T +>a || k : T +>a : T +>k : T + } + } + + public getA() { +>getA : () => T + + return this.a +>this.a : T +>this : C1 +>a : T + } + + public getB() { +>getB : () => U + + return this.b +>this.b : U +>this : C1 +>b : U + } + + public getC() { +>getC : () => V + + return this.c; +>this.c : V +>this : C1 +>c : V + } +} + +class C2 extends C1 { +>C2 : C2 +>C1 : C1 + + public doSomethingWithSuperProperties() { +>doSomethingWithSuperProperties : () => string + + return `${this.a} ${this.b} ${this.c}`; +>this.a : number +>this : C2 +>a : number +>this.b : string +>this : C2 +>b : string +>this.c : boolean +>this : C2 +>c : boolean + } +} + diff --git a/tests/baselines/reference/destructuringParameterProperties5.errors.txt b/tests/baselines/reference/destructuringParameterProperties5.errors.txt new file mode 100644 index 0000000000000..30e03c12a43f8 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties5.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(5,27): error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x1' and no string index signature. +tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(5,31): error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x2' and no string index signature. +tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(5,35): error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x3' and no string index signature. +tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts(11,16): error TS2345: Argument of type '[{ x1: number; x2: string; x3: boolean; }, string, boolean]' is not assignable to parameter of type '[{ x: number; y: string; z: boolean; }, number, string]'. + Types of property '0' are incompatible. + Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. + Property 'x' is missing in type '{ x1: number; x2: string; x3: boolean; }'. + + +==== tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts (4 errors) ==== + type ObjType1 = { x: number; y: string; z: boolean } + type TupleType1 = [ObjType1, number, string] + + class C1 { + constructor(public [{ x1, x2, x3 }, y, z]: TupleType1) { + ~~ +!!! error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x1' and no string index signature. + ~~ +!!! error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x2' and no string index signature. + ~~ +!!! error TS2459: Type '{ x: number; y: string; z: boolean; }' has no property 'x3' and no string index signature. + var foo: any = x1 || x2 || x3 || y || z; + var bar: any = this.x1 || this.x2 || this.x3 || this.y || this.z; + } + } + + var a = new C1([{ x1: 10, x2: "", x3: true }, "", false]); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '[{ x1: number; x2: string; x3: boolean; }, string, boolean]' is not assignable to parameter of type '[{ x: number; y: string; z: boolean; }, number, string]'. +!!! error TS2345: Types of property '0' are incompatible. +!!! error TS2345: Type '{ x1: number; x2: string; x3: boolean; }' is not assignable to type '{ x: number; y: string; z: boolean; }'. +!!! error TS2345: Property 'x' is missing in type '{ x1: number; x2: string; x3: boolean; }'. + var [a_x1, a_x2, a_x3, a_y, a_z] = [a.x1, a.x2, a.x3, a.y, a.z]; \ No newline at end of file diff --git a/tests/baselines/reference/destructuringParameterProperties5.js b/tests/baselines/reference/destructuringParameterProperties5.js new file mode 100644 index 0000000000000..ed0e604a55b62 --- /dev/null +++ b/tests/baselines/reference/destructuringParameterProperties5.js @@ -0,0 +1,30 @@ +//// [destructuringParameterProperties5.ts] +type ObjType1 = { x: number; y: string; z: boolean } +type TupleType1 = [ObjType1, number, string] + +class C1 { + constructor(public [{ x1, x2, x3 }, y, z]: TupleType1) { + var foo: any = x1 || x2 || x3 || y || z; + var bar: any = this.x1 || this.x2 || this.x3 || this.y || this.z; + } +} + +var a = new C1([{ x1: 10, x2: "", x3: true }, "", false]); +var [a_x1, a_x2, a_x3, a_y, a_z] = [a.x1, a.x2, a.x3, a.y, a.z]; + +//// [destructuringParameterProperties5.js] +var C1 = (function () { + function C1(_a) { + var _b = _a[0], x1 = _b.x1, x2 = _b.x2, x3 = _b.x3, y = _a[1], z = _a[2]; + this.x1 = x1; + this.x2 = x2; + this.x3 = x3; + this.y = y; + this.z = z; + var foo = x1 || x2 || x3 || y || z; + var bar = this.x1 || this.x2 || this.x3 || this.y || this.z; + } + return C1; +})(); +var a = new C1([{ x1: 10, x2: "", x3: true }, "", false]); +var _a = [a.x1, a.x2, a.x3, a.y, a.z], a_x1 = _a[0], a_x2 = _a[1], a_x3 = _a[2], a_y = _a[3], a_z = _a[4]; diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts new file mode 100644 index 0000000000000..ba73adc9fde21 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties1.ts @@ -0,0 +1,29 @@ +class C1 { + constructor(public [x, y, z]: string[]) { + } +} + +type TupleType1 = [string, number, boolean]; + +class C2 { + constructor(public [x, y, z]: TupleType1) { + } +} + +type ObjType1 = { x: number; y: string; z: boolean } + +class C3 { + constructor(public { x, y, z }: ObjType1) { + } +} + +var c1 = new C1([]); +c1 = new C1(["larry", "{curly}", "moe"]); +var useC1Properties = c1.x === c1.y && c1.y === c1.z; + +var c2 = new C2(["10", 10, !!10]); +var [c2_x, c2_y, c2_z] = [c2.x, c2.y, c2.z]; + +var c3 = new C3({x: 0, y: "", z: false}); +c3 = new C3({x: 0, "y": "y", z: true}); +var [c3_x, c3_y, c3_z] = [c3.x, c3.y, c3.z]; \ No newline at end of file diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts new file mode 100644 index 0000000000000..b7f37809154be --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties2.ts @@ -0,0 +1,28 @@ +class C1 { + constructor(private k: number, private [a, b, c]: [number, string, boolean]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +var x = new C1(undefined, [0, undefined, ""]); +var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; + +var y = new C1(10, [0, "", true]); +var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; + +var z = new C1(10, [undefined, "", null]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts new file mode 100644 index 0000000000000..6819d024e6a15 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties3.ts @@ -0,0 +1,31 @@ +class C1 { + constructor(private k: T, private [a, b, c]: [T,U,V]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +var x = new C1(undefined, [0, true, ""]); +var [x_a, x_b, x_c] = [x.getA(), x.getB(), x.getC()]; + +var y = new C1(10, [0, true, true]); +var [y_a, y_b, y_c] = [y.getA(), y.getB(), y.getC()]; + +var z = new C1(10, [undefined, "", ""]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; + +var w = new C1(10, [undefined, undefined, undefined]); +var [z_a, z_b, z_c] = [z.getA(), z.getB(), z.getC()]; diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterProperties4.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties4.ts new file mode 100644 index 0000000000000..7a83e5f4d4b99 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties4.ts @@ -0,0 +1,27 @@ +// @target: es6 + +class C1 { + constructor(private k: T, protected [a, b, c]: [T,U,V]) { + if ((b === undefined && c === undefined) || (this.b === undefined && this.c === undefined)) { + this.a = a || k; + } + } + + public getA() { + return this.a + } + + public getB() { + return this.b + } + + public getC() { + return this.c; + } +} + +class C2 extends C1 { + public doSomethingWithSuperProperties() { + return `${this.a} ${this.b} ${this.c}`; + } +} diff --git a/tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts new file mode 100644 index 0000000000000..02f9b780ad99d --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringParameterProperties5.ts @@ -0,0 +1,12 @@ +type ObjType1 = { x: number; y: string; z: boolean } +type TupleType1 = [ObjType1, number, string] + +class C1 { + constructor(public [{ x1, x2, x3 }, y, z]: TupleType1) { + var foo: any = x1 || x2 || x3 || y || z; + var bar: any = this.x1 || this.x2 || this.x3 || this.y || this.z; + } +} + +var a = new C1([{ x1: 10, x2: "", x3: true }, "", false]); +var [a_x1, a_x2, a_x3, a_y, a_z] = [a.x1, a.x2, a.x3, a.y, a.z]; \ No newline at end of file