From 0e1df66a7cbf98e5706e8a5d5fcd9855efa4c595 Mon Sep 17 00:00:00 2001 From: Zzzen <843968788@qq.com> Date: Tue, 25 May 2021 06:52:40 +0800 Subject: [PATCH] don't duplicate function properties when emiting definitions of overload signatures (#44235) --- src/compiler/transformers/declarations.ts | 12 +++++++++- ...clarationEmitFunctionDuplicateNamespace.js | 23 ++++++++++++++++++ ...tionEmitFunctionDuplicateNamespace.symbols | 22 +++++++++++++++++ ...rationEmitFunctionDuplicateNamespace.types | 24 +++++++++++++++++++ ...clarationEmitFunctionDuplicateNamespace.ts | 8 +++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.js create mode 100644 tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.symbols create mode 100644 tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.types create mode 100644 tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 9732458c7a9..6a9cb08fa7c 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -574,6 +574,16 @@ namespace ts { return false; } + // If the ExpandoFunctionDeclaration have multiple overloads, then we only need to emit properties for the last one. + function shouldEmitFunctionProperties(input: FunctionDeclaration) { + if (input.body) { + return true; + } + + const overloadSignatures = input.symbol.declarations?.filter(decl => isFunctionDeclaration(decl) && !decl.body); + return !overloadSignatures || overloadSignatures.indexOf(input) === overloadSignatures.length - 1; + } + function getBindingNameVisible(elem: BindingElement | VariableDeclaration | OmittedExpression): boolean { if (isOmittedExpression(elem)) { return false; @@ -1194,7 +1204,7 @@ namespace ts { ensureType(input, input.type), /*body*/ undefined )); - if (clean && resolver.isExpandoFunctionDeclaration(input)) { + if (clean && resolver.isExpandoFunctionDeclaration(input) && shouldEmitFunctionProperties(input)) { const props = resolver.getPropertiesOfContainerFunction(input); // Use parseNodeFactory so it is usable as an enclosing declaration const fakespace = parseNodeFactory.createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace); diff --git a/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.js b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.js new file mode 100644 index 00000000000..c32276096db --- /dev/null +++ b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.js @@ -0,0 +1,23 @@ +//// [declarationEmitFunctionDuplicateNamespace.ts] +function f(a: 0): 0; +function f(a: 1): 1; +function f(a: 0 | 1) { + return a; +} + +f.x = 2; + + +//// [declarationEmitFunctionDuplicateNamespace.js] +function f(a) { + return a; +} +f.x = 2; + + +//// [declarationEmitFunctionDuplicateNamespace.d.ts] +declare function f(a: 0): 0; +declare function f(a: 1): 1; +declare namespace f { + var x: number; +} diff --git a/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.symbols b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.symbols new file mode 100644 index 00000000000..75ff9f9d4e0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts === +function f(a: 0): 0; +>f : Symbol(f, Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 0), Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 1, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) +>a : Symbol(a, Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 11)) + +function f(a: 1): 1; +>f : Symbol(f, Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 0), Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 1, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) +>a : Symbol(a, Decl(declarationEmitFunctionDuplicateNamespace.ts, 1, 11)) + +function f(a: 0 | 1) { +>f : Symbol(f, Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 0), Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 1, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) +>a : Symbol(a, Decl(declarationEmitFunctionDuplicateNamespace.ts, 2, 11)) + + return a; +>a : Symbol(a, Decl(declarationEmitFunctionDuplicateNamespace.ts, 2, 11)) +} + +f.x = 2; +>f.x : Symbol(f.x, Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) +>f : Symbol(f, Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 0), Decl(declarationEmitFunctionDuplicateNamespace.ts, 0, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 1, 20), Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) +>x : Symbol(f.x, Decl(declarationEmitFunctionDuplicateNamespace.ts, 4, 1)) + diff --git a/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.types b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.types new file mode 100644 index 00000000000..74bd54bcc00 --- /dev/null +++ b/tests/baselines/reference/declarationEmitFunctionDuplicateNamespace.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts === +function f(a: 0): 0; +>f : typeof f +>a : 0 + +function f(a: 1): 1; +>f : typeof f +>a : 1 + +function f(a: 0 | 1) { +>f : typeof f +>a : 0 | 1 + + return a; +>a : 0 | 1 +} + +f.x = 2; +>f.x = 2 : 2 +>f.x : number +>f : typeof f +>x : number +>2 : 2 + diff --git a/tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts b/tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts new file mode 100644 index 00000000000..317f6b7e517 --- /dev/null +++ b/tests/cases/compiler/declarationEmitFunctionDuplicateNamespace.ts @@ -0,0 +1,8 @@ +// @declaration: true +function f(a: 0): 0; +function f(a: 1): 1; +function f(a: 0 | 1) { + return a; +} + +f.x = 2;