From 0e273c3e07666d201bb434a6c822a2efbaec5a77 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 11 Jul 2019 10:45:19 -1000 Subject: [PATCH 1/3] Fix type parameter inference cache invalidation --- src/compiler/checker.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d5d99f62c..b840417db3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15229,8 +15229,8 @@ namespace ts { const inference = inferences[i]; if (t === inference.typeParameter) { if (fix && !inference.isFixed) { + clearCachedInferences(inferences); inference.isFixed = true; - inference.inferredType = undefined; } return getInferredType(context, i); } @@ -15238,6 +15238,14 @@ namespace ts { return t; } + function clearCachedInferences(inferences: InferenceInfo[]) { + for (const inference of inferences) { + if (!inference.isFixed) { + inference.inferredType = undefined; + } + } + } + function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { return { typeParameter, @@ -15517,17 +15525,17 @@ namespace ts { if (contravariant && !bivariant) { if (!contains(inference.contraCandidates, candidate)) { inference.contraCandidates = append(inference.contraCandidates, candidate); - inference.inferredType = undefined; + clearCachedInferences(inferences); } } else if (!contains(inference.candidates, candidate)) { inference.candidates = append(inference.candidates, candidate); - inference.inferredType = undefined; + clearCachedInferences(inferences); } } if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target)) { inference.topLevel = false; - inference.inferredType = undefined; + clearCachedInferences(inferences); } } return; From c53246fa35bb0e8f931042240e0fe28d5c34f31a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 11 Jul 2019 10:47:27 -1000 Subject: [PATCH 2/3] Add regression test --- .../typeInferenceCacheInvalidation.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/cases/compiler/typeInferenceCacheInvalidation.ts diff --git a/tests/cases/compiler/typeInferenceCacheInvalidation.ts b/tests/cases/compiler/typeInferenceCacheInvalidation.ts new file mode 100644 index 0000000000..d037f139ec --- /dev/null +++ b/tests/cases/compiler/typeInferenceCacheInvalidation.ts @@ -0,0 +1,23 @@ +// @strict: true + +// Repro from #32230 + +type Callback = (foo: TFoo, bar: TBar) => any + +declare function example>( + foo: TFoo, + callback: TCallback, + bar: TBar, +): TCallback + +example(42, (foo, bar) => ({ + t: () => { + let s: string = bar; + } +}), '42'); + +example(42, (foo, bar) => ({ + t() { + let s: string = bar; + } +}), '42'); From 4b9ca33e1d532b33da2331420b5353bb9a5ae576 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 11 Jul 2019 10:47:34 -1000 Subject: [PATCH 3/3] Accept new baselines --- .../typeInferenceCacheInvalidation.js | 37 +++++++++++ .../typeInferenceCacheInvalidation.symbols | 64 +++++++++++++++++++ .../typeInferenceCacheInvalidation.types | 63 ++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 tests/baselines/reference/typeInferenceCacheInvalidation.js create mode 100644 tests/baselines/reference/typeInferenceCacheInvalidation.symbols create mode 100644 tests/baselines/reference/typeInferenceCacheInvalidation.types diff --git a/tests/baselines/reference/typeInferenceCacheInvalidation.js b/tests/baselines/reference/typeInferenceCacheInvalidation.js new file mode 100644 index 0000000000..bda29ad8b7 --- /dev/null +++ b/tests/baselines/reference/typeInferenceCacheInvalidation.js @@ -0,0 +1,37 @@ +//// [typeInferenceCacheInvalidation.ts] +// Repro from #32230 + +type Callback = (foo: TFoo, bar: TBar) => any + +declare function example>( + foo: TFoo, + callback: TCallback, + bar: TBar, +): TCallback + +example(42, (foo, bar) => ({ + t: () => { + let s: string = bar; + } +}), '42'); + +example(42, (foo, bar) => ({ + t() { + let s: string = bar; + } +}), '42'); + + +//// [typeInferenceCacheInvalidation.js] +"use strict"; +// Repro from #32230 +example(42, function (foo, bar) { return ({ + t: function () { + var s = bar; + } +}); }, '42'); +example(42, function (foo, bar) { return ({ + t: function () { + var s = bar; + } +}); }, '42'); diff --git a/tests/baselines/reference/typeInferenceCacheInvalidation.symbols b/tests/baselines/reference/typeInferenceCacheInvalidation.symbols new file mode 100644 index 0000000000..e9e1949dc9 --- /dev/null +++ b/tests/baselines/reference/typeInferenceCacheInvalidation.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/typeInferenceCacheInvalidation.ts === +// Repro from #32230 + +type Callback = (foo: TFoo, bar: TBar) => any +>Callback : Symbol(Callback, Decl(typeInferenceCacheInvalidation.ts, 0, 0)) +>TFoo : Symbol(TFoo, Decl(typeInferenceCacheInvalidation.ts, 2, 14)) +>TBar : Symbol(TBar, Decl(typeInferenceCacheInvalidation.ts, 2, 19)) +>foo : Symbol(foo, Decl(typeInferenceCacheInvalidation.ts, 2, 29)) +>TFoo : Symbol(TFoo, Decl(typeInferenceCacheInvalidation.ts, 2, 14)) +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 2, 39)) +>TBar : Symbol(TBar, Decl(typeInferenceCacheInvalidation.ts, 2, 19)) + +declare function example>( +>example : Symbol(example, Decl(typeInferenceCacheInvalidation.ts, 2, 57)) +>TFoo : Symbol(TFoo, Decl(typeInferenceCacheInvalidation.ts, 4, 25)) +>TBar : Symbol(TBar, Decl(typeInferenceCacheInvalidation.ts, 4, 30)) +>TCallback : Symbol(TCallback, Decl(typeInferenceCacheInvalidation.ts, 4, 36)) +>Callback : Symbol(Callback, Decl(typeInferenceCacheInvalidation.ts, 0, 0)) +>TFoo : Symbol(TFoo, Decl(typeInferenceCacheInvalidation.ts, 4, 25)) +>TBar : Symbol(TBar, Decl(typeInferenceCacheInvalidation.ts, 4, 30)) + + foo: TFoo, +>foo : Symbol(foo, Decl(typeInferenceCacheInvalidation.ts, 4, 77)) +>TFoo : Symbol(TFoo, Decl(typeInferenceCacheInvalidation.ts, 4, 25)) + + callback: TCallback, +>callback : Symbol(callback, Decl(typeInferenceCacheInvalidation.ts, 5, 14)) +>TCallback : Symbol(TCallback, Decl(typeInferenceCacheInvalidation.ts, 4, 36)) + + bar: TBar, +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 6, 24)) +>TBar : Symbol(TBar, Decl(typeInferenceCacheInvalidation.ts, 4, 30)) + +): TCallback +>TCallback : Symbol(TCallback, Decl(typeInferenceCacheInvalidation.ts, 4, 36)) + +example(42, (foo, bar) => ({ +>example : Symbol(example, Decl(typeInferenceCacheInvalidation.ts, 2, 57)) +>foo : Symbol(foo, Decl(typeInferenceCacheInvalidation.ts, 10, 13)) +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 10, 17)) + + t: () => { +>t : Symbol(t, Decl(typeInferenceCacheInvalidation.ts, 10, 28)) + + let s: string = bar; +>s : Symbol(s, Decl(typeInferenceCacheInvalidation.ts, 12, 11)) +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 10, 17)) + } +}), '42'); + +example(42, (foo, bar) => ({ +>example : Symbol(example, Decl(typeInferenceCacheInvalidation.ts, 2, 57)) +>foo : Symbol(foo, Decl(typeInferenceCacheInvalidation.ts, 16, 13)) +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 16, 17)) + + t() { +>t : Symbol(t, Decl(typeInferenceCacheInvalidation.ts, 16, 28)) + + let s: string = bar; +>s : Symbol(s, Decl(typeInferenceCacheInvalidation.ts, 18, 11)) +>bar : Symbol(bar, Decl(typeInferenceCacheInvalidation.ts, 16, 17)) + } +}), '42'); + diff --git a/tests/baselines/reference/typeInferenceCacheInvalidation.types b/tests/baselines/reference/typeInferenceCacheInvalidation.types new file mode 100644 index 0000000000..35911fafb3 --- /dev/null +++ b/tests/baselines/reference/typeInferenceCacheInvalidation.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/typeInferenceCacheInvalidation.ts === +// Repro from #32230 + +type Callback = (foo: TFoo, bar: TBar) => any +>Callback : Callback +>foo : TFoo +>bar : TBar + +declare function example>( +>example : >(foo: TFoo, callback: TCallback, bar: TBar) => TCallback + + foo: TFoo, +>foo : TFoo + + callback: TCallback, +>callback : TCallback + + bar: TBar, +>bar : TBar + +): TCallback + +example(42, (foo, bar) => ({ +>example(42, (foo, bar) => ({ t: () => { let s: string = bar; }}), '42') : (foo: number, bar: string) => { t: () => void; } +>example : >(foo: TFoo, callback: TCallback, bar: TBar) => TCallback +>42 : 42 +>(foo, bar) => ({ t: () => { let s: string = bar; }}) : (foo: number, bar: string) => { t: () => void; } +>foo : number +>bar : string +>({ t: () => { let s: string = bar; }}) : { t: () => void; } +>{ t: () => { let s: string = bar; }} : { t: () => void; } + + t: () => { +>t : () => void +>() => { let s: string = bar; } : () => void + + let s: string = bar; +>s : string +>bar : string + } +}), '42'); +>'42' : "42" + +example(42, (foo, bar) => ({ +>example(42, (foo, bar) => ({ t() { let s: string = bar; }}), '42') : (foo: number, bar: string) => { t(): void; } +>example : >(foo: TFoo, callback: TCallback, bar: TBar) => TCallback +>42 : 42 +>(foo, bar) => ({ t() { let s: string = bar; }}) : (foo: number, bar: string) => { t(): void; } +>foo : number +>bar : string +>({ t() { let s: string = bar; }}) : { t(): void; } +>{ t() { let s: string = bar; }} : { t(): void; } + + t() { +>t : () => void + + let s: string = bar; +>s : string +>bar : string + } +}), '42'); +>'42' : "42" +