diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 961ca205281ab..6b480699a55c7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2771,6 +2771,11 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } + // a method declaration with object rest destructuring is ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + // An async method declaration is ES2017 syntax. if (hasModifier(node, ModifierFlags.Async)) { transformFlags |= TransformFlags.AssertES2017; @@ -2797,6 +2802,11 @@ namespace ts { transformFlags |= TransformFlags.AssertTypeScript; } + // a method declaration with object rest destructuring is ES Next syntax + if (subtreeFlags & TransformFlags.ContainsSpreadExpression) { + transformFlags |= TransformFlags.AssertESNext; + } + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; return transformFlags & ~TransformFlags.MethodOrAccessorExcludes; } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1fad209bdb31e..0db09d79570fa 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -46,6 +46,11 @@ namespace ts { return visitFunctionExpression(node as FunctionExpression); case SyntaxKind.ArrowFunction: return visitArrowFunction(node as ArrowFunction); + case SyntaxKind.MethodDeclaration: + return visitMethodDeclaration(node as MethodDeclaration); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return visitAccessorDeclaration(node as AccessorDeclaration); case SyntaxKind.Parameter: return visitParameter(node as ParameterDeclaration); default: @@ -208,11 +213,6 @@ namespace ts { } function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); - return setOriginalNode( createFunctionDeclaration( /*decorators*/ undefined, @@ -222,17 +222,13 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node); } function visitArrowFunction(node: ArrowFunction) { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); const func = setOriginalNode( createArrowFunction( /*modifiers*/ undefined, @@ -240,7 +236,7 @@ namespace ts { visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, node.equalsGreaterThanToken, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node @@ -250,10 +246,6 @@ namespace ts { } function visitFunctionExpression(node: FunctionExpression): Expression { - const hasRest = forEach(node.parameters, isObjectRestParameter); - const body = hasRest ? - transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block : - visitEachChild(node.body, visitor, context); return setOriginalNode( createFunctionExpression( /*modifiers*/ undefined, @@ -262,11 +254,62 @@ namespace ts { /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - body, + transformFunctionBodyIfNeeded(node), /*location*/ node ), /*original*/ node ); } + + function visitMethodDeclaration(node: MethodDeclaration): MethodDeclaration { + return setOriginalNode( + createMethod( + /*decorators*/ undefined, + node.modifiers, + node.asteriskToken, + node.name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + + function visitAccessorDeclaration(node: AccessorDeclaration): AccessorDeclaration { + if (node.kind === SyntaxKind.GetAccessor) { + return setOriginalNode( + createGetAccessor( + /*decorators*/ undefined, + node.modifiers, + node.name, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + else { + return setOriginalNode( + createSetAccessor( + /*decorators*/ undefined, + node.modifiers, + node.name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBodyIfNeeded(node), + /*location*/ node + ), + /*original*/ node); + } + } + + function transformFunctionBodyIfNeeded(node: FunctionLikeDeclaration): Block { + const hasRest = forEach(node.parameters, isObjectRestParameter); + return hasRest ? + transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) : + visitEachChild(node.body, visitor, context) as Block; + } } } diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js index 49434f24eece7..a05448a8be2bf 100644 --- a/tests/baselines/reference/objectRestParameter.js +++ b/tests/baselines/reference/objectRestParameter.js @@ -6,6 +6,15 @@ 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 + } +} + //// [objectRestParameter.js] @@ -26,3 +35,13 @@ suddenly((_a = { x: { z: 1, ka: 1 }, y: 'noo' }) => { var _b = _a.x, { z = 12 } = _b, nested = __rest(_b, ["z"]), rest = __rest(_a, ["x"]); return rest.y + nested.ka; }); +class C { + m(_a) { + var { a } = _a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + } + set p(_a) { + var { a } = _a, clone = __rest(_a, ["a"]); + // actually, never mind, don't clone + } +} diff --git a/tests/baselines/reference/objectRestParameter.symbols b/tests/baselines/reference/objectRestParameter.symbols index 9569dc53d3a86..c43a8ba5a04ed 100644 --- a/tests/baselines/reference/objectRestParameter.symbols +++ b/tests/baselines/reference/objectRestParameter.symbols @@ -42,4 +42,27 @@ suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' >nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24)) >ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42)) +class C { +>C : Symbol(C, Decl(objectRestParameter.ts, 5, 107)) + + m({ a, ...clone }: { a: number, b: string}): void { +>m : Symbol(C.m, Decl(objectRestParameter.ts, 7, 9)) +>a : Symbol(a, Decl(objectRestParameter.ts, 8, 7)) +>clone : Symbol(clone, Decl(objectRestParameter.ts, 8, 10)) +>a : Symbol(a, Decl(objectRestParameter.ts, 8, 24)) +>b : Symbol(b, Decl(objectRestParameter.ts, 8, 35)) + + // actually, never mind, don't clone + } + set p({ a, ...clone }: { a: number, b: string}) { +>p : Symbol(C.p, Decl(objectRestParameter.ts, 10, 5)) +>a : Symbol(a, Decl(objectRestParameter.ts, 11, 11)) +>clone : Symbol(clone, Decl(objectRestParameter.ts, 11, 14)) +>a : Symbol(a, Decl(objectRestParameter.ts, 11, 28)) +>b : Symbol(b, Decl(objectRestParameter.ts, 11, 39)) + + // actually, never mind, don't clone + } +} + diff --git a/tests/baselines/reference/objectRestParameter.types b/tests/baselines/reference/objectRestParameter.types index c634c9c5cd530..56e7352870f63 100644 --- a/tests/baselines/reference/objectRestParameter.types +++ b/tests/baselines/reference/objectRestParameter.types @@ -53,4 +53,27 @@ suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' >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 + } +} + diff --git a/tests/cases/conformance/types/rest/objectRestParameter.ts b/tests/cases/conformance/types/rest/objectRestParameter.ts index 5b47442f047ab..a9c17a29d146d 100644 --- a/tests/cases/conformance/types/rest/objectRestParameter.ts +++ b/tests/cases/conformance/types/rest/objectRestParameter.ts @@ -6,3 +6,12 @@ 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 + } +} +