diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index cf307199da0..5c7486debe3 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3058,7 +3058,18 @@ namespace ts { * @param ensureUseStrict: boolean determining whether the function need to add prologue-directives * @param visitor: Optional callback used to visit any custom prologue directives. */ - export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + export function addPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + const offset = addStandardPrologue(target, source, ensureUseStrict); + return addCustomPrologue(target, source, offset, visitor); + } + + /** + * Add just the standard (string-expression) prologue-directives into target statement-array. + * The function needs to be called during each transformation step. + * This function needs to be called whenever we transform the statement + * list of a source file, namespace, or function-like body. + */ + export function addStandardPrologue(target: Statement[], source: Statement[], ensureUseStrict?: boolean): number { Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); let foundUseStrict = false; let statementOffset = 0; @@ -3066,7 +3077,7 @@ namespace ts { while (statementOffset < numStatements) { const statement = source[statementOffset]; if (isPrologueDirective(statement)) { - if (isUseStrictPrologue(statement as ExpressionStatement)) { + if (isUseStrictPrologue(statement)) { foundUseStrict = true; } target.push(statement); @@ -3079,6 +3090,17 @@ namespace ts { if (ensureUseStrict && !foundUseStrict) { target.push(startOnNewLine(createStatement(createLiteral("use strict")))); } + return statementOffset; + } + + /** + * Add just the custom prologue-directives into target statement-array. + * The function needs to be called during each transformation step. + * This function needs to be called whenever we transform the statement + * list of a source file, namespace, or function-like body. + */ + export function addCustomPrologue(target: Statement[], source: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult): number { + const numStatements = source.length; while (statementOffset < numStatements) { const statement = source[statementOffset]; if (getEmitFlags(statement) & EmitFlags.CustomPrologue) { diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 3fd837dea10..f8ecf6bdcff 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -515,8 +515,9 @@ namespace ts { const ancestorFacts = enterSubtree(HierarchyFacts.SourceFileExcludes, HierarchyFacts.SourceFileIncludes); const statements: Statement[] = []; startLexicalEnvironment(); - const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ false, visitor); + let statementOffset = addStandardPrologue(statements, node.statements, /*ensureUseStrict*/ false); addCaptureThisForNodeIfNeeded(statements, node); + statementOffset = addCustomPrologue(statements, node.statements, statementOffset, visitor); addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); addRange(statements, endLexicalEnvironment()); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -924,13 +925,16 @@ namespace ts { statementOffset = 0; } else if (constructor) { - // Otherwise, try to emit all potential prologue directives first. - statementOffset = addPrologueDirectives(statements, constructor.body.statements, /*ensureUseStrict*/ false, visitor); + statementOffset = addStandardPrologue(statements, constructor.body.statements, /*ensureUseStrict*/ false); } if (constructor) { addDefaultValueAssignmentsIfNeeded(statements, constructor); addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); + if (!hasSynthesizedSuper) { + // If no super call has been synthesized, emit custom prologue directives. + statementOffset = addCustomPrologue(statements, constructor.body.statements, statementOffset, visitor); + } Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!"); } @@ -1821,8 +1825,8 @@ namespace ts { resumeLexicalEnvironment(); if (isBlock(body)) { // ensureUseStrict is false because no new prologue-directive should be added. - // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array - statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + // addStandardPrologue will put already-existing directives at the beginning of the target statement-array + statementOffset = addStandardPrologue(statements, body.statements, /*ensureUseStrict*/ false); } addCaptureThisForNodeIfNeeded(statements, node); @@ -1835,6 +1839,9 @@ namespace ts { } if (isBlock(body)) { + // addCustomPrologue puts already-existing directives at the beginning of the target statement-array + statementOffset = addCustomPrologue(statements, body.statements, statementOffset, visitor); + statementsLocation = body.statements; addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset)); diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 088c57866d0..3bbb3b3123f 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -222,7 +222,7 @@ namespace ts { if (!isArrowFunction) { const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, (node.body).statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, (node.body).statements, /*ensureUseStrict*/ false, visitor); statements.push( createReturn( createAwaiterHelper( diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 83e84e6eab5..b0e8b527820 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -618,7 +618,7 @@ namespace ts { function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { resumeLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.body.statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, node.body.statements, /*ensureUseStrict*/ false, visitor); appendObjectRestAssignmentsIfNeeded(statements, node); statements.push( @@ -663,12 +663,19 @@ namespace ts { function transformFunctionBody(node: ArrowFunction): ConciseBody; function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); - const leadingStatements = appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node); + let statementOffset = 0; + const statements: Statement[] = []; const body = visitNode(node.body, visitor, isConciseBody); + if (isBlock(body)) { + statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor); + } + addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node)); const trailingStatements = endLexicalEnvironment(); - if (some(leadingStatements) || some(trailingStatements)) { + if (statementOffset > 0 || some(statements) || some(trailingStatements)) { const block = convertToFunctionBody(body, /*multiLine*/ true); - return updateBlock(block, setTextRange(createNodeArray(concatenate(concatenate(leadingStatements, block.statements), trailingStatements)), block.statements)); + addRange(statements, block.statements.slice(statementOffset)); + addRange(statements, trailingStatements); + return updateBlock(block, setTextRange(createNodeArray(statements), block.statements)); } return body; } diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index a9da71de885..286892f9d3b 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -587,7 +587,7 @@ namespace ts { // Build the generator resumeLexicalEnvironment(); - const statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = addPrologue(statements, body.statements, /*ensureUseStrict*/ false, visitor); transformAndEmitStatements(body.statements, statementOffset); diff --git a/src/compiler/transformers/module/es2015.ts b/src/compiler/transformers/module/es2015.ts index 7028e235961..660293e074f 100644 --- a/src/compiler/transformers/module/es2015.ts +++ b/src/compiler/transformers/module/es2015.ts @@ -24,7 +24,7 @@ namespace ts { const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(node, compilerOptions); if (externalHelpersModuleName) { const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.statements); + const statementOffset = addPrologue(statements, node.statements); append(statements, createImportDeclaration( /*decorators*/ undefined, diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 4fe7b027e93..d387a1a3a24 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -90,7 +90,7 @@ namespace ts { const statements: Statement[] = []; const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); @@ -388,7 +388,7 @@ namespace ts { startLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = addPrologueDirectives(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 56341f482ff..cde4fcad57e 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -228,7 +228,7 @@ namespace ts { // Add any prologue directives. const ensureUseStrict = compilerOptions.alwaysStrict || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = addPrologueDirectives(statements, node.statements, ensureUseStrict, sourceElementVisitor); + const statementOffset = addPrologue(statements, node.statements, ensureUseStrict, sourceElementVisitor); // var __moduleName = context_1 && context_1.id; statements.push( diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 8df760d51c0..0daf76fa9ec 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -954,7 +954,7 @@ namespace ts { if (ctor.body) { const statements = ctor.body.statements; // add prologue directives to the list (if any) - const index = addPrologueDirectives(result, statements, /*ensureUseStrict*/ false, visitor); + const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); if (index === statements.length) { // list contains nothing but prologue directives (or empty) - exit return index; diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js index 14e84eddfce..a73e9b77b38 100644 --- a/tests/baselines/reference/objectRestParameter.js +++ b/tests/baselines/reference/objectRestParameter.js @@ -14,7 +14,11 @@ class C { // actually, never mind, don't clone } } - +function foobar({ bar={}, ...opts }: any = {}) { +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } }); //// [objectRestParameter.js] @@ -48,3 +52,9 @@ class C { // actually, never mind, don't clone } } +function foobar(_a = {}) { + var { bar = {} } = _a, opts = __rest(_a, ["bar"]); +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } }); diff --git a/tests/baselines/reference/objectRestParameter.symbols b/tests/baselines/reference/objectRestParameter.symbols index c43a8ba5a04..f629f46e8e9 100644 --- a/tests/baselines/reference/objectRestParameter.symbols +++ b/tests/baselines/reference/objectRestParameter.symbols @@ -64,5 +64,20 @@ class C { // actually, never mind, don't clone } } +function foobar({ bar={}, ...opts }: any = {}) { +>foobar : Symbol(foobar, Decl(objectRestParameter.ts, 14, 1)) +>bar : Symbol(bar, Decl(objectRestParameter.ts, 15, 17)) +>opts : Symbol(opts, Decl(objectRestParameter.ts, 15, 25)) +} +foobar(); +>foobar : Symbol(foobar, Decl(objectRestParameter.ts, 14, 1)) +foobar({ baz: 'hello' }); +>foobar : Symbol(foobar, Decl(objectRestParameter.ts, 14, 1)) +>baz : Symbol(baz, Decl(objectRestParameter.ts, 18, 8)) + +foobar({ bar: { greeting: 'hello' } }); +>foobar : Symbol(foobar, Decl(objectRestParameter.ts, 14, 1)) +>bar : Symbol(bar, Decl(objectRestParameter.ts, 19, 8)) +>greeting : Symbol(greeting, Decl(objectRestParameter.ts, 19, 15)) diff --git a/tests/baselines/reference/objectRestParameter.types b/tests/baselines/reference/objectRestParameter.types index 56e7352870f..e56e7cebfc7 100644 --- a/tests/baselines/reference/objectRestParameter.types +++ b/tests/baselines/reference/objectRestParameter.types @@ -75,5 +75,30 @@ class C { // actually, never mind, don't clone } } +function foobar({ bar={}, ...opts }: any = {}) { +>foobar : ({bar, ...opts}?: any) => void +>bar : {} +>{} : {} +>opts : any +>{} : {} +} +foobar(); +>foobar() : void +>foobar : ({bar, ...opts}?: any) => void +foobar({ baz: 'hello' }); +>foobar({ baz: 'hello' }) : void +>foobar : ({bar, ...opts}?: any) => void +>{ baz: 'hello' } : { baz: string; } +>baz : string +>'hello' : "hello" + +foobar({ bar: { greeting: 'hello' } }); +>foobar({ bar: { greeting: 'hello' } }) : void +>foobar : ({bar, ...opts}?: any) => void +>{ bar: { greeting: 'hello' } } : { bar: { greeting: string; }; } +>bar : { greeting: string; } +>{ greeting: 'hello' } : { greeting: string; } +>greeting : string +>'hello' : "hello" diff --git a/tests/baselines/reference/objectRestParameterES5.js b/tests/baselines/reference/objectRestParameterES5.js new file mode 100644 index 00000000000..d16a0c68df0 --- /dev/null +++ b/tests/baselines/reference/objectRestParameterES5.js @@ -0,0 +1,69 @@ +//// [objectRestParameterES5.ts] +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +suddenly(({ x: a, ...rest }) => rest.y); +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); + +class C { + m({ a, ...clone }: { a: number, b: string}): void { + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { + // actually, never mind, don't clone + } +} +function foobar({ bar={}, ...opts }: any = {}) { +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } }); + + +//// [objectRestParameterES5.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +function cloneAgain(_a) { + var a = _a.a, clone = __rest(_a, ["a"]); +} +suddenly(function (_a) { + var a = _a.x, rest = __rest(_a, ["x"]); + return rest.y; +}); +suddenly(function (_a) { + if (_a === void 0) { _a = { x: { z: 1, ka: 1 }, y: 'noo' }; } + var _b = _a.x, _c = _b.z, z = _c === void 0 ? 12 : _c, nested = __rest(_b, ["z"]), rest = __rest(_a, ["x"]); + return rest.y + nested.ka; +}); +var C = (function () { + function C() { + } + C.prototype.m = function (_a) { + var a = _a.a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + }; + Object.defineProperty(C.prototype, "p", { + set: function (_a) { + var a = _a.a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + }, + enumerable: true, + configurable: true + }); + return C; +}()); +function foobar(_a) { + if (_a === void 0) { _a = {}; } + var _b = _a.bar, bar = _b === void 0 ? {} : _b, opts = __rest(_a, ["bar"]); +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } }); diff --git a/tests/baselines/reference/objectRestParameterES5.symbols b/tests/baselines/reference/objectRestParameterES5.symbols new file mode 100644 index 00000000000..4c6b8115169 --- /dev/null +++ b/tests/baselines/reference/objectRestParameterES5.symbols @@ -0,0 +1,83 @@ +=== tests/cases/conformance/types/rest/objectRestParameterES5.ts === +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +>cloneAgain : Symbol(cloneAgain, Decl(objectRestParameterES5.ts, 0, 0)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 0, 21)) +>clone : Symbol(clone, Decl(objectRestParameterES5.ts, 0, 24)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 0, 38)) +>b : Symbol(b, Decl(objectRestParameterES5.ts, 0, 49)) +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +>suddenly : Symbol(suddenly, Decl(objectRestParameterES5.ts, 1, 1)) +>f : Symbol(f, Decl(objectRestParameterES5.ts, 3, 26)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 3, 30)) +>x : Symbol(x, Decl(objectRestParameterES5.ts, 3, 34)) +>z : Symbol(z, Decl(objectRestParameterES5.ts, 3, 39)) +>ka : Symbol(ka, Decl(objectRestParameterES5.ts, 3, 42)) +>y : Symbol(y, Decl(objectRestParameterES5.ts, 3, 48)) + +suddenly(({ x: a, ...rest }) => rest.y); +>suddenly : Symbol(suddenly, Decl(objectRestParameterES5.ts, 1, 1)) +>x : Symbol(x, Decl(objectRestParameterES5.ts, 3, 34)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 4, 11)) +>rest : Symbol(rest, Decl(objectRestParameterES5.ts, 4, 17)) +>rest.y : Symbol(y, Decl(objectRestParameterES5.ts, 3, 48)) +>rest : Symbol(rest, Decl(objectRestParameterES5.ts, 4, 17)) +>y : Symbol(y, Decl(objectRestParameterES5.ts, 3, 48)) + +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +>suddenly : Symbol(suddenly, Decl(objectRestParameterES5.ts, 1, 1)) +>x : Symbol(x, Decl(objectRestParameterES5.ts, 3, 34)) +>z : Symbol(z, Decl(objectRestParameterES5.ts, 5, 16)) +>nested : Symbol(nested, Decl(objectRestParameterES5.ts, 5, 24)) +>rest : Symbol(rest, Decl(objectRestParameterES5.ts, 5, 37)) +>x : Symbol(x, Decl(objectRestParameterES5.ts, 5, 51)) +>z : Symbol(z, Decl(objectRestParameterES5.ts, 5, 56)) +>ka : Symbol(ka, Decl(objectRestParameterES5.ts, 5, 62)) +>y : Symbol(y, Decl(objectRestParameterES5.ts, 5, 71)) +>rest.y : Symbol(y, Decl(objectRestParameterES5.ts, 3, 48)) +>rest : Symbol(rest, Decl(objectRestParameterES5.ts, 5, 37)) +>y : Symbol(y, Decl(objectRestParameterES5.ts, 3, 48)) +>nested.ka : Symbol(ka, Decl(objectRestParameterES5.ts, 3, 42)) +>nested : Symbol(nested, Decl(objectRestParameterES5.ts, 5, 24)) +>ka : Symbol(ka, Decl(objectRestParameterES5.ts, 3, 42)) + +class C { +>C : Symbol(C, Decl(objectRestParameterES5.ts, 5, 107)) + + m({ a, ...clone }: { a: number, b: string}): void { +>m : Symbol(C.m, Decl(objectRestParameterES5.ts, 7, 9)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 8, 7)) +>clone : Symbol(clone, Decl(objectRestParameterES5.ts, 8, 10)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 8, 24)) +>b : Symbol(b, Decl(objectRestParameterES5.ts, 8, 35)) + + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { +>p : Symbol(C.p, Decl(objectRestParameterES5.ts, 10, 5)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 11, 11)) +>clone : Symbol(clone, Decl(objectRestParameterES5.ts, 11, 14)) +>a : Symbol(a, Decl(objectRestParameterES5.ts, 11, 28)) +>b : Symbol(b, Decl(objectRestParameterES5.ts, 11, 39)) + + // actually, never mind, don't clone + } +} +function foobar({ bar={}, ...opts }: any = {}) { +>foobar : Symbol(foobar, Decl(objectRestParameterES5.ts, 14, 1)) +>bar : Symbol(bar, Decl(objectRestParameterES5.ts, 15, 17)) +>opts : Symbol(opts, Decl(objectRestParameterES5.ts, 15, 25)) +} +foobar(); +>foobar : Symbol(foobar, Decl(objectRestParameterES5.ts, 14, 1)) + +foobar({ baz: 'hello' }); +>foobar : Symbol(foobar, Decl(objectRestParameterES5.ts, 14, 1)) +>baz : Symbol(baz, Decl(objectRestParameterES5.ts, 18, 8)) + +foobar({ bar: { greeting: 'hello' } }); +>foobar : Symbol(foobar, Decl(objectRestParameterES5.ts, 14, 1)) +>bar : Symbol(bar, Decl(objectRestParameterES5.ts, 19, 8)) +>greeting : Symbol(greeting, Decl(objectRestParameterES5.ts, 19, 15)) + diff --git a/tests/baselines/reference/objectRestParameterES5.types b/tests/baselines/reference/objectRestParameterES5.types new file mode 100644 index 00000000000..009d810782b --- /dev/null +++ b/tests/baselines/reference/objectRestParameterES5.types @@ -0,0 +1,104 @@ +=== tests/cases/conformance/types/rest/objectRestParameterES5.ts === +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +>cloneAgain : ({a, ...clone}: { a: number; b: string; }) => void +>a : number +>clone : { b: string; } +>a : number +>b : string +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>f : (a: { x: { z: any; ka: any; }; y: string; }) => void +>a : { x: { z: any; ka: any; }; y: string; } +>x : { z: any; ka: any; } +>z : any +>ka : any +>y : string + +suddenly(({ x: a, ...rest }) => rest.y); +>suddenly(({ x: a, ...rest }) => rest.y) : any +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>({ x: a, ...rest }) => rest.y : ({x: a, ...rest}: { x: { z: any; ka: any; }; y: string; }) => string +>x : any +>a : { z: any; ka: any; } +>rest : { y: string; } +>rest.y : string +>rest : { y: string; } +>y : string + +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); +>suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka) : any +>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any +>({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka : ({x: {z, ...nested}, ...rest}?: { x: { z: any; ka: any; }; y: string; }) => string +>x : any +>z : any +>12 : 12 +>nested : { ka: any; } +>rest : { y: string; } +>{ x: { z: 1, ka: 1 }, y: 'noo' } : { x: { z: number; ka: number; }; y: string; } +>x : { z: number; ka: number; } +>{ z: 1, ka: 1 } : { z: number; ka: number; } +>z : number +>1 : 1 +>ka : number +>1 : 1 +>y : string +>'noo' : "noo" +>rest.y + nested.ka : string +>rest.y : string +>rest : { y: string; } +>y : string +>nested.ka : any +>nested : { ka: any; } +>ka : any + +class C { +>C : C + + m({ a, ...clone }: { a: number, b: string}): void { +>m : ({a, ...clone}: { a: number; b: string; }) => void +>a : number +>clone : { b: string; } +>a : number +>b : string + + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { +>p : { a: number; b: string; } +>a : number +>clone : { b: string; } +>a : number +>b : string + + // actually, never mind, don't clone + } +} +function foobar({ bar={}, ...opts }: any = {}) { +>foobar : ({bar, ...opts}?: any) => void +>bar : {} +>{} : {} +>opts : any +>{} : {} +} +foobar(); +>foobar() : void +>foobar : ({bar, ...opts}?: any) => void + +foobar({ baz: 'hello' }); +>foobar({ baz: 'hello' }) : void +>foobar : ({bar, ...opts}?: any) => void +>{ baz: 'hello' } : { baz: string; } +>baz : string +>'hello' : "hello" + +foobar({ bar: { greeting: 'hello' } }); +>foobar({ bar: { greeting: 'hello' } }) : void +>foobar : ({bar, ...opts}?: any) => void +>{ bar: { greeting: 'hello' } } : { bar: { greeting: string; }; } +>bar : { greeting: string; } +>{ greeting: 'hello' } : { greeting: string; } +>greeting : string +>'hello' : "hello" + diff --git a/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.js b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.js new file mode 100644 index 00000000000..e7d4a4472e8 --- /dev/null +++ b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.js @@ -0,0 +1,49 @@ +//// [parameterInitializerBeforeDestructuringEmit.ts] +interface Foo { + bar?: any; + baz?: any; +} + +function foobar({ bar = {}, ...opts }: Foo = {}) { + "use strict"; + "Some other prologue"; + opts.baz(bar); +} + +class C { + constructor({ bar = {}, ...opts }: Foo = {}) { + "use strict"; + "Some other prologue"; + opts.baz(bar); + } +} + + +//// [parameterInitializerBeforeDestructuringEmit.js] +"use strict"; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +function foobar(_a) { + "use strict"; + "Some other prologue"; + if (_a === void 0) { _a = {}; } + var _b = _a.bar, bar = _b === void 0 ? {} : _b, opts = __rest(_a, ["bar"]); + opts.baz(bar); +} +var C = (function () { + function C(_a) { + "use strict"; + "Some other prologue"; + if (_a === void 0) { _a = {}; } + var _b = _a.bar, bar = _b === void 0 ? {} : _b, opts = __rest(_a, ["bar"]); + opts.baz(bar); + } + return C; +}()); diff --git a/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.symbols b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.symbols new file mode 100644 index 00000000000..857310bf87c --- /dev/null +++ b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.symbols @@ -0,0 +1,44 @@ +=== tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts === +interface Foo { +>Foo : Symbol(Foo, Decl(parameterInitializerBeforeDestructuringEmit.ts, 0, 0)) + + bar?: any; +>bar : Symbol(Foo.bar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 0, 15)) + + baz?: any; +>baz : Symbol(Foo.baz, Decl(parameterInitializerBeforeDestructuringEmit.ts, 1, 14)) +} + +function foobar({ bar = {}, ...opts }: Foo = {}) { +>foobar : Symbol(foobar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 3, 1)) +>bar : Symbol(bar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 5, 17)) +>opts : Symbol(opts, Decl(parameterInitializerBeforeDestructuringEmit.ts, 5, 27)) +>Foo : Symbol(Foo, Decl(parameterInitializerBeforeDestructuringEmit.ts, 0, 0)) + + "use strict"; + "Some other prologue"; + opts.baz(bar); +>opts.baz : Symbol(Foo.baz, Decl(parameterInitializerBeforeDestructuringEmit.ts, 1, 14)) +>opts : Symbol(opts, Decl(parameterInitializerBeforeDestructuringEmit.ts, 5, 27)) +>baz : Symbol(Foo.baz, Decl(parameterInitializerBeforeDestructuringEmit.ts, 1, 14)) +>bar : Symbol(bar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 5, 17)) +} + +class C { +>C : Symbol(C, Decl(parameterInitializerBeforeDestructuringEmit.ts, 9, 1)) + + constructor({ bar = {}, ...opts }: Foo = {}) { +>bar : Symbol(bar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 12, 17)) +>opts : Symbol(opts, Decl(parameterInitializerBeforeDestructuringEmit.ts, 12, 27)) +>Foo : Symbol(Foo, Decl(parameterInitializerBeforeDestructuringEmit.ts, 0, 0)) + + "use strict"; + "Some other prologue"; + opts.baz(bar); +>opts.baz : Symbol(Foo.baz, Decl(parameterInitializerBeforeDestructuringEmit.ts, 1, 14)) +>opts : Symbol(opts, Decl(parameterInitializerBeforeDestructuringEmit.ts, 12, 27)) +>baz : Symbol(Foo.baz, Decl(parameterInitializerBeforeDestructuringEmit.ts, 1, 14)) +>bar : Symbol(bar, Decl(parameterInitializerBeforeDestructuringEmit.ts, 12, 17)) + } +} + diff --git a/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.types b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.types new file mode 100644 index 00000000000..46b5983a514 --- /dev/null +++ b/tests/baselines/reference/parameterInitializerBeforeDestructuringEmit.types @@ -0,0 +1,58 @@ +=== tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts === +interface Foo { +>Foo : Foo + + bar?: any; +>bar : any + + baz?: any; +>baz : any +} + +function foobar({ bar = {}, ...opts }: Foo = {}) { +>foobar : ({bar, ...opts}?: Foo) => void +>bar : any +>{} : {} +>opts : { baz?: any; } +>Foo : Foo +>{} : {} + + "use strict"; +>"use strict" : "use strict" + + "Some other prologue"; +>"Some other prologue" : "Some other prologue" + + opts.baz(bar); +>opts.baz(bar) : any +>opts.baz : any +>opts : { baz?: any; } +>baz : any +>bar : any +} + +class C { +>C : C + + constructor({ bar = {}, ...opts }: Foo = {}) { +>bar : any +>{} : {} +>opts : { baz?: any; } +>Foo : Foo +>{} : {} + + "use strict"; +>"use strict" : "use strict" + + "Some other prologue"; +>"Some other prologue" : "Some other prologue" + + opts.baz(bar); +>opts.baz(bar) : any +>opts.baz : any +>opts : { baz?: any; } +>baz : any +>bar : any + } +} + diff --git a/tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts b/tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts new file mode 100644 index 00000000000..461ab1b9cf8 --- /dev/null +++ b/tests/cases/compiler/parameterInitializerBeforeDestructuringEmit.ts @@ -0,0 +1,20 @@ +// @noImplicitUseStrict: false +// @alwaysStrict: true +interface Foo { + bar?: any; + baz?: any; +} + +function foobar({ bar = {}, ...opts }: Foo = {}) { + "use strict"; + "Some other prologue"; + opts.baz(bar); +} + +class C { + constructor({ bar = {}, ...opts }: Foo = {}) { + "use strict"; + "Some other prologue"; + opts.baz(bar); + } +} diff --git a/tests/cases/conformance/types/rest/objectRestParameter.ts b/tests/cases/conformance/types/rest/objectRestParameter.ts index a9c17a29d14..5b6faeb7978 100644 --- a/tests/cases/conformance/types/rest/objectRestParameter.ts +++ b/tests/cases/conformance/types/rest/objectRestParameter.ts @@ -14,4 +14,8 @@ class C { // actually, never mind, don't clone } } - +function foobar({ bar={}, ...opts }: any = {}) { +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } }); diff --git a/tests/cases/conformance/types/rest/objectRestParameterES5.ts b/tests/cases/conformance/types/rest/objectRestParameterES5.ts new file mode 100644 index 00000000000..07a15ffbd44 --- /dev/null +++ b/tests/cases/conformance/types/rest/objectRestParameterES5.ts @@ -0,0 +1,21 @@ +// @target: es5 +function cloneAgain({ a, ...clone }: { a: number, b: string }): void { +} + +declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void); +suddenly(({ x: a, ...rest }) => rest.y); +suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka); + +class C { + m({ a, ...clone }: { a: number, b: string}): void { + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { + // actually, never mind, don't clone + } +} +function foobar({ bar={}, ...opts }: any = {}) { +} +foobar(); +foobar({ baz: 'hello' }); +foobar({ bar: { greeting: 'hello' } });