Skip to content

Commit 07b9fb6

Browse files
authored
fix: Fix type confusion when resolving nested generics (#1762)
1 parent cd6f9f4 commit 07b9fb6

File tree

5 files changed

+100
-7
lines changed

5 files changed

+100
-7
lines changed

src/compiler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6438,7 +6438,7 @@ export class Compiler extends DiagnosticEmitter {
64386438
assert(typeParameterNodes),
64396439
typeArgumentNodes,
64406440
this.currentFlow.actualFunction.parent,
6441-
uniqueMap<string,Type>(this.currentFlow.contextualTypeArguments),
6441+
uniqueMap<string,Type>(this.currentFlow.contextualTypeArguments), // don't update
64426442
expression
64436443
);
64446444
}

src/resolver.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ export class Resolver extends DiagnosticEmitter {
306306
typeParameterNodes,
307307
typeArgumentNodes,
308308
ctxElement,
309-
ctxTypes = uniqueMap(ctxTypes), // inherit
309+
ctxTypes = uniqueMap(ctxTypes), // update
310310
node,
311311
reportMode
312312
);
@@ -644,7 +644,7 @@ export class Resolver extends DiagnosticEmitter {
644644
typeArgumentNodes: TypeNode[] | null,
645645
/** Contextual element. */
646646
ctxElement: Element,
647-
/** Contextual types, i.e. `T`. */
647+
/** Contextual types, i.e. `T`. Updated in place with the new set of contextual types. */
648648
ctxTypes: Map<string,Type> = uniqueMap<string,Type>(),
649649
/** Alternative report node in case of empty type arguments. */
650650
alternativeReportNode: Node | null = null,
@@ -675,18 +675,20 @@ export class Resolver extends DiagnosticEmitter {
675675
return null;
676676
}
677677
var typeArguments = new Array<Type>(maxParameterCount);
678+
var oldCtxTypes = uniqueMap<string,Type>(ctxTypes);
679+
ctxTypes.clear();
678680
for (let i = 0; i < maxParameterCount; ++i) {
679681
let type = i < argumentCount
680682
? this.resolveType( // reports
681683
typeArgumentNodes![i],
682684
ctxElement,
683-
ctxTypes,
685+
oldCtxTypes, // update
684686
reportMode
685687
)
686688
: this.resolveType( // reports
687689
assert(typeParameters[i].defaultType),
688690
ctxElement,
689-
ctxTypes,
691+
uniqueMap<string,Type>(ctxTypes), // don't update
690692
reportMode
691693
);
692694
if (!type) return null;
@@ -2796,7 +2798,7 @@ export class Resolver extends DiagnosticEmitter {
27962798
assert(prototype.typeParameterNodes),
27972799
typeArgumentNodes,
27982800
ctxElement,
2799-
ctxTypes,
2801+
ctxTypes, // update
28002802
reportNode,
28012803
reportMode
28022804
);
@@ -3272,7 +3274,7 @@ export class Resolver extends DiagnosticEmitter {
32723274
assert(prototype.typeParameterNodes), // must be present if generic
32733275
typeArgumentNodes,
32743276
ctxElement,
3275-
ctxTypes,
3277+
ctxTypes, // update
32763278
reportNode,
32773279
reportMode
32783280
);
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
(module
2+
(memory $0 1)
3+
(data (i32.const 1036) ",")
4+
(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")
5+
(data (i32.const 1084) "\1c")
6+
(data (i32.const 1096) "\01\00\00\00\06\00\00\00i\003\002")
7+
(export "memory" (memory $0))
8+
)

tests/compiler/issues/1714.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
function a_i64_i32<T,U>(): bool { // T'=U=i64, U'=T=i32
2+
return sizeof<T>() == sizeof<U>();
3+
}
4+
5+
function foo<T,U>(): bool { // T=i32, U=i64
6+
return a_i64_i32<U,T>() == true;
7+
}
8+
9+
assert(foo<i32, i64>() == false);
10+
11+
function bar<T1,T2>(): string { // T1=f64, T2=i32
12+
if (isInteger<T2>()) {
13+
return bar<T2,T1>(); // T2'=T1=f64, T2'=T1=i32
14+
}
15+
return nameof<T1>(); // iff T1 == i32
16+
}
17+
18+
assert(bar<f64, i32>() === "i32");
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
(module
2+
(type $none_=>_i32 (func (result i32)))
3+
(type $none_=>_none (func))
4+
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
5+
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
6+
(memory $0 1)
7+
(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")
8+
(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")
9+
(table $0 1 funcref)
10+
(global $~lib/memory/__data_end i32 (i32.const 92))
11+
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16476))
12+
(global $~lib/memory/__heap_base i32 (i32.const 16476))
13+
(export "memory" (memory $0))
14+
(start $~start)
15+
(func $issues/1714/a_i64_i32<i64,i32> (result i32)
16+
i32.const 8
17+
i32.const 4
18+
i32.eq
19+
)
20+
(func $issues/1714/foo<i32,i64> (result i32)
21+
call $issues/1714/a_i64_i32<i64,i32>
22+
i32.const 1
23+
i32.eq
24+
)
25+
(func $issues/1714/bar<i32,f64> (result i32)
26+
i32.const 0
27+
drop
28+
i32.const 80
29+
)
30+
(func $issues/1714/bar<f64,i32> (result i32)
31+
i32.const 1
32+
drop
33+
call $issues/1714/bar<i32,f64>
34+
return
35+
)
36+
(func $start:issues/1714
37+
call $issues/1714/foo<i32,i64>
38+
i32.const 0
39+
i32.eq
40+
i32.eqz
41+
if
42+
i32.const 0
43+
i32.const 32
44+
i32.const 9
45+
i32.const 1
46+
call $~lib/builtins/abort
47+
unreachable
48+
end
49+
call $issues/1714/bar<f64,i32>
50+
i32.const 80
51+
i32.eq
52+
i32.eqz
53+
if
54+
i32.const 0
55+
i32.const 32
56+
i32.const 18
57+
i32.const 1
58+
call $~lib/builtins/abort
59+
unreachable
60+
end
61+
)
62+
(func $~start
63+
call $start:issues/1714
64+
)
65+
)

0 commit comments

Comments
 (0)