Skip to content

Commit c23059a

Browse files
authored
feat: Support ternary expressions in void contexts (#2060)
1 parent 78d40b0 commit c23059a

File tree

4 files changed

+227
-18
lines changed

4 files changed

+227
-18
lines changed

src/compiler.ts

+25-13
Original file line numberDiff line numberDiff line change
@@ -9212,20 +9212,32 @@ export class Compiler extends DiagnosticEmitter {
92129212
var ifElseExpr = this.compileExpression(ifElse, ctxType == Type.auto ? ifThenType : ctxType);
92139213
var ifElseType = this.currentType;
92149214

9215-
var commonType = Type.commonDenominator(ifThenType, ifElseType, false);
9216-
if (!commonType) {
9217-
this.error(
9218-
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
9219-
ifElse.range, ifElseType.toString(), ifThenType.toString()
9220-
);
9221-
this.currentType = ctxType;
9222-
return module.unreachable();
9215+
if (ctxType == Type.void) { // values, including type mismatch, are irrelevant
9216+
if (ifThenType != Type.void) {
9217+
ifThenExpr = module.drop(ifThenExpr);
9218+
ifThenType = Type.void;
9219+
}
9220+
if (ifElseType != Type.void) {
9221+
ifElseExpr = module.drop(ifElseExpr);
9222+
ifElseType = Type.void;
9223+
}
9224+
this.currentType = Type.void;
9225+
} else {
9226+
let commonType = Type.commonDenominator(ifThenType, ifElseType, false);
9227+
if (!commonType) {
9228+
this.error(
9229+
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
9230+
ifElse.range, ifElseType.toString(), ifThenType.toString()
9231+
);
9232+
this.currentType = ctxType;
9233+
return module.unreachable();
9234+
}
9235+
ifThenExpr = this.convertExpression(ifThenExpr, ifThenType, commonType, false, ifThen);
9236+
ifThenType = commonType;
9237+
ifElseExpr = this.convertExpression(ifElseExpr, ifElseType, commonType, false, ifElse);
9238+
ifElseType = commonType;
9239+
this.currentType = commonType;
92239240
}
9224-
ifThenExpr = this.convertExpression(ifThenExpr, ifThenType, commonType, false, ifThen);
9225-
ifThenType = commonType;
9226-
ifElseExpr = this.convertExpression(ifElseExpr, ifElseType, commonType, false, ifElse);
9227-
ifElseType = commonType;
9228-
this.currentType = commonType;
92299241

92309242
ifThenFlow.freeScopedLocals();
92319243
ifElseFlow.freeScopedLocals();

tests/compiler/ternary.optimized.wat

+80-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,91 @@
11
(module
2+
(type $none_=>_none (func))
23
(type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
3-
(memory $0 0)
4+
(type $i32_=>_none (func (param i32)))
5+
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
6+
(type $i32_i32_=>_none (func (param i32 i32)))
7+
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
8+
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 17452))
9+
(memory $0 1)
10+
(data (i32.const 1036) "\1c")
11+
(data (i32.const 1048) "\01\00\00\00\02\00\00\00a")
12+
(table $0 1 funcref)
413
(export "test" (func $ternary/test))
14+
(export "testDropWithTypeMismatch" (func $ternary/testDropWithTypeMismatch))
515
(export "memory" (memory $0))
16+
(export "testVoidInclTypeMismatch" (func $export:ternary/testVoidInclTypeMismatch))
617
(func $ternary/test (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
718
local.get $1
819
local.get $2
920
local.get $0
1021
select
1122
)
23+
(func $ternary/testDropWithTypeMismatch (param $0 i32)
24+
global.get $~lib/memory/__stack_pointer
25+
i32.const 4
26+
i32.sub
27+
global.set $~lib/memory/__stack_pointer
28+
global.get $~lib/memory/__stack_pointer
29+
i32.const 1068
30+
i32.lt_s
31+
if
32+
i32.const 17472
33+
i32.const 17520
34+
i32.const 1
35+
i32.const 1
36+
call $~lib/builtins/abort
37+
unreachable
38+
end
39+
global.get $~lib/memory/__stack_pointer
40+
local.tee $0
41+
i32.const 0
42+
i32.store
43+
local.get $0
44+
i32.const 1056
45+
i32.store
46+
local.get $0
47+
i32.const 4
48+
i32.add
49+
global.set $~lib/memory/__stack_pointer
50+
)
51+
(func $export:ternary/testVoidInclTypeMismatch (param $0 i32) (param $1 i32)
52+
global.get $~lib/memory/__stack_pointer
53+
i32.const 4
54+
i32.sub
55+
global.set $~lib/memory/__stack_pointer
56+
global.get $~lib/memory/__stack_pointer
57+
i32.const 1068
58+
i32.lt_s
59+
if
60+
i32.const 17472
61+
i32.const 17520
62+
i32.const 1
63+
i32.const 1
64+
call $~lib/builtins/abort
65+
unreachable
66+
end
67+
global.get $~lib/memory/__stack_pointer
68+
local.get $1
69+
i32.store
70+
local.get $1
71+
i32.load
72+
call_indirect $0 (type $none_=>_none)
73+
local.get $0
74+
if
75+
local.get $1
76+
i32.load
77+
call_indirect $0 (type $none_=>_none)
78+
end
79+
local.get $0
80+
i32.eqz
81+
if
82+
local.get $1
83+
i32.load
84+
call_indirect $0 (type $none_=>_none)
85+
end
86+
global.get $~lib/memory/__stack_pointer
87+
i32.const 4
88+
i32.add
89+
global.set $~lib/memory/__stack_pointer
90+
)
1291
)

tests/compiler/ternary.ts

+12
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,15 @@ a = (0 ? unreachable() : 1) ? 1 : unreachable();
1111
export function test(x: i32, y: i32, z: i32): i32 {
1212
return x ? y : z;
1313
}
14+
15+
export function testDropWithTypeMismatch(cond: bool): void {
16+
var x = 1;
17+
var y = "a";
18+
cond ? x : y;
19+
}
20+
21+
export function testVoidInclTypeMismatch(cond: bool, nop: () => void): void {
22+
cond ? nop() : nop();
23+
cond ? nop() : true;
24+
cond ? true : nop();
25+
}

tests/compiler/ternary.untouched.wat

+110-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
(module
22
(type $none_=>_none (func))
3+
(type $i32_i32_=>_none (func (param i32 i32)))
34
(type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
5+
(type $i32_=>_none (func (param i32)))
6+
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
7+
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
48
(global $ternary/a (mut i32) (i32.const 0))
5-
(global $~lib/memory/__data_end i32 (i32.const 8))
6-
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392))
7-
(global $~lib/memory/__heap_base i32 (i32.const 16392))
8-
(memory $0 0)
9+
(global $~argumentsLength (mut i32) (i32.const 0))
10+
(global $~lib/memory/__data_end i32 (i32.const 44))
11+
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16428))
12+
(global $~lib/memory/__heap_base i32 (i32.const 16428))
13+
(memory $0 1)
14+
(data (i32.const 12) "\1c\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\02\00\00\00a\00\00\00\00\00\00\00\00\00\00\00")
915
(table $0 1 funcref)
1016
(elem $0 (i32.const 1))
1117
(export "test" (func $ternary/test))
18+
(export "testDropWithTypeMismatch" (func $ternary/testDropWithTypeMismatch))
1219
(export "memory" (memory $0))
20+
(export "testVoidInclTypeMismatch" (func $export:ternary/testVoidInclTypeMismatch))
1321
(start $~start)
1422
(func $start:ternary
1523
i32.const 1
@@ -33,7 +41,105 @@
3341
local.get $2
3442
end
3543
)
44+
(func $ternary/testDropWithTypeMismatch (param $0 i32)
45+
(local $1 i32)
46+
(local $2 i32)
47+
global.get $~lib/memory/__stack_pointer
48+
i32.const 4
49+
i32.sub
50+
global.set $~lib/memory/__stack_pointer
51+
call $~stack_check
52+
global.get $~lib/memory/__stack_pointer
53+
i32.const 0
54+
i32.store
55+
i32.const 1
56+
local.set $1
57+
global.get $~lib/memory/__stack_pointer
58+
i32.const 32
59+
local.tee $2
60+
i32.store
61+
local.get $0
62+
if
63+
local.get $1
64+
drop
65+
else
66+
local.get $2
67+
drop
68+
end
69+
global.get $~lib/memory/__stack_pointer
70+
i32.const 4
71+
i32.add
72+
global.set $~lib/memory/__stack_pointer
73+
)
74+
(func $ternary/testVoidInclTypeMismatch (param $0 i32) (param $1 i32)
75+
local.get $0
76+
if
77+
i32.const 0
78+
global.set $~argumentsLength
79+
local.get $1
80+
i32.load
81+
call_indirect $0 (type $none_=>_none)
82+
else
83+
i32.const 0
84+
global.set $~argumentsLength
85+
local.get $1
86+
i32.load
87+
call_indirect $0 (type $none_=>_none)
88+
end
89+
local.get $0
90+
if
91+
i32.const 0
92+
global.set $~argumentsLength
93+
local.get $1
94+
i32.load
95+
call_indirect $0 (type $none_=>_none)
96+
else
97+
i32.const 1
98+
drop
99+
end
100+
local.get $0
101+
if
102+
i32.const 1
103+
drop
104+
else
105+
i32.const 0
106+
global.set $~argumentsLength
107+
local.get $1
108+
i32.load
109+
call_indirect $0 (type $none_=>_none)
110+
end
111+
)
36112
(func $~start
37113
call $start:ternary
38114
)
115+
(func $~stack_check
116+
global.get $~lib/memory/__stack_pointer
117+
global.get $~lib/memory/__data_end
118+
i32.lt_s
119+
if
120+
i32.const 16448
121+
i32.const 16496
122+
i32.const 1
123+
i32.const 1
124+
call $~lib/builtins/abort
125+
unreachable
126+
end
127+
)
128+
(func $export:ternary/testVoidInclTypeMismatch (param $0 i32) (param $1 i32)
129+
global.get $~lib/memory/__stack_pointer
130+
i32.const 4
131+
i32.sub
132+
global.set $~lib/memory/__stack_pointer
133+
call $~stack_check
134+
global.get $~lib/memory/__stack_pointer
135+
local.get $1
136+
i32.store
137+
local.get $0
138+
local.get $1
139+
call $ternary/testVoidInclTypeMismatch
140+
global.get $~lib/memory/__stack_pointer
141+
i32.const 4
142+
i32.add
143+
global.set $~lib/memory/__stack_pointer
144+
)
39145
)

0 commit comments

Comments
 (0)