Skip to content

Commit de46123

Browse files
committed
fix let statements, prevent in scope nested closure calls
1 parent bca614d commit de46123

9 files changed

+171
-33
lines changed

Diff for: src/compiler.ts

+7
Original file line numberDiff line numberDiff line change
@@ -6548,6 +6548,13 @@ export class Compiler extends DiagnosticEmitter {
65486548
let nativeSizeType = this.options.nativeSizeType;
65496549
signature = assert(local.type.signatureReference);
65506550
if (local.type.is(TypeFlags.IN_SCOPE_CLOSURE)) {
6551+
if (this.currentFlow.parentFunction.parent.kind == ElementKind.FUNCTION) {
6552+
this.error(
6553+
DiagnosticCode.Not_implemented,
6554+
expression.expression.range
6555+
);
6556+
return module.unreachable();
6557+
}
65516558
// If we're calling a local we know to be a closure, then we must still be in the creator functions
65526559
// scope. Because of this, we should update the values of locals that are still available
65536560
return module.block(null, [

Diff for: src/program.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -3423,9 +3423,10 @@ export class Function extends TypedElement {
34233423
lookup(name: string): Element | null {
34243424
var locals = this.localsByName;
34253425
if (locals.has(name)) return assert(locals.get(name));
3426-
var parentResult = this.parent.lookup(name);
3427-
if (parentResult !== null && this.parent.kind == ElementKind.FUNCTION) {
3426+
if (this.parent.kind == ElementKind.FUNCTION) {
34283427
var parentFunction = <Function>this.parent;
3428+
var parentResult = parentFunction.flow.lookup(name);
3429+
if (parentResult === null) return null;
34293430
if (parentFunction.closedLocals.size > 0) { //TODO allow nested closure definitions
34303431
this.program.error(
34313432
DiagnosticCode.Not_implemented,
@@ -3445,7 +3446,7 @@ export class Function extends TypedElement {
34453446
return closedLocal;
34463447
}
34473448
}
3448-
return parentResult;
3449+
return this.parent.lookup(name);
34493450
}
34503451

34513452
// used by flows to keep track of temporary locals

Diff for: tests/compiler/closure-limitations.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"--runtime none"
44
],
55
"stderr": [
6-
"Cannot find name '$local0'.",
6+
"AS100: Not implemented.",
77
"AS100: Not implemented.",
88
"EOF"
99
]

Diff for: tests/compiler/closure-limitations.optimized.wat

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(module
2+
(memory $0 0)
3+
(export "memory" (memory $0))
4+
)

Diff for: tests/compiler/closure-limitations.ts

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
function testLet(): (value: i32) => i32 {
2-
let $local0 = 0;
3-
return function inner(value: i32) {
4-
return $local0;
5-
};
6-
}
7-
testLet();
8-
91
function closureWrites(): (value: i32) => i32 {
102
var $local0 = 0;
113
return function inner(value: i32) {
@@ -15,4 +7,16 @@ function closureWrites(): (value: i32) => i32 {
157
}
168
closureWrites();
179

10+
function inScopeNestedCalls(): (value: i32) => i32 {
11+
var x = 0;
12+
var f = (): i32 => {
13+
return x;
14+
}
15+
var p = (value: i32): i32 => {
16+
return f();
17+
}
18+
return p;
19+
}
20+
inScopeNestedCalls();
21+
1822
ERROR("EOF")

Diff for: tests/compiler/closure-limitations.untouched.wat

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
(module
2+
(memory $0 0)
3+
(table $0 1 funcref)
4+
(export "memory" (memory $0))
5+
)

Diff for: tests/compiler/closure.optimized.wat

+50-8
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
(data (i32.const 1136) "\1e\00\00\00\01\00\00\00\01\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00p\00u\00r\00e\00.\00t\00s")
2020
(data (i32.const 1184) "\14\00\00\00\01\00\00\00\01\00\00\00\14\00\00\00c\00l\00o\00s\00u\00r\00e\00.\00t\00s")
2121
(data (i32.const 1232) "\03\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 ")
22-
(table $0 9 funcref)
23-
(elem (i32.const 1) $closure/testParam~inner $closure/testParam~inner $closure/complexCreateClosure~anonymous|0 $closure/complexCreateClosure~anonymous|1 $closure/nestedExecutionTest~anonymous|0 $closure/createClosure~anonymous|0 $closure/runInline~anonymous|0 $closure/returnOverBoundary~anonymous|0~nonClosure)
22+
(table $0 10 funcref)
23+
(elem (i32.const 1) $closure/testParam~inner $closure/testParam~inner $closure/testParam~inner $closure/complexCreateClosure~anonymous|0 $closure/complexCreateClosure~anonymous|1 $closure/nestedExecutionTest~anonymous|0 $closure/createClosure~anonymous|0 $closure/runInline~anonymous|0 $closure/returnOverBoundary~anonymous|0~nonClosure)
2424
(global $~lib/rt/tlsf/ROOT (mut i32) (i32.const 0))
2525
(global $~lib/rt/tlsf/collectLock (mut i32) (i32.const 0))
2626
(global $~lib/rt/__rtti_base i32 (i32.const 1232))
@@ -1192,14 +1192,14 @@
11921192
call $~lib/rt/tlsf/__alloc
11931193
call $~lib/rt/pure/__retain
11941194
local.tee $2
1195-
i32.const 3
1195+
i32.const 4
11961196
i32.store
11971197
i32.const 16
11981198
i32.const 0
11991199
call $~lib/rt/tlsf/__alloc
12001200
call $~lib/rt/pure/__retain
12011201
local.tee $0
1202-
i32.const 4
1202+
i32.const 5
12031203
i32.store
12041204
local.get $0
12051205
i32.const 11
@@ -1238,7 +1238,7 @@
12381238
call $~lib/rt/tlsf/__alloc
12391239
call $~lib/rt/pure/__retain
12401240
local.tee $0
1241-
i32.const 5
1241+
i32.const 6
12421242
i32.store
12431243
local.get $0
12441244
i32.const 1
@@ -1280,7 +1280,7 @@
12801280
call $~lib/rt/tlsf/__alloc
12811281
call $~lib/rt/pure/__retain
12821282
local.tee $0
1283-
i32.const 6
1283+
i32.const 7
12841284
i32.store
12851285
local.get $0
12861286
i32.const 1
@@ -1322,7 +1322,7 @@
13221322
i32.const 6
13231323
)
13241324
(func $closure/returnOverBoundary (result i32)
1325-
i32.const 8
1325+
i32.const 9
13261326
)
13271327
(func $start:closure
13281328
(local $0 i32)
@@ -1412,6 +1412,48 @@
14121412
i32.eq
14131413
select
14141414
call $~lib/rt/pure/__release
1415+
i32.const 8
1416+
i32.const 0
1417+
call $~lib/rt/tlsf/__alloc
1418+
call $~lib/rt/pure/__retain
1419+
local.tee $0
1420+
i32.const 3
1421+
i32.store
1422+
local.get $0
1423+
i32.const 0
1424+
i32.store offset=4
1425+
local.get $0
1426+
i32.const 4
1427+
i32.shr_s
1428+
i32.const -2147483648
1429+
i32.or
1430+
local.tee $1
1431+
i32.const -2147483648
1432+
i32.and
1433+
i32.const -2147483648
1434+
i32.eq
1435+
if (result i32)
1436+
local.get $1
1437+
i32.const 4
1438+
i32.shl
1439+
else
1440+
i32.const 0
1441+
end
1442+
call $~lib/rt/pure/__retain
1443+
drop
1444+
local.get $0
1445+
call $~lib/rt/pure/__release
1446+
local.get $1
1447+
i32.const 4
1448+
i32.shl
1449+
i32.const 0
1450+
local.get $1
1451+
i32.const -2147483648
1452+
i32.and
1453+
i32.const -2147483648
1454+
i32.eq
1455+
select
1456+
call $~lib/rt/pure/__release
14151457
call $closure/nestedExecutionTest
14161458
call $closure/createClosure
14171459
local.tee $0
@@ -1472,7 +1514,7 @@
14721514
call $~lib/rt/tlsf/__alloc
14731515
call $~lib/rt/pure/__retain
14741516
local.tee $0
1475-
i32.const 7
1517+
i32.const 8
14761518
i32.store
14771519
local.get $0
14781520
i32.const 1

Diff for: tests/compiler/closure.ts

+8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ function testVar(): (value: i32) => i32 {
1313
}
1414
testVar();
1515

16+
function testLet(): (value: i32) => i32 {
17+
let $local0 = 0;
18+
return function inner(value: i32) {
19+
return $local0;
20+
};
21+
}
22+
testLet();
23+
1624
function nestedExecutionTest(arg: i32): i32 {
1725
var x = 7;
1826
var f = complexCreateClosure(arg);

0 commit comments

Comments
 (0)