diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 667152d3ad2..7ded1be4ea4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2069,8 +2069,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const contextualTypes: (Type | undefined)[] = []; let contextualTypeCount = 0; - let currentInferenceNode: Node | undefined; - let currentInferenceContext: InferenceContext | undefined; + const inferenceContextNodes: Node[] = []; + const inferenceContexts: (InferenceContext | undefined)[] = []; + let inferenceContextCount = 0; const emptyStringType = getStringLiteralType(""); const zeroType = getNumberLiteralType(0); @@ -28764,8 +28765,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return -1; } + function pushInferenceContext(node: Node, inferenceContext: InferenceContext | undefined) { + inferenceContextNodes[inferenceContextCount] = node; + inferenceContexts[inferenceContextCount] = inferenceContext; + inferenceContextCount++; + } + + function popInferenceContext() { + inferenceContextCount--; + } + function getInferenceContext(node: Node) { - return isNodeDescendantOf(node, currentInferenceNode) ? currentInferenceContext : undefined; + for (let i = inferenceContextCount - 1; i >= 0; i--) { + if (isNodeDescendantOf(node, inferenceContextNodes[i])) { + return inferenceContexts[i]; + } + } } function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { @@ -36022,10 +36037,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { const contextNode = getContextNode(node); pushContextualType(contextNode, contextualType); - const saveInferenceNode = currentInferenceNode; - const saveInferenceContext = currentInferenceContext; - currentInferenceNode = contextNode; - currentInferenceContext = inferenceContext; + pushInferenceContext(contextNode, inferenceContext); const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type // parameters. This information is no longer needed after the call to checkExpression. @@ -36037,8 +36049,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // here would be to not mark contextually typed literals as fresh in the first place. const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? getRegularTypeOfLiteralType(type) : type; - currentInferenceNode = saveInferenceNode; - currentInferenceContext = saveInferenceContext; + popInferenceContext(); popContextualType(); return result; } diff --git a/tests/baselines/reference/multipleInferenceContexts.js b/tests/baselines/reference/multipleInferenceContexts.js new file mode 100644 index 00000000000..533cc5578d5 --- /dev/null +++ b/tests/baselines/reference/multipleInferenceContexts.js @@ -0,0 +1,36 @@ +//// [multipleInferenceContexts.ts] +type ConstructorOptions = + & ComponentOptionsProperties + & ThisType>; + +interface ComponentOptionsProperties { + data: Data; + render(): unknown; +} + +interface Instance { + get(name: K): unknown; +} + +declare var Moon: { + (options?: ConstructorOptions): Instance; +}; + +const r2 = Moon({ + data: { msg: "" }, + render() { + const h = (x: unknown) => x; + return h(this.get("msg")); + }, +}); + + +//// [multipleInferenceContexts.js] +"use strict"; +var r2 = Moon({ + data: { msg: "" }, + render: function () { + var h = function (x) { return x; }; + return h(this.get("msg")); + }, +}); diff --git a/tests/baselines/reference/multipleInferenceContexts.symbols b/tests/baselines/reference/multipleInferenceContexts.symbols new file mode 100644 index 00000000000..b92eedada3d --- /dev/null +++ b/tests/baselines/reference/multipleInferenceContexts.symbols @@ -0,0 +1,76 @@ +=== tests/cases/compiler/multipleInferenceContexts.ts === +type ConstructorOptions = +>ConstructorOptions : Symbol(ConstructorOptions, Decl(multipleInferenceContexts.ts, 0, 0)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24)) + + & ComponentOptionsProperties +>ComponentOptionsProperties : Symbol(ComponentOptionsProperties, Decl(multipleInferenceContexts.ts, 2, 31)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24)) + + & ThisType>; +>ThisType : Symbol(ThisType, Decl(lib.es5.d.ts, --, --)) +>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 0, 24)) + +interface ComponentOptionsProperties { +>ComponentOptionsProperties : Symbol(ComponentOptionsProperties, Decl(multipleInferenceContexts.ts, 2, 31)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 4, 37)) + + data: Data; +>data : Symbol(ComponentOptionsProperties.data, Decl(multipleInferenceContexts.ts, 4, 44)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 4, 37)) + + render(): unknown; +>render : Symbol(ComponentOptionsProperties.render, Decl(multipleInferenceContexts.ts, 5, 15)) +} + +interface Instance { +>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 9, 19)) + + get(name: K): unknown; +>get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26)) +>K : Symbol(K, Decl(multipleInferenceContexts.ts, 10, 8)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 9, 19)) +>name : Symbol(name, Decl(multipleInferenceContexts.ts, 10, 30)) +>K : Symbol(K, Decl(multipleInferenceContexts.ts, 10, 8)) +} + +declare var Moon: { +>Moon : Symbol(Moon, Decl(multipleInferenceContexts.ts, 13, 11)) + + (options?: ConstructorOptions): Instance; +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5)) +>options : Symbol(options, Decl(multipleInferenceContexts.ts, 14, 11)) +>ConstructorOptions : Symbol(ConstructorOptions, Decl(multipleInferenceContexts.ts, 0, 0)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5)) +>Instance : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1)) +>Data : Symbol(Data, Decl(multipleInferenceContexts.ts, 14, 5)) + +}; + +const r2 = Moon({ +>r2 : Symbol(r2, Decl(multipleInferenceContexts.ts, 17, 5)) +>Moon : Symbol(Moon, Decl(multipleInferenceContexts.ts, 13, 11)) + + data: { msg: "" }, +>data : Symbol(data, Decl(multipleInferenceContexts.ts, 17, 17)) +>msg : Symbol(msg, Decl(multipleInferenceContexts.ts, 18, 11)) + + render() { +>render : Symbol(render, Decl(multipleInferenceContexts.ts, 18, 22)) + + const h = (x: unknown) => x; +>h : Symbol(h, Decl(multipleInferenceContexts.ts, 20, 13)) +>x : Symbol(x, Decl(multipleInferenceContexts.ts, 20, 19)) +>x : Symbol(x, Decl(multipleInferenceContexts.ts, 20, 19)) + + return h(this.get("msg")); +>h : Symbol(h, Decl(multipleInferenceContexts.ts, 20, 13)) +>this.get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26)) +>this : Symbol(Instance, Decl(multipleInferenceContexts.ts, 7, 1)) +>get : Symbol(Instance.get, Decl(multipleInferenceContexts.ts, 9, 26)) + + }, +}); + diff --git a/tests/baselines/reference/multipleInferenceContexts.types b/tests/baselines/reference/multipleInferenceContexts.types new file mode 100644 index 00000000000..1751ab8f276 --- /dev/null +++ b/tests/baselines/reference/multipleInferenceContexts.types @@ -0,0 +1,62 @@ +=== tests/cases/compiler/multipleInferenceContexts.ts === +type ConstructorOptions = +>ConstructorOptions : ConstructorOptions + + & ComponentOptionsProperties + & ThisType>; + +interface ComponentOptionsProperties { + data: Data; +>data : Data + + render(): unknown; +>render : () => unknown +} + +interface Instance { + get(name: K): unknown; +>get : (name: K) => unknown +>name : K +} + +declare var Moon: { +>Moon : (options?: ConstructorOptions | undefined) => Instance + + (options?: ConstructorOptions): Instance; +>options : ConstructorOptions | undefined + +}; + +const r2 = Moon({ +>r2 : Instance<{ msg: string; }> +>Moon({ data: { msg: "" }, render() { const h = (x: unknown) => x; return h(this.get("msg")); },}) : Instance<{ msg: string; }> +>Moon : (options?: ConstructorOptions | undefined) => Instance +>{ data: { msg: "" }, render() { const h = (x: unknown) => x; return h(this.get("msg")); },} : { data: { msg: string; }; render(): unknown; } + + data: { msg: "" }, +>data : { msg: string; } +>{ msg: "" } : { msg: string; } +>msg : string +>"" : "" + + render() { +>render : () => unknown + + const h = (x: unknown) => x; +>h : (x: unknown) => unknown +>(x: unknown) => x : (x: unknown) => unknown +>x : unknown +>x : unknown + + return h(this.get("msg")); +>h(this.get("msg")) : unknown +>h : (x: unknown) => unknown +>this.get("msg") : unknown +>this.get : (name: K) => unknown +>this : Instance<{ msg: string; }> +>get : (name: K) => unknown +>"msg" : "msg" + + }, +}); + diff --git a/tests/cases/compiler/multipleInferenceContexts.ts b/tests/cases/compiler/multipleInferenceContexts.ts new file mode 100644 index 00000000000..edda25beb36 --- /dev/null +++ b/tests/cases/compiler/multipleInferenceContexts.ts @@ -0,0 +1,26 @@ +// @strict: true + +type ConstructorOptions = + & ComponentOptionsProperties + & ThisType>; + +interface ComponentOptionsProperties { + data: Data; + render(): unknown; +} + +interface Instance { + get(name: K): unknown; +} + +declare var Moon: { + (options?: ConstructorOptions): Instance; +}; + +const r2 = Moon({ + data: { msg: "" }, + render() { + const h = (x: unknown) => x; + return h(this.get("msg")); + }, +});