From 39c2a09b1fcdfd02dd837f9591ba6ad4157830ac Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 9 Oct 2020 10:53:36 -0700 Subject: [PATCH] Fix crash due to unchecked cast in addImplementationSuccessElaboration --- src/compiler/checker.ts | 2 +- ...dWithFunctionWithOverloadsUsage.errors.txt | 28 +++++++++++++++ ...aceMergedWithFunctionWithOverloadsUsage.js | 23 ++++++++++++ ...rgedWithFunctionWithOverloadsUsage.symbols | 36 +++++++++++++++++++ ...MergedWithFunctionWithOverloadsUsage.types | 31 ++++++++++++++++ ...aceMergedWithFunctionWithOverloadsUsage.ts | 15 ++++++++ 6 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.errors.txt create mode 100644 tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.js create mode 100644 tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.symbols create mode 100644 tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.types create mode 100644 tests/cases/compiler/namespaceMergedWithFunctionWithOverloadsUsage.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 999fe0a85c6be..6404bff181ac0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27335,7 +27335,7 @@ namespace ts { const declCount = length(failed.declaration?.symbol.declarations); const isOverload = declCount > 1; - const implDecl = isOverload ? find(failed.declaration?.symbol.declarations || emptyArray, d => nodeIsPresent((d as FunctionLikeDeclaration).body)) : undefined; + const implDecl = isOverload ? find(failed.declaration?.symbol.declarations || emptyArray, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) : undefined; if (implDecl) { const candidate = getSignatureFromDeclaration(implDecl as FunctionLikeDeclaration); const isSingleNonGenericCandidate = !candidate.typeParameters; diff --git a/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.errors.txt b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.errors.txt new file mode 100644 index 0000000000000..c8ddbed2dddc5 --- /dev/null +++ b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.errors.txt @@ -0,0 +1,28 @@ +tests/cases/compiler/index.ts(3,3): error TS2769: No overload matches this call. + Overload 1 of 2, '(opts?: Whatever): void', gave the following error. + Argument of type 'number' is not assignable to parameter of type 'Whatever'. + Overload 2 of 2, '(cb: Function, opts?: Whatever): void', gave the following error. + Argument of type 'number' is not assignable to parameter of type 'Function'. + + +==== tests/cases/compiler/index.ts (1 errors) ==== + import X = require("./file"); + + X(0); // shouldn't cause a crash + ~ +!!! error TS2769: No overload matches this call. +!!! error TS2769: Overload 1 of 2, '(opts?: Whatever): void', gave the following error. +!!! error TS2769: Argument of type 'number' is not assignable to parameter of type 'Whatever'. +!!! error TS2769: Overload 2 of 2, '(cb: Function, opts?: Whatever): void', gave the following error. +!!! error TS2769: Argument of type 'number' is not assignable to parameter of type 'Function'. +==== tests/cases/compiler/file.d.ts (0 errors) ==== + declare namespace Foo { + interface Whatever { + prop: any; + } + } + + declare function Foo(opts?: Foo.Whatever): void; + declare function Foo(cb: Function, opts?: Foo.Whatever): void; + + export = Foo; \ No newline at end of file diff --git a/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.js b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.js new file mode 100644 index 0000000000000..9350a389cd314 --- /dev/null +++ b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.js @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/namespaceMergedWithFunctionWithOverloadsUsage.ts] //// + +//// [file.d.ts] +declare namespace Foo { + interface Whatever { + prop: any; + } +} + +declare function Foo(opts?: Foo.Whatever): void; +declare function Foo(cb: Function, opts?: Foo.Whatever): void; + +export = Foo; +//// [index.ts] +import X = require("./file"); + +X(0); // shouldn't cause a crash + +//// [index.js] +"use strict"; +exports.__esModule = true; +var X = require("./file"); +X(0); // shouldn't cause a crash diff --git a/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.symbols b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.symbols new file mode 100644 index 0000000000000..009d9fd7d9d08 --- /dev/null +++ b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.symbols @@ -0,0 +1,36 @@ +=== tests/cases/compiler/index.ts === +import X = require("./file"); +>X : Symbol(X, Decl(index.ts, 0, 0)) + +X(0); // shouldn't cause a crash +>X : Symbol(X, Decl(index.ts, 0, 0)) + +=== tests/cases/compiler/file.d.ts === +declare namespace Foo { +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) + + interface Whatever { +>Whatever : Symbol(Whatever, Decl(file.d.ts, 0, 23)) + + prop: any; +>prop : Symbol(Whatever.prop, Decl(file.d.ts, 1, 24)) + } +} + +declare function Foo(opts?: Foo.Whatever): void; +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) +>opts : Symbol(opts, Decl(file.d.ts, 6, 21)) +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) +>Whatever : Symbol(Foo.Whatever, Decl(file.d.ts, 0, 23)) + +declare function Foo(cb: Function, opts?: Foo.Whatever): void; +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) +>cb : Symbol(cb, Decl(file.d.ts, 7, 21)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>opts : Symbol(opts, Decl(file.d.ts, 7, 34)) +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) +>Whatever : Symbol(Foo.Whatever, Decl(file.d.ts, 0, 23)) + +export = Foo; +>Foo : Symbol(Foo, Decl(file.d.ts, 4, 1), Decl(file.d.ts, 6, 48), Decl(file.d.ts, 0, 0)) + diff --git a/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.types b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.types new file mode 100644 index 0000000000000..a7652416c4448 --- /dev/null +++ b/tests/baselines/reference/namespaceMergedWithFunctionWithOverloadsUsage.types @@ -0,0 +1,31 @@ +=== tests/cases/compiler/index.ts === +import X = require("./file"); +>X : { (opts?: X.Whatever): void; (cb: Function, opts?: X.Whatever): void; } + +X(0); // shouldn't cause a crash +>X(0) : void +>X : { (opts?: X.Whatever): void; (cb: Function, opts?: X.Whatever): void; } +>0 : 0 + +=== tests/cases/compiler/file.d.ts === +declare namespace Foo { + interface Whatever { + prop: any; +>prop : any + } +} + +declare function Foo(opts?: Foo.Whatever): void; +>Foo : { (opts?: Foo.Whatever): void; (cb: Function, opts?: Foo.Whatever): void; } +>opts : Foo.Whatever +>Foo : any + +declare function Foo(cb: Function, opts?: Foo.Whatever): void; +>Foo : { (opts?: Foo.Whatever): void; (cb: Function, opts?: Foo.Whatever): void; } +>cb : Function +>opts : Foo.Whatever +>Foo : any + +export = Foo; +>Foo : { (opts?: Foo.Whatever): void; (cb: Function, opts?: Foo.Whatever): void; } + diff --git a/tests/cases/compiler/namespaceMergedWithFunctionWithOverloadsUsage.ts b/tests/cases/compiler/namespaceMergedWithFunctionWithOverloadsUsage.ts new file mode 100644 index 0000000000000..10f558566c0df --- /dev/null +++ b/tests/cases/compiler/namespaceMergedWithFunctionWithOverloadsUsage.ts @@ -0,0 +1,15 @@ +// @filename: file.d.ts +declare namespace Foo { + interface Whatever { + prop: any; + } +} + +declare function Foo(opts?: Foo.Whatever): void; +declare function Foo(cb: Function, opts?: Foo.Whatever): void; + +export = Foo; +// @filename: index.ts +import X = require("./file"); + +X(0); // shouldn't cause a crash \ No newline at end of file