gofront 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/backend/js/expressions.js +329 -58
- package/src/backend/js/index.js +90 -10
- package/src/backend/js/runtime.js +51 -9
- package/src/backend/js/statements.js +193 -84
- package/src/backend/js/type-info.js +123 -8
- package/src/backend/shared/fmt-types.js +30 -1
- package/src/backend/wasm/emit-builtins.js +250 -9
- package/src/backend/wasm/emit-exprs.js +63 -22
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +239 -205
- package/src/backend/wasm/emit.js +73 -26
- package/src/backend/wasm/globals.js +1 -0
- package/src/backend/wasm/index.js +8 -0
- package/src/backend/wasm/module-emitter.js +211 -57
- package/src/backend/wasm/monomorph.js +36 -2
- package/src/backend/wasm/natives.js +4 -0
- package/src/backend/wasm/types.js +32 -3
- package/src/backend/wasm/variadic.js +6 -1
- package/src/compiler.js +6 -1
- package/src/lexer/lexer.js +1 -0
- package/src/link/stdlib.js +1 -0
- package/src/link/type-names.js +72 -16
- package/src/lower/embedding.js +43 -15
- package/src/lower/fmt-formatters.js +38 -14
- package/src/lower/functions.js +223 -7
- package/src/lower/gen-types.js +21 -2
- package/src/lower/index.js +7 -1
- package/src/lower/json-codecs.js +114 -6
- package/src/parser/declarations.js +4 -2
- package/src/parser/expressions.js +25 -41
- package/src/parser/statements.js +107 -0
- package/src/parser/types.js +11 -0
- package/src/typechecker/assignability.js +94 -12
- package/src/typechecker/constants.js +124 -2
- package/src/typechecker/expressions.js +171 -17
- package/src/typechecker/index.js +158 -29
- package/src/typechecker/operand-text.js +1 -0
- package/src/typechecker/resolve.js +308 -39
- package/src/typechecker/statements.js +171 -21
- package/src/typechecker/types.js +84 -2
|
@@ -720,7 +720,95 @@ export class StmtsEmitter {
|
|
|
720
720
|
return idx;
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
+
// Stores the value `emitValue` pushes into the variable `name` that a range
|
|
724
|
+
// assignment (`for k, v = range m`) targets: a plain local, a boxed local
|
|
725
|
+
// (its address is taken or a closure mutates it), or a global. When the
|
|
726
|
+
// target is an interface, `valueGoType` is the Go type of the ranged
|
|
727
|
+
// element and the value is boxed into the interface representation;
|
|
728
|
+
// `emitValue` is then called with the wasm type of `valueGoType`.
|
|
729
|
+
_emitRangeAssignStore(name, info, emitValue, valueGoType = null) {
|
|
730
|
+
const local = this.resolveLocal(name);
|
|
731
|
+
const boxIface =
|
|
732
|
+
valueGoType && this._rangeStoreWType(name, info) === "anyref";
|
|
733
|
+
const pushValue = () => {
|
|
734
|
+
if (boxIface) this._emitRangeValueToAny(emitValue, valueGoType);
|
|
735
|
+
else emitValue();
|
|
736
|
+
};
|
|
737
|
+
if (!local) {
|
|
738
|
+
pushValue();
|
|
739
|
+
this.pushInstruction({ op: "global.set", index: info.index });
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (local.isBoxed) {
|
|
743
|
+
this.pushInstruction({ op: "local.get", index: local.index });
|
|
744
|
+
pushValue();
|
|
745
|
+
this.pushInstruction({
|
|
746
|
+
op: "struct.set",
|
|
747
|
+
typeIndex: local.boxInfo.typeIndex,
|
|
748
|
+
fieldIndex: 0,
|
|
749
|
+
});
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
pushValue();
|
|
753
|
+
this.pushInstruction({ op: "local.set", index: info.index });
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Pushes a ranged element of Go type `goType` as an interface value.
|
|
757
|
+
// `emitValue(wType)` pushes the element in the wasm type of `goType`; an
|
|
758
|
+
// element that is already an interface needs no boxing.
|
|
759
|
+
_emitRangeValueToAny(emitValue, goType) {
|
|
760
|
+
const wType = this.toWasmType(goType);
|
|
761
|
+
if (wType === "anyref") {
|
|
762
|
+
emitValue(wType);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
const name = `__rangeval$${this.tempCounter++}`;
|
|
766
|
+
const idx = this.allocLocal(name, wType, goType, true);
|
|
767
|
+
emitValue(wType);
|
|
768
|
+
this.pushInstruction({ op: "local.set", index: idx });
|
|
769
|
+
this.emitExpr(
|
|
770
|
+
{ kind: "Ident", name, _type: goType, _parTmp: true },
|
|
771
|
+
"anyref",
|
|
772
|
+
);
|
|
773
|
+
this.locals.delete(name);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// The wasm type of the value a range assignment stores into `info`: the
|
|
777
|
+
// box's field type when the target local is boxed.
|
|
778
|
+
_rangeStoreWType(name, info) {
|
|
779
|
+
const local = this.resolveLocal(name);
|
|
780
|
+
return local?.isBoxed ? local.boxInfo.wType : info.type;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// `for _, out[0] = range xs`: an index, selector or dereference target is
|
|
784
|
+
// not a variable the loop can store into directly. Each such target gets
|
|
785
|
+
// a hidden local that the loop writes (so conversions and interface
|
|
786
|
+
// boxing work as for a variable), and `_emitRangeBoxes` assigns it to the
|
|
787
|
+
// real target at the top of the body. Returns `lhs` with those targets
|
|
788
|
+
// replaced by identifiers of the hidden locals.
|
|
789
|
+
_bindRangeAssignTargets(lhs) {
|
|
790
|
+
return lhs.map((node) => {
|
|
791
|
+
if (!node || node.kind === "Ident" || !node._type) return node;
|
|
792
|
+
const name = `__rangetarget$${this.tempCounter++}`;
|
|
793
|
+
const wType = this.toWasmType(node._type);
|
|
794
|
+
this.allocLocal(name, wType, node._type, true);
|
|
795
|
+
if (!this._pendingRangeTargets) this._pendingRangeTargets = [];
|
|
796
|
+
this._pendingRangeTargets.push({ node, name, goType: node._type });
|
|
797
|
+
return { kind: "Ident", name, _type: node._type };
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
|
|
723
801
|
_emitRangeBoxes() {
|
|
802
|
+
const targets = this._pendingRangeTargets ?? [];
|
|
803
|
+
this._pendingRangeTargets = [];
|
|
804
|
+
for (const { node, name, goType } of targets) {
|
|
805
|
+
this._emitAssignSingle(
|
|
806
|
+
node,
|
|
807
|
+
{ kind: "Ident", name, _type: goType, _parTmp: true },
|
|
808
|
+
"=",
|
|
809
|
+
);
|
|
810
|
+
this.locals.delete(name);
|
|
811
|
+
}
|
|
724
812
|
const pending = this._pendingRangeBoxes ?? [];
|
|
725
813
|
this._pendingRangeBoxes = [];
|
|
726
814
|
for (const { name, idx, wType, goType } of pending) {
|
|
@@ -1350,21 +1438,28 @@ export class StmtsEmitter {
|
|
|
1350
1438
|
// is the declared type, not its underlying one: a defined string type is
|
|
1351
1439
|
// boxed apart from `string`, and `error` carries a method set.
|
|
1352
1440
|
_resolveTestTarget(t) {
|
|
1441
|
+
// A composite type-switch case (`case func(int) string:`) carries the
|
|
1442
|
+
// checker's type, which keys typed-nil markers like the boxed value.
|
|
1443
|
+
if (t?._assertType) return t._assertType;
|
|
1353
1444
|
if ((t?.kind !== "TypeName" && t?.kind !== "Ident") || !t.name) return t;
|
|
1354
1445
|
if (t.name === "nil" || t.name === "any" || t.name === "interface{}")
|
|
1355
1446
|
return t;
|
|
1356
1447
|
return this.mod.checker?.types?.get(t.name) ?? t;
|
|
1357
1448
|
}
|
|
1358
1449
|
|
|
1359
|
-
// A defined func
|
|
1360
|
-
// `
|
|
1450
|
+
// A defined func, map or array type lives in `any` as a box (so
|
|
1451
|
+
// `iter.Seq[int]` is not a plain `func(func(int) bool)`, `type M
|
|
1452
|
+
// map[string]int` keeps its name in `%T` and unhashable-key panics, and
|
|
1453
|
+
// `type A [2]int` is not a `[2]int` in a type switch).
|
|
1361
1454
|
_isMethodNamedRef(goType) {
|
|
1362
1455
|
const t = this._resolveTestTarget(goType);
|
|
1456
|
+
if (
|
|
1457
|
+
t &&
|
|
1458
|
+
(isArrayType(t, this.mod.checker) || isMapType(t, this.mod.checker))
|
|
1459
|
+
)
|
|
1460
|
+
return true;
|
|
1363
1461
|
if (t?.kind !== "named") return false;
|
|
1364
|
-
return (
|
|
1365
|
-
isFuncType(t, this.mod.checker) ||
|
|
1366
|
-
(t.methods?.size > 0 && isMapType(t, this.mod.checker))
|
|
1367
|
-
);
|
|
1462
|
+
return isFuncType(t, this.mod.checker);
|
|
1368
1463
|
}
|
|
1369
1464
|
|
|
1370
1465
|
_emitTypeTest(targetGoType) {
|
|
@@ -1423,35 +1518,27 @@ export class StmtsEmitter {
|
|
|
1423
1518
|
|
|
1424
1519
|
if (isSliceType(targetGoType, this.mod.checker)) {
|
|
1425
1520
|
const elem = this._getSliceElemType(targetGoType);
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
:
|
|
1429
|
-
if (sInfo) {
|
|
1430
|
-
this.pushInstruction({ op: "ref.test", typeIndex: sInfo.typeIndex });
|
|
1521
|
+
if (isTaggedSliceType(targetGoType, this.mod.checker)) {
|
|
1522
|
+
const tagged = this.mod.getTaggedSliceType(targetGoType, elem);
|
|
1523
|
+
this.pushInstruction({ op: "ref.test", typeIndex: tagged.typeIndex });
|
|
1431
1524
|
return;
|
|
1432
1525
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
this.
|
|
1526
|
+
const sInfo = this.mod.getSliceType(elem);
|
|
1527
|
+
if (sInfo) {
|
|
1528
|
+
// The unnamed slice type is the bare one, not a tagged subtype.
|
|
1529
|
+
const root = this.mod.getTaggedSliceRoot(sInfo);
|
|
1530
|
+
const tmp = this.acquireTemp("anyref");
|
|
1531
|
+
this.pushInstruction({ op: "local.tee", index: tmp });
|
|
1532
|
+
this.pushInstruction({ op: "ref.test", typeIndex: sInfo.typeIndex });
|
|
1533
|
+
this.pushInstruction({ op: "local.get", index: tmp });
|
|
1534
|
+
this.pushInstruction({ op: "ref.test", typeIndex: root.typeIndex });
|
|
1535
|
+
this.pushInstruction("i32.eqz");
|
|
1536
|
+
this.pushInstruction("i32.and");
|
|
1537
|
+
this.releaseTemp(tmp, "anyref");
|
|
1440
1538
|
return;
|
|
1441
1539
|
}
|
|
1442
1540
|
}
|
|
1443
1541
|
|
|
1444
|
-
// A map lives in `any` as its bare map struct.
|
|
1445
|
-
if (isMapType(targetGoType, this.mod.checker)) {
|
|
1446
|
-
const { keyType, valType } = getMapKeyValTypes(
|
|
1447
|
-
targetGoType,
|
|
1448
|
-
this.mod.checker,
|
|
1449
|
-
);
|
|
1450
|
-
const mInfo = this.mod.getMapType(keyType, valType);
|
|
1451
|
-
this._emitRefTestOrNil(targetGoType, mInfo.typeIndex);
|
|
1452
|
-
return;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
1542
|
// Scalar types
|
|
1456
1543
|
const box = this.mod.getIfaceBoxType(targetGoType);
|
|
1457
1544
|
if (box) {
|
|
@@ -1463,32 +1550,6 @@ export class StmtsEmitter {
|
|
|
1463
1550
|
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
1464
1551
|
}
|
|
1465
1552
|
|
|
1466
|
-
// `[3]int` and `[2]int` share one wasm array type, so the test also compares
|
|
1467
|
-
// the length.
|
|
1468
|
-
_emitArrayTypeTest(goType, aInfo) {
|
|
1469
|
-
let t = goType?._assertType ?? goType;
|
|
1470
|
-
for (let i = 0; i < 16 && t && t.kind !== "array"; i++)
|
|
1471
|
-
t = t.underlying ?? this.mod.checker?.types?.get(t.name);
|
|
1472
|
-
const size = typeof t?.size === "number" ? t.size : null;
|
|
1473
|
-
if (size === null) {
|
|
1474
|
-
this.pushInstruction({ op: "ref.test", typeIndex: aInfo.typeIndex });
|
|
1475
|
-
return;
|
|
1476
|
-
}
|
|
1477
|
-
const tmp = this.acquireTemp("anyref");
|
|
1478
|
-
this.pushInstruction({ op: "local.tee", index: tmp });
|
|
1479
|
-
this.pushInstruction({ op: "ref.test", typeIndex: aInfo.typeIndex });
|
|
1480
|
-
this.pushInstruction({ op: "if", blockType: "i32" });
|
|
1481
|
-
this.pushInstruction({ op: "local.get", index: tmp });
|
|
1482
|
-
this.pushInstruction({ op: "ref.cast", typeIndex: aInfo.typeIndex });
|
|
1483
|
-
this.pushInstruction("array.len");
|
|
1484
|
-
this.pushInstruction({ op: "i32.const", value: size });
|
|
1485
|
-
this.pushInstruction("i32.eq");
|
|
1486
|
-
this.pushInstruction("else");
|
|
1487
|
-
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1488
|
-
this.pushInstruction("end");
|
|
1489
|
-
this.releaseTemp(tmp, "anyref");
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
1553
|
// Whether the interface value on the stack holds a type implementing the
|
|
1493
1554
|
// non-empty interface: a `ref.test` over every implementing type (a typed
|
|
1494
1555
|
// nil `*S` marker included).
|
|
@@ -1616,28 +1677,6 @@ export class StmtsEmitter {
|
|
|
1616
1677
|
}
|
|
1617
1678
|
}
|
|
1618
1679
|
|
|
1619
|
-
if (isArrayType(targetGoType, this.mod.checker)) {
|
|
1620
|
-
const elem = this._getArrayElemType(targetGoType);
|
|
1621
|
-
const aInfo = this.mod.getArrayType(elem);
|
|
1622
|
-
if (aInfo) {
|
|
1623
|
-
this.pushInstruction({
|
|
1624
|
-
op: "ref.cast_null",
|
|
1625
|
-
typeIndex: aInfo.typeIndex,
|
|
1626
|
-
});
|
|
1627
|
-
return;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
if (isMapType(targetGoType, this.mod.checker)) {
|
|
1632
|
-
const { keyType, valType } = getMapKeyValTypes(
|
|
1633
|
-
targetGoType,
|
|
1634
|
-
this.mod.checker,
|
|
1635
|
-
);
|
|
1636
|
-
const mInfo = this.mod.getMapType(keyType, valType);
|
|
1637
|
-
this._emitRefCastOrNil(targetGoType, mInfo.typeIndex);
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1641
1680
|
// Scalar types
|
|
1642
1681
|
const box = this.mod.getIfaceBoxType(targetGoType);
|
|
1643
1682
|
if (box) {
|
|
@@ -2256,7 +2295,9 @@ export class StmtsEmitter {
|
|
|
2256
2295
|
const rangeExpr =
|
|
2257
2296
|
stmt.cond?.kind === "RangeExpr" ? stmt.cond : stmt.init.rhs[0];
|
|
2258
2297
|
const isAssign = stmt.init?.kind === "AssignStmt";
|
|
2259
|
-
const lhs =
|
|
2298
|
+
const lhs = isAssign
|
|
2299
|
+
? this._bindRangeAssignTargets(stmt.init.lhs)
|
|
2300
|
+
: (stmt.init?.lhs ?? []);
|
|
2260
2301
|
const iterExpr = rangeExpr.expr;
|
|
2261
2302
|
const iterType = iterExpr._type;
|
|
2262
2303
|
|
|
@@ -2323,21 +2364,21 @@ export class StmtsEmitter {
|
|
|
2323
2364
|
|
|
2324
2365
|
// Assign loop var if present
|
|
2325
2366
|
if (idxLocalInfo) {
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2367
|
+
const name = lhs[0].name;
|
|
2368
|
+
const wType = this._rangeStoreWType(name, idxLocalInfo);
|
|
2369
|
+
const idxGoType =
|
|
2370
|
+
iterType?.kind === "untyped"
|
|
2371
|
+
? { kind: "basic", name: "int" }
|
|
2372
|
+
: iterType;
|
|
2373
|
+
this._emitRangeAssignStore(
|
|
2374
|
+
name,
|
|
2375
|
+
idxLocalInfo,
|
|
2376
|
+
(want = wType) => {
|
|
2377
|
+
this.pushInstruction({ op: "local.get", index: idxTmp });
|
|
2378
|
+
if (want === "i64") this.pushInstruction("i64.extend_i32_s");
|
|
2379
|
+
},
|
|
2380
|
+
idxGoType,
|
|
2381
|
+
);
|
|
2341
2382
|
}
|
|
2342
2383
|
|
|
2343
2384
|
// Emit body
|
|
@@ -2448,38 +2489,30 @@ export class StmtsEmitter {
|
|
|
2448
2489
|
|
|
2449
2490
|
// Assign index variable
|
|
2450
2491
|
if (idxLocalInfo) {
|
|
2451
|
-
this.
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
op: "local.
|
|
2456
|
-
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
op: "global.set",
|
|
2461
|
-
index: idxLocalInfo.index,
|
|
2462
|
-
});
|
|
2463
|
-
}
|
|
2492
|
+
this._emitRangeAssignStore(
|
|
2493
|
+
lhs[0].name,
|
|
2494
|
+
idxLocalInfo,
|
|
2495
|
+
() => {
|
|
2496
|
+
this.pushInstruction({ op: "local.get", index: idxTmp });
|
|
2497
|
+
this.pushInstruction("i64.extend_i32_s");
|
|
2498
|
+
},
|
|
2499
|
+
{ kind: "basic", name: "int" },
|
|
2500
|
+
);
|
|
2464
2501
|
}
|
|
2465
2502
|
|
|
2466
2503
|
// Assign rune variable
|
|
2467
2504
|
if (valLocalInfo) {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
op: "local.
|
|
2475
|
-
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
op: "global.set",
|
|
2480
|
-
index: valLocalInfo.index,
|
|
2481
|
-
});
|
|
2482
|
-
}
|
|
2505
|
+
const name = lhs[1].name;
|
|
2506
|
+
const wType = this._rangeStoreWType(name, valLocalInfo);
|
|
2507
|
+
this._emitRangeAssignStore(
|
|
2508
|
+
name,
|
|
2509
|
+
valLocalInfo,
|
|
2510
|
+
(want = wType) => {
|
|
2511
|
+
this.pushInstruction({ op: "local.get", index: runeTmp });
|
|
2512
|
+
if (want === "i64") this.pushInstruction("i64.extend_i32_u");
|
|
2513
|
+
},
|
|
2514
|
+
{ kind: "basic", name: "int32" },
|
|
2515
|
+
);
|
|
2483
2516
|
}
|
|
2484
2517
|
|
|
2485
2518
|
// Body
|
|
@@ -2647,46 +2680,38 @@ export class StmtsEmitter {
|
|
|
2647
2680
|
|
|
2648
2681
|
// Assign key variable
|
|
2649
2682
|
if (keyLocalInfo) {
|
|
2650
|
-
this.
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
op: "global.set",
|
|
2665
|
-
index: keyLocalInfo.index,
|
|
2666
|
-
});
|
|
2667
|
-
}
|
|
2683
|
+
this._emitRangeAssignStore(
|
|
2684
|
+
lhs[0].name,
|
|
2685
|
+
keyLocalInfo,
|
|
2686
|
+
() => {
|
|
2687
|
+
this.pushInstruction({ op: "local.get", index: entryTmp });
|
|
2688
|
+
this.pushInstruction({
|
|
2689
|
+
op: "struct.get",
|
|
2690
|
+
typeIndex: mapInfo.entryTypeIndex,
|
|
2691
|
+
fieldIndex: 0,
|
|
2692
|
+
});
|
|
2693
|
+
this._emitCopyMapEntry(keyType, mapInfo.keyWType);
|
|
2694
|
+
},
|
|
2695
|
+
keyType,
|
|
2696
|
+
);
|
|
2668
2697
|
}
|
|
2669
2698
|
|
|
2670
2699
|
// Assign val variable
|
|
2671
2700
|
if (valLocalInfo) {
|
|
2672
|
-
this.
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
op: "global.set",
|
|
2687
|
-
index: valLocalInfo.index,
|
|
2688
|
-
});
|
|
2689
|
-
}
|
|
2701
|
+
this._emitRangeAssignStore(
|
|
2702
|
+
lhs[1].name,
|
|
2703
|
+
valLocalInfo,
|
|
2704
|
+
() => {
|
|
2705
|
+
this.pushInstruction({ op: "local.get", index: entryTmp });
|
|
2706
|
+
this.pushInstruction({
|
|
2707
|
+
op: "struct.get",
|
|
2708
|
+
typeIndex: mapInfo.entryTypeIndex,
|
|
2709
|
+
fieldIndex: 1,
|
|
2710
|
+
});
|
|
2711
|
+
this._emitCopyMapEntry(valType, mapInfo.valWType);
|
|
2712
|
+
},
|
|
2713
|
+
valType,
|
|
2714
|
+
);
|
|
2690
2715
|
}
|
|
2691
2716
|
|
|
2692
2717
|
// Body
|
|
@@ -2860,52 +2885,50 @@ export class StmtsEmitter {
|
|
|
2860
2885
|
|
|
2861
2886
|
// Assign idx
|
|
2862
2887
|
if (idxLocalInfo) {
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
}
|
|
2888
|
+
const name = lhs[0].name;
|
|
2889
|
+
const wType = this._rangeStoreWType(name, idxLocalInfo);
|
|
2890
|
+
this._emitRangeAssignStore(
|
|
2891
|
+
name,
|
|
2892
|
+
idxLocalInfo,
|
|
2893
|
+
(want = wType) => {
|
|
2894
|
+
this.pushInstruction({ op: "local.get", index: idxTmp });
|
|
2895
|
+
if (want === "i64") this.pushInstruction("i64.extend_i32_s");
|
|
2896
|
+
},
|
|
2897
|
+
{ kind: "basic", name: "int" },
|
|
2898
|
+
);
|
|
2875
2899
|
}
|
|
2876
2900
|
|
|
2877
2901
|
// Assign val
|
|
2878
2902
|
if (valLocalInfo) {
|
|
2879
|
-
this.
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
}
|
|
2903
|
+
this._emitRangeAssignStore(
|
|
2904
|
+
lhs[1].name,
|
|
2905
|
+
valLocalInfo,
|
|
2906
|
+
() => {
|
|
2907
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
2908
|
+
this.pushInstruction({ op: "local.get", index: offTmp });
|
|
2909
|
+
this.pushInstruction({ op: "local.get", index: idxTmp });
|
|
2910
|
+
this.pushInstruction("i32.add");
|
|
2911
|
+
this.pushInstruction({
|
|
2912
|
+
op: "array.get",
|
|
2913
|
+
typeIndex: arrInfo.typeIndex,
|
|
2914
|
+
});
|
|
2915
|
+
if (
|
|
2916
|
+
isStructType(elemGoType, this.mod.checker, this.mod) &&
|
|
2917
|
+
!isPointerToStruct(elemGoType, this.mod.checker, this.mod)
|
|
2918
|
+
) {
|
|
2919
|
+
const sInfo = this._resolveStructInfo({ _type: elemGoType });
|
|
2920
|
+
if (sInfo) {
|
|
2921
|
+
this.emitCloneStruct(sInfo, arrInfo.elemWType);
|
|
2922
|
+
}
|
|
2923
|
+
} else if (
|
|
2924
|
+
elemGoType?.kind !== "pointer" &&
|
|
2925
|
+
isArrayType(elemGoType, this.mod.checker)
|
|
2926
|
+
) {
|
|
2927
|
+
this.emitCopyArray(elemGoType);
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
elemGoType,
|
|
2931
|
+
);
|
|
2909
2932
|
}
|
|
2910
2933
|
|
|
2911
2934
|
// Body
|
|
@@ -3627,13 +3650,24 @@ export class StmtsEmitter {
|
|
|
3627
3650
|
this.pushInstruction("i64.eq");
|
|
3628
3651
|
this.pushInstruction({ op: "if", blockType: "void" });
|
|
3629
3652
|
if (target.role !== "break" || stmt.label !== target.label) {
|
|
3630
|
-
|
|
3653
|
+
const isContinue = target.role === "continue";
|
|
3654
|
+
const inScope = this.controlStack.some(
|
|
3655
|
+
(c) => c.label === target.label && c.role === target.role,
|
|
3656
|
+
);
|
|
3657
|
+
if (
|
|
3658
|
+
!inScope &&
|
|
3659
|
+
isContinue &&
|
|
3660
|
+
this.funcDecl._isYieldClosure &&
|
|
3661
|
+
target.label === this.funcDecl._forStmt?.label
|
|
3662
|
+
) {
|
|
3663
|
+
// `continue L` where L labels the iterator loop whose body this
|
|
3664
|
+
// yield closure is: resume that iterator.
|
|
3665
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
3666
|
+
this.pushInstruction({ op: "return" });
|
|
3667
|
+
} else if (!inScope && this.funcDecl._isYieldClosure) {
|
|
3631
3668
|
this._propagateYieldExit(BigInt(target.tag));
|
|
3632
3669
|
} else {
|
|
3633
|
-
const depth = this.resolveBranchDepth(
|
|
3634
|
-
target.label,
|
|
3635
|
-
target.role === "continue",
|
|
3636
|
-
);
|
|
3670
|
+
const depth = this.resolveBranchDepth(target.label, isContinue);
|
|
3637
3671
|
this.pushInstruction({ op: "br", depth });
|
|
3638
3672
|
}
|
|
3639
3673
|
}
|
|
@@ -3758,7 +3792,7 @@ export class StmtsEmitter {
|
|
|
3758
3792
|
}
|
|
3759
3793
|
|
|
3760
3794
|
emitBranchStmt(stmt) {
|
|
3761
|
-
const alias = stmt.label && this.
|
|
3795
|
+
const alias = stmt.label && this._stackedLabelAlias(stmt.label);
|
|
3762
3796
|
if (alias) stmt = { ...stmt, label: alias };
|
|
3763
3797
|
if (this._tryEmitYieldBranch(stmt)) return;
|
|
3764
3798
|
const isContinue = stmt.keyword === "continue";
|