diff --git a/src/compiler.ts b/src/compiler.ts index 30d9fcbbdf..c7ea707feb 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6438,7 +6438,7 @@ export class Compiler extends DiagnosticEmitter { assert(typeParameterNodes), typeArgumentNodes, this.currentFlow.actualFunction.parent, - uniqueMap(this.currentFlow.contextualTypeArguments), + uniqueMap(this.currentFlow.contextualTypeArguments), // don't update expression ); } diff --git a/src/resolver.ts b/src/resolver.ts index e2d4b1dd25..f66307ba9e 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -306,7 +306,7 @@ export class Resolver extends DiagnosticEmitter { typeParameterNodes, typeArgumentNodes, ctxElement, - ctxTypes = uniqueMap(ctxTypes), // inherit + ctxTypes = uniqueMap(ctxTypes), // update node, reportMode ); @@ -644,7 +644,7 @@ export class Resolver extends DiagnosticEmitter { typeArgumentNodes: TypeNode[] | null, /** Contextual element. */ ctxElement: Element, - /** Contextual types, i.e. `T`. */ + /** Contextual types, i.e. `T`. Updated in place with the new set of contextual types. */ ctxTypes: Map = uniqueMap(), /** Alternative report node in case of empty type arguments. */ alternativeReportNode: Node | null = null, @@ -675,18 +675,20 @@ export class Resolver extends DiagnosticEmitter { return null; } var typeArguments = new Array(maxParameterCount); + var oldCtxTypes = uniqueMap(ctxTypes); + ctxTypes.clear(); for (let i = 0; i < maxParameterCount; ++i) { let type = i < argumentCount ? this.resolveType( // reports typeArgumentNodes![i], ctxElement, - ctxTypes, + oldCtxTypes, // update reportMode ) : this.resolveType( // reports assert(typeParameters[i].defaultType), ctxElement, - ctxTypes, + uniqueMap(ctxTypes), // don't update reportMode ); if (!type) return null; @@ -2796,7 +2798,7 @@ export class Resolver extends DiagnosticEmitter { assert(prototype.typeParameterNodes), typeArgumentNodes, ctxElement, - ctxTypes, + ctxTypes, // update reportNode, reportMode ); @@ -3272,7 +3274,7 @@ export class Resolver extends DiagnosticEmitter { assert(prototype.typeParameterNodes), // must be present if generic typeArgumentNodes, ctxElement, - ctxTypes, + ctxTypes, // update reportNode, reportMode ); diff --git a/tests/compiler/issues/1714.optimized.wat b/tests/compiler/issues/1714.optimized.wat new file mode 100644 index 0000000000..5b3ac4dd54 --- /dev/null +++ b/tests/compiler/issues/1714.optimized.wat @@ -0,0 +1,8 @@ +(module + (memory $0 1) + (data (i32.const 1036) ",") + (data (i32.const 1048) "\01\00\00\00\1c\00\00\00i\00s\00s\00u\00e\00s\00/\001\007\001\004\00.\00t\00s") + (data (i32.const 1084) "\1c") + (data (i32.const 1096) "\01\00\00\00\06\00\00\00i\003\002") + (export "memory" (memory $0)) +) diff --git a/tests/compiler/issues/1714.ts b/tests/compiler/issues/1714.ts new file mode 100644 index 0000000000..9dd08915ae --- /dev/null +++ b/tests/compiler/issues/1714.ts @@ -0,0 +1,18 @@ +function a_i64_i32(): bool { // T'=U=i64, U'=T=i32 + return sizeof() == sizeof(); +} + +function foo(): bool { // T=i32, U=i64 + return a_i64_i32() == true; +} + +assert(foo() == false); + +function bar(): string { // T1=f64, T2=i32 + if (isInteger()) { + return bar(); // T2'=T1=f64, T2'=T1=i32 + } + return nameof(); // iff T1 == i32 +} + +assert(bar() === "i32"); diff --git a/tests/compiler/issues/1714.untouched.wat b/tests/compiler/issues/1714.untouched.wat new file mode 100644 index 0000000000..ceb170e846 --- /dev/null +++ b/tests/compiler/issues/1714.untouched.wat @@ -0,0 +1,65 @@ +(module + (type $none_=>_i32 (func (result i32))) + (type $none_=>_none (func)) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 12) ",\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\1c\00\00\00i\00s\00s\00u\00e\00s\00/\001\007\001\004\00.\00t\00s\00") + (data (i32.const 60) "\1c\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\06\00\00\00i\003\002\00\00\00\00\00\00\00") + (table $0 1 funcref) + (global $~lib/memory/__data_end i32 (i32.const 92)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16476)) + (global $~lib/memory/__heap_base i32 (i32.const 16476)) + (export "memory" (memory $0)) + (start $~start) + (func $issues/1714/a_i64_i32 (result i32) + i32.const 8 + i32.const 4 + i32.eq + ) + (func $issues/1714/foo (result i32) + call $issues/1714/a_i64_i32 + i32.const 1 + i32.eq + ) + (func $issues/1714/bar (result i32) + i32.const 0 + drop + i32.const 80 + ) + (func $issues/1714/bar (result i32) + i32.const 1 + drop + call $issues/1714/bar + return + ) + (func $start:issues/1714 + call $issues/1714/foo + i32.const 0 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 9 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $issues/1714/bar + i32.const 80 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 18 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~start + call $start:issues/1714 + ) +)