Skip to content

Commit acf854b

Browse files
authored
Keep track of multiple current inference contexts (#51978)
* Keep track of multiple current inference contexts * Add regression test
1 parent 54a554d commit acf854b

File tree

5 files changed

+220
-9
lines changed

5 files changed

+220
-9
lines changed

src/compiler/checker.ts

+20-9
Original file line numberDiff line numberDiff line change
@@ -2069,8 +2069,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20692069
const contextualTypes: (Type | undefined)[] = [];
20702070
let contextualTypeCount = 0;
20712071

2072-
let currentInferenceNode: Node | undefined;
2073-
let currentInferenceContext: InferenceContext | undefined;
2072+
const inferenceContextNodes: Node[] = [];
2073+
const inferenceContexts: (InferenceContext | undefined)[] = [];
2074+
let inferenceContextCount = 0;
20742075

20752076
const emptyStringType = getStringLiteralType("");
20762077
const zeroType = getNumberLiteralType(0);
@@ -28764,8 +28765,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2876428765
return -1;
2876528766
}
2876628767

28768+
function pushInferenceContext(node: Node, inferenceContext: InferenceContext | undefined) {
28769+
inferenceContextNodes[inferenceContextCount] = node;
28770+
inferenceContexts[inferenceContextCount] = inferenceContext;
28771+
inferenceContextCount++;
28772+
}
28773+
28774+
function popInferenceContext() {
28775+
inferenceContextCount--;
28776+
}
28777+
2876728778
function getInferenceContext(node: Node) {
28768-
return isNodeDescendantOf(node, currentInferenceNode) ? currentInferenceContext : undefined;
28779+
for (let i = inferenceContextCount - 1; i >= 0; i--) {
28780+
if (isNodeDescendantOf(node, inferenceContextNodes[i])) {
28781+
return inferenceContexts[i];
28782+
}
28783+
}
2876928784
}
2877028785

2877128786
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
@@ -36022,10 +36037,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3602236037
function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type {
3602336038
const contextNode = getContextNode(node);
3602436039
pushContextualType(contextNode, contextualType);
36025-
const saveInferenceNode = currentInferenceNode;
36026-
const saveInferenceContext = currentInferenceContext;
36027-
currentInferenceNode = contextNode;
36028-
currentInferenceContext = inferenceContext;
36040+
pushInferenceContext(contextNode, inferenceContext);
3602936041
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
3603036042
// In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type
3603136043
// parameters. This information is no longer needed after the call to checkExpression.
@@ -36037,8 +36049,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3603736049
// here would be to not mark contextually typed literals as fresh in the first place.
3603836050
const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ?
3603936051
getRegularTypeOfLiteralType(type) : type;
36040-
currentInferenceNode = saveInferenceNode;
36041-
currentInferenceContext = saveInferenceContext;
36052+
popInferenceContext();
3604236053
popContextualType();
3604336054
return result;
3604436055
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [multipleInferenceContexts.ts]
2+
type ConstructorOptions<Data> =
3+
& ComponentOptionsProperties<Data>
4+
& ThisType<Instance<Data>>;
5+
6+
interface ComponentOptionsProperties<Data> {
7+
data: Data;
8+
render(): unknown;
9+
}
10+
11+
interface Instance<Data> {
12+
get<K extends keyof Data>(name: K): unknown;
13+
}
14+
15+
declare var Moon: {
16+
<Data>(options?: ConstructorOptions<Data>): Instance<Data>;
17+
};
18+
19+
const r2 = Moon({
20+
data: { msg: "" },
21+
render() {
22+
const h = (x: unknown) => x;
23+
return h(this.get("msg"));
24+
},
25+
});
26+
27+
28+
//// [multipleInferenceContexts.js]
29+
"use strict";
30+
var r2 = Moon({
31+
data: { msg: "" },
32+
render: function () {
33+
var h = function (x) { return x; };
34+
return h(this.get("msg"));
35+
},
36+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
=== tests/cases/compiler/multipleInferenceContexts.ts ===
2+
type ConstructorOptions<Data> =
3+
>ConstructorOptions : Symbol(ConstructorOptions, Decl(multipleInferenceContexts.ts, 0, 0))
4+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24))
5+
6+
& ComponentOptionsProperties<Data>
7+
>ComponentOptionsProperties : Symbol(ComponentOptionsProperties, Decl(multipleInferenceContexts.ts, 2, 31))
8+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24))
9+
10+
& ThisType<Instance<Data>>;
11+
>ThisType : Symbol(ThisType, Decl(lib.es5.d.ts, --, --))
12+
>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1))
13+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24))
14+
15+
interface ComponentOptionsProperties<Data> {
16+
>ComponentOptionsProperties : Symbol(ComponentOptionsProperties, Decl(multipleInferenceContexts.ts, 2, 31))
17+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 4, 37))
18+
19+
data: Data;
20+
>data : Symbol(ComponentOptionsProperties.data, Decl(multipleInferenceContexts.ts, 4, 44))
21+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 4, 37))
22+
23+
render(): unknown;
24+
>render : Symbol(ComponentOptionsProperties.render, Decl(multipleInferenceContexts.ts, 5, 15))
25+
}
26+
27+
interface Instance<Data> {
28+
>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1))
29+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 9, 19))
30+
31+
get<K extends keyof Data>(name: K): unknown;
32+
>get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26))
33+
>K : Symbol(K, Decl(multipleInferenceContexts.ts, 10, 8))
34+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 9, 19))
35+
>name : Symbol(name, Decl(multipleInferenceContexts.ts, 10, 30))
36+
>K : Symbol(K, Decl(multipleInferenceContexts.ts, 10, 8))
37+
}
38+
39+
declare var Moon: {
40+
>Moon : Symbol(Moon, Decl(multipleInferenceContexts.ts, 13, 11))
41+
42+
<Data>(options?: ConstructorOptions<Data>): Instance<Data>;
43+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5))
44+
>options : Symbol(options, Decl(multipleInferenceContexts.ts, 14, 11))
45+
>ConstructorOptions : Symbol(ConstructorOptions, Decl(multipleInferenceContexts.ts, 0, 0))
46+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5))
47+
>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1))
48+
>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5))
49+
50+
};
51+
52+
const r2 = Moon({
53+
>r2 : Symbol(r2, Decl(multipleInferenceContexts.ts, 17, 5))
54+
>Moon : Symbol(Moon, Decl(multipleInferenceContexts.ts, 13, 11))
55+
56+
data: { msg: "" },
57+
>data : Symbol(data, Decl(multipleInferenceContexts.ts, 17, 17))
58+
>msg : Symbol(msg, Decl(multipleInferenceContexts.ts, 18, 11))
59+
60+
render() {
61+
>render : Symbol(render, Decl(multipleInferenceContexts.ts, 18, 22))
62+
63+
const h = (x: unknown) => x;
64+
>h : Symbol(h, Decl(multipleInferenceContexts.ts, 20, 13))
65+
>x : Symbol(x, Decl(multipleInferenceContexts.ts, 20, 19))
66+
>x : Symbol(x, Decl(multipleInferenceContexts.ts, 20, 19))
67+
68+
return h(this.get("msg"));
69+
>h : Symbol(h, Decl(multipleInferenceContexts.ts, 20, 13))
70+
>this.get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26))
71+
>this : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1))
72+
>get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26))
73+
74+
},
75+
});
76+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/compiler/multipleInferenceContexts.ts ===
2+
type ConstructorOptions<Data> =
3+
>ConstructorOptions : ConstructorOptions<Data>
4+
5+
& ComponentOptionsProperties<Data>
6+
& ThisType<Instance<Data>>;
7+
8+
interface ComponentOptionsProperties<Data> {
9+
data: Data;
10+
>data : Data
11+
12+
render(): unknown;
13+
>render : () => unknown
14+
}
15+
16+
interface Instance<Data> {
17+
get<K extends keyof Data>(name: K): unknown;
18+
>get : <K extends keyof Data>(name: K) => unknown
19+
>name : K
20+
}
21+
22+
declare var Moon: {
23+
>Moon : <Data>(options?: ConstructorOptions<Data> | undefined) => Instance<Data>
24+
25+
<Data>(options?: ConstructorOptions<Data>): Instance<Data>;
26+
>options : ConstructorOptions<Data> | undefined
27+
28+
};
29+
30+
const r2 = Moon({
31+
>r2 : Instance<{ msg: string; }>
32+
>Moon({ data: { msg: "" }, render() { const h = (x: unknown) => x; return h(this.get("msg")); },}) : Instance<{ msg: string; }>
33+
>Moon : <Data>(options?: ConstructorOptions<Data> | undefined) => Instance<Data>
34+
>{ data: { msg: "" }, render() { const h = (x: unknown) => x; return h(this.get("msg")); },} : { data: { msg: string; }; render(): unknown; }
35+
36+
data: { msg: "" },
37+
>data : { msg: string; }
38+
>{ msg: "" } : { msg: string; }
39+
>msg : string
40+
>"" : ""
41+
42+
render() {
43+
>render : () => unknown
44+
45+
const h = (x: unknown) => x;
46+
>h : (x: unknown) => unknown
47+
>(x: unknown) => x : (x: unknown) => unknown
48+
>x : unknown
49+
>x : unknown
50+
51+
return h(this.get("msg"));
52+
>h(this.get("msg")) : unknown
53+
>h : (x: unknown) => unknown
54+
>this.get("msg") : unknown
55+
>this.get : <K extends "msg">(name: K) => unknown
56+
>this : Instance<{ msg: string; }>
57+
>get : <K extends "msg">(name: K) => unknown
58+
>"msg" : "msg"
59+
60+
},
61+
});
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @strict: true
2+
3+
type ConstructorOptions<Data> =
4+
& ComponentOptionsProperties<Data>
5+
& ThisType<Instance<Data>>;
6+
7+
interface ComponentOptionsProperties<Data> {
8+
data: Data;
9+
render(): unknown;
10+
}
11+
12+
interface Instance<Data> {
13+
get<K extends keyof Data>(name: K): unknown;
14+
}
15+
16+
declare var Moon: {
17+
<Data>(options?: ConstructorOptions<Data>): Instance<Data>;
18+
};
19+
20+
const r2 = Moon({
21+
data: { msg: "" },
22+
render() {
23+
const h = (x: unknown) => x;
24+
return h(this.get("msg"));
25+
},
26+
});

0 commit comments

Comments
 (0)