From 58ff76abf663190a91ada6e3f23e9b3fed417af0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 28 Jul 2019 09:01:11 -0700 Subject: [PATCH 1/3] Properly instantiate contextual type for object literal methods --- src/compiler/checker.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f8242ed6df700..1ad92eebc2112 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19099,10 +19099,13 @@ namespace ts { // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined { - const contextualType = instantiateContextualType(getContextualType(node, contextFlags), node, contextFlags); - if (contextualType) { - const apparentType = mapType(contextualType, getApparentType, /*noReductions*/ true); + function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags?: ContextFlags): Type | undefined { + const contextualType = isObjectLiteralMethod(node) ? + getContextualTypeForObjectLiteralMethod(node, contextFlags) : + getContextualType(node, contextFlags); + const instantiatedType = instantiateContextualType(contextualType, node, contextFlags); + if (instantiatedType) { + const apparentType = mapType(instantiatedType, getApparentType, /*noReductions*/ true); if (apparentType.flags & TypeFlags.Union) { if (isObjectLiteralExpression(node)) { return discriminateContextualTypeByObjectMembers(node, apparentType as UnionType); @@ -19426,9 +19429,7 @@ namespace ts { if (typeTagSignature) { return typeTagSignature; } - const type = isObjectLiteralMethod(node) ? - getContextualTypeForObjectLiteralMethod(node, ContextFlags.Signature) : - getApparentTypeOfContextualType(node, ContextFlags.Signature); + const type = getApparentTypeOfContextualType(node, ContextFlags.Signature); if (!type) { return undefined; } From a717d3ab44b2cacc9e0fb36861bbe7c428bba6fc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 28 Jul 2019 09:05:57 -0700 Subject: [PATCH 2/3] Add regression test --- tests/cases/compiler/instantiateContextualTypes.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/compiler/instantiateContextualTypes.ts b/tests/cases/compiler/instantiateContextualTypes.ts index 3165011ecffea..4059bd5202e9a 100644 --- a/tests/cases/compiler/instantiateContextualTypes.ts +++ b/tests/cases/compiler/instantiateContextualTypes.ts @@ -174,3 +174,13 @@ class Interesting { declare function invoke(f: () => T): T; let xx: 0 | 1 | 2 = invoke(() => 1); + +// Repro from #32416 + +declare function assignPartial(target: T, partial: Partial): T; + +let obj = { + foo(bar: string) {} +} + +assignPartial(obj, { foo(...args) {} }); // args has type [string] From 4a17581f67a0c0cd413adcd7ce0e0ffe30698122 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 28 Jul 2019 09:06:04 -0700 Subject: [PATCH 3/3] Accept new baselines --- .../reference/instantiateContextualTypes.js | 14 ++++++++++ .../instantiateContextualTypes.symbols | 26 +++++++++++++++++++ .../instantiateContextualTypes.types | 24 +++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/tests/baselines/reference/instantiateContextualTypes.js b/tests/baselines/reference/instantiateContextualTypes.js index 9de6bfb612c15..46d87cb11538b 100644 --- a/tests/baselines/reference/instantiateContextualTypes.js +++ b/tests/baselines/reference/instantiateContextualTypes.js @@ -172,6 +172,16 @@ class Interesting { declare function invoke(f: () => T): T; let xx: 0 | 1 | 2 = invoke(() => 1); + +// Repro from #32416 + +declare function assignPartial(target: T, partial: Partial): T; + +let obj = { + foo(bar: string) {} +} + +assignPartial(obj, { foo(...args) {} }); // args has type [string] //// [instantiateContextualTypes.js] @@ -222,3 +232,7 @@ class Interesting { } } let xx = invoke(() => 1); +let obj = { + foo(bar) { } +}; +assignPartial(obj, { foo(...args) { } }); // args has type [string] diff --git a/tests/baselines/reference/instantiateContextualTypes.symbols b/tests/baselines/reference/instantiateContextualTypes.symbols index 1250edd585ba6..d3e8a7a317c4f 100644 --- a/tests/baselines/reference/instantiateContextualTypes.symbols +++ b/tests/baselines/reference/instantiateContextualTypes.symbols @@ -481,3 +481,29 @@ let xx: 0 | 1 | 2 = invoke(() => 1); >xx : Symbol(xx, Decl(instantiateContextualTypes.ts, 172, 3)) >invoke : Symbol(invoke, Decl(instantiateContextualTypes.ts, 166, 1)) +// Repro from #32416 + +declare function assignPartial(target: T, partial: Partial): T; +>assignPartial : Symbol(assignPartial, Decl(instantiateContextualTypes.ts, 172, 36)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 176, 31)) +>target : Symbol(target, Decl(instantiateContextualTypes.ts, 176, 34)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 176, 31)) +>partial : Symbol(partial, Decl(instantiateContextualTypes.ts, 176, 44)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 176, 31)) +>T : Symbol(T, Decl(instantiateContextualTypes.ts, 176, 31)) + +let obj = { +>obj : Symbol(obj, Decl(instantiateContextualTypes.ts, 178, 3)) + + foo(bar: string) {} +>foo : Symbol(foo, Decl(instantiateContextualTypes.ts, 178, 11)) +>bar : Symbol(bar, Decl(instantiateContextualTypes.ts, 179, 6)) +} + +assignPartial(obj, { foo(...args) {} }); // args has type [string] +>assignPartial : Symbol(assignPartial, Decl(instantiateContextualTypes.ts, 172, 36)) +>obj : Symbol(obj, Decl(instantiateContextualTypes.ts, 178, 3)) +>foo : Symbol(foo, Decl(instantiateContextualTypes.ts, 182, 20)) +>args : Symbol(args, Decl(instantiateContextualTypes.ts, 182, 25)) + diff --git a/tests/baselines/reference/instantiateContextualTypes.types b/tests/baselines/reference/instantiateContextualTypes.types index 88e6ca7e4ddd5..b5317b6f7561f 100644 --- a/tests/baselines/reference/instantiateContextualTypes.types +++ b/tests/baselines/reference/instantiateContextualTypes.types @@ -422,3 +422,27 @@ let xx: 0 | 1 | 2 = invoke(() => 1); >() => 1 : () => 1 >1 : 1 +// Repro from #32416 + +declare function assignPartial(target: T, partial: Partial): T; +>assignPartial : (target: T, partial: Partial) => T +>target : T +>partial : Partial + +let obj = { +>obj : { foo(bar: string): void; } +>{ foo(bar: string) {}} : { foo(bar: string): void; } + + foo(bar: string) {} +>foo : (bar: string) => void +>bar : string +} + +assignPartial(obj, { foo(...args) {} }); // args has type [string] +>assignPartial(obj, { foo(...args) {} }) : { foo(bar: string): void; } +>assignPartial : (target: T, partial: Partial) => T +>obj : { foo(bar: string): void; } +>{ foo(...args) {} } : { foo(bar: string): void; } +>foo : (bar: string) => void +>args : [string] +