gofront 1.7.0 → 1.8.0
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 +13 -13
- package/package.json +8 -37
- package/src/backend/js/expressions.js +1341 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +375 -57
- package/src/backend/js/runtime.js +1460 -133
- package/src/backend/js/statements.js +900 -86
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +2 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +8 -3
- package/src/backend/js/stdlib/json.js +247 -52
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +10 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +436 -80
- package/src/backend/wasm/emit-builtins.js +303 -13
- package/src/backend/wasm/emit-exprs.js +1397 -203
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +512 -77
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +0 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +200 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +107 -269
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +176 -32
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +69 -9
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +176 -17
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +931 -122
- package/src/typechecker/index.js +459 -67
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +451 -56
- package/src/typechecker/statements.js +90 -9
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +322 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +149 -25
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -3,10 +3,16 @@
|
|
|
3
3
|
// call expression dispatch (static, method, closure, package).
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
+
anonIfaceName,
|
|
6
7
|
getMapKeyValTypes,
|
|
7
8
|
isArrayType,
|
|
9
|
+
isBoolGoType,
|
|
10
|
+
isComplex,
|
|
11
|
+
isComplex64,
|
|
8
12
|
isMapType,
|
|
9
13
|
isNonEmptyInterface,
|
|
14
|
+
isScalarType,
|
|
15
|
+
isSigned,
|
|
10
16
|
isSliceType,
|
|
11
17
|
isStringType,
|
|
12
18
|
isStructType,
|
|
@@ -228,7 +234,12 @@ export class BuiltinsEmitter {
|
|
|
228
234
|
this.emitPanic("runtime error: makeslice: len out of range");
|
|
229
235
|
this.pushInstruction("end");
|
|
230
236
|
|
|
231
|
-
if (
|
|
237
|
+
if (
|
|
238
|
+
isStructType(elemGoType, this.mod.checker, this.mod) ||
|
|
239
|
+
isComplex(elemGoType) ||
|
|
240
|
+
(elemGoType?.kind !== "pointer" &&
|
|
241
|
+
isArrayType(elemGoType, this.mod.checker))
|
|
242
|
+
) {
|
|
232
243
|
const arrTmp = this.acquireTemp({
|
|
233
244
|
kind: "ref",
|
|
234
245
|
nullable: true,
|
|
@@ -302,6 +313,49 @@ export class BuiltinsEmitter {
|
|
|
302
313
|
}
|
|
303
314
|
}
|
|
304
315
|
|
|
316
|
+
_emitBuiltinNew(call) {
|
|
317
|
+
const targetType =
|
|
318
|
+
call._type?.base ??
|
|
319
|
+
(call.args[0]?.kind === "TypeExpr"
|
|
320
|
+
? call.args[0].type
|
|
321
|
+
: call.args[0]?._type) ??
|
|
322
|
+
call.args[0];
|
|
323
|
+
if (isStructType(targetType, this.mod.checker, this.mod)) {
|
|
324
|
+
let structInfo = this._resolveStructInfo({ _type: targetType });
|
|
325
|
+
if (!structInfo) {
|
|
326
|
+
const typeName =
|
|
327
|
+
targetType.kind === "named" ? targetType.name : targetType.name;
|
|
328
|
+
if (typeName) structInfo = this.mod.getStructType(typeName);
|
|
329
|
+
}
|
|
330
|
+
if (!structInfo) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Unknown struct in new: ${targetType.name ?? targetType}`,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
for (const f of structInfo.fields) {
|
|
336
|
+
this.emitZeroValue(f.goType, f.wType);
|
|
337
|
+
}
|
|
338
|
+
this.pushInstruction({
|
|
339
|
+
op: "struct.new",
|
|
340
|
+
typeIndex: structInfo.typeIndex,
|
|
341
|
+
});
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (isArrayType(targetType, this.mod.checker)) {
|
|
345
|
+
const wType = this.toWasmType(targetType);
|
|
346
|
+
this.emitZeroValue(targetType, wType);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const box = this.mod.getBoxType(targetType);
|
|
350
|
+
const valWType = this.toWasmType(targetType);
|
|
351
|
+
this.emitZeroValue(targetType, valWType);
|
|
352
|
+
this.pushInstruction({
|
|
353
|
+
op: "struct.new",
|
|
354
|
+
typeIndex: box.typeIndex,
|
|
355
|
+
typeName: box.name,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
305
359
|
// With `newLen` already computed: when it exceeds the old capacity, allocate
|
|
306
360
|
// a doubled (min 2, at least newLen) backing array and copy the old elements
|
|
307
361
|
// into it at offset 0; otherwise reuse the old array, offset and capacity.
|
|
@@ -374,6 +428,17 @@ export class BuiltinsEmitter {
|
|
|
374
428
|
this.pushInstruction("end");
|
|
375
429
|
}
|
|
376
430
|
|
|
431
|
+
// The source operand of `append(b, x...)` and `copy(b, x)`: a string
|
|
432
|
+
// (the only non-slice form Go allows) is converted to a fresh byte slice.
|
|
433
|
+
_emitSliceOperand(node, elemGoType, sliceWType) {
|
|
434
|
+
if (isStringType(node._type, this.mod.checker)) {
|
|
435
|
+
this.emitExpr(node, "externref");
|
|
436
|
+
this._emitStringToByteSlice({ kind: "slice", elem: elemGoType });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
this.emitExpr(node, sliceWType);
|
|
440
|
+
}
|
|
441
|
+
|
|
377
442
|
_emitBuiltinAppend(call) {
|
|
378
443
|
const { args } = call;
|
|
379
444
|
const sNode = args[0];
|
|
@@ -428,7 +493,7 @@ export class BuiltinsEmitter {
|
|
|
428
493
|
|
|
429
494
|
if (args.length === 2 && args[1]._spread) {
|
|
430
495
|
const s2Tmp = this.acquireTemp(sliceWType);
|
|
431
|
-
this.
|
|
496
|
+
this._emitSliceOperand(args[1], elemGoType, sliceWType);
|
|
432
497
|
this.pushInstruction({ op: "local.set", index: s2Tmp });
|
|
433
498
|
|
|
434
499
|
const s2ArrTmp = this.acquireTemp(arrWType);
|
|
@@ -487,7 +552,7 @@ export class BuiltinsEmitter {
|
|
|
487
552
|
this.pushInstruction("i32.add");
|
|
488
553
|
}
|
|
489
554
|
this.emitExpr(elemNode, arrInfo.elemWType);
|
|
490
|
-
this.
|
|
555
|
+
this._emitCopyIfValue(elemNode, elemGoType, arrInfo.elemWType);
|
|
491
556
|
this.pushInstruction({
|
|
492
557
|
op: "array.set",
|
|
493
558
|
typeIndex: arrInfo.typeIndex,
|
|
@@ -538,7 +603,7 @@ export class BuiltinsEmitter {
|
|
|
538
603
|
this.pushInstruction({ op: "local.set", index: dstTmp });
|
|
539
604
|
|
|
540
605
|
const srcTmp = this.acquireTemp(sliceWType);
|
|
541
|
-
this.
|
|
606
|
+
this._emitSliceOperand(srcNode, elemGoType, sliceWType);
|
|
542
607
|
this.pushInstruction({ op: "local.set", index: srcTmp });
|
|
543
608
|
|
|
544
609
|
const nTmp = this.acquireTemp("i32");
|
|
@@ -667,7 +732,7 @@ export class BuiltinsEmitter {
|
|
|
667
732
|
const arg = args[i];
|
|
668
733
|
const isLast = i === args.length - 1 && isPrintln;
|
|
669
734
|
const isBool =
|
|
670
|
-
arg._type
|
|
735
|
+
isBoolGoType(arg._type) ||
|
|
671
736
|
(arg.kind === "BasicLit" && arg.litKind === "BOOL");
|
|
672
737
|
const wType = toWasmType(arg._type, this.mod.checker);
|
|
673
738
|
this.emitExpr(arg, wType);
|
|
@@ -795,6 +860,136 @@ export class BuiltinsEmitter {
|
|
|
795
860
|
}
|
|
796
861
|
}
|
|
797
862
|
|
|
863
|
+
_emitBuiltinComplex(call, targetWasmType) {
|
|
864
|
+
const arg0 = call.args[0];
|
|
865
|
+
const arg1 = call.args[1];
|
|
866
|
+
const callType = call._type;
|
|
867
|
+
const is64 =
|
|
868
|
+
callType?.name === "complex64" ||
|
|
869
|
+
arg0._type?.name === "float32" ||
|
|
870
|
+
arg1._type?.name === "float32" ||
|
|
871
|
+
targetWasmType?.typeName === "$complex64";
|
|
872
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
873
|
+
const info = this.mod.getComplexType(complexName);
|
|
874
|
+
this.emitExpr(arg0, info.elemWType);
|
|
875
|
+
this.emitExpr(arg1, info.elemWType);
|
|
876
|
+
this.pushInstruction({
|
|
877
|
+
op: "struct.new",
|
|
878
|
+
typeIndex: info.typeIndex,
|
|
879
|
+
typeName: info.name,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
_emitBuiltinReal(call, targetWasmType) {
|
|
884
|
+
const arg = call.args[0];
|
|
885
|
+
const argType = arg._type ?? this._resolveExprGoType(arg);
|
|
886
|
+
const is64 = isComplex64(argType);
|
|
887
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
888
|
+
const info = this.mod.getComplexType(complexName);
|
|
889
|
+
const complexWType = {
|
|
890
|
+
kind: "ref",
|
|
891
|
+
nullable: true,
|
|
892
|
+
typeIndex: info.typeIndex,
|
|
893
|
+
typeName: info.name,
|
|
894
|
+
};
|
|
895
|
+
this.emitExpr(arg, complexWType);
|
|
896
|
+
this.pushInstruction({
|
|
897
|
+
op: "struct.get",
|
|
898
|
+
typeIndex: info.typeIndex,
|
|
899
|
+
typeName: info.name,
|
|
900
|
+
fieldIndex: 0,
|
|
901
|
+
});
|
|
902
|
+
if (targetWasmType && targetWasmType !== info.elemWType) {
|
|
903
|
+
if (info.elemWType === "f32" && targetWasmType === "f64") {
|
|
904
|
+
this.pushInstruction("f64.promote_f32");
|
|
905
|
+
} else if (info.elemWType === "f64" && targetWasmType === "f32") {
|
|
906
|
+
this.pushInstruction("f32.demote_f64");
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
_emitBuiltinImag(call, targetWasmType) {
|
|
912
|
+
const arg = call.args[0];
|
|
913
|
+
const argType = arg._type ?? this._resolveExprGoType(arg);
|
|
914
|
+
const is64 = isComplex64(argType);
|
|
915
|
+
const complexName = is64 ? "complex64" : "complex128";
|
|
916
|
+
const info = this.mod.getComplexType(complexName);
|
|
917
|
+
const complexWType = {
|
|
918
|
+
kind: "ref",
|
|
919
|
+
nullable: true,
|
|
920
|
+
typeIndex: info.typeIndex,
|
|
921
|
+
typeName: info.name,
|
|
922
|
+
};
|
|
923
|
+
this.emitExpr(arg, complexWType);
|
|
924
|
+
this.pushInstruction({
|
|
925
|
+
op: "struct.get",
|
|
926
|
+
typeIndex: info.typeIndex,
|
|
927
|
+
typeName: info.name,
|
|
928
|
+
fieldIndex: 1,
|
|
929
|
+
});
|
|
930
|
+
if (targetWasmType && targetWasmType !== info.elemWType) {
|
|
931
|
+
if (info.elemWType === "f32" && targetWasmType === "f64") {
|
|
932
|
+
this.pushInstruction("f64.promote_f32");
|
|
933
|
+
} else if (info.elemWType === "f64" && targetWasmType === "f32") {
|
|
934
|
+
this.pushInstruction("f32.demote_f64");
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// min/max fold left over the operands: floats use f32/f64.min/max (NaN
|
|
940
|
+
// propagates, -0 < +0), integers `select` on lt/gt, strings compare via the
|
|
941
|
+
// string import. A single operand is the result itself.
|
|
942
|
+
_emitBuiltinMinMax(call, targetWasmType) {
|
|
943
|
+
const isMin = call.func.name === "min";
|
|
944
|
+
const goType = call._type ?? this._resolveExprGoType(call.args[0]);
|
|
945
|
+
const wType =
|
|
946
|
+
goType?.kind === "untyped" && typeof targetWasmType === "string"
|
|
947
|
+
? targetWasmType
|
|
948
|
+
: toWasmType(goType, this.mod.checker);
|
|
949
|
+
const [first, ...rest] = call.args;
|
|
950
|
+
this.emitExpr(first, wType);
|
|
951
|
+
if (rest.length === 0) return;
|
|
952
|
+
const acc = this.acquireTemp(wType);
|
|
953
|
+
const next = this.acquireTemp(wType);
|
|
954
|
+
const isStr = isStringType(goType, this.mod.checker);
|
|
955
|
+
const isFloatType = wType === "f32" || wType === "f64";
|
|
956
|
+
const cmp = isMin ? "lt" : "gt";
|
|
957
|
+
for (const arg of rest) {
|
|
958
|
+
this.pushInstruction({ op: "local.set", index: acc });
|
|
959
|
+
this.emitExpr(arg, wType);
|
|
960
|
+
this.pushInstruction({ op: "local.set", index: next });
|
|
961
|
+
if (isFloatType) {
|
|
962
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
963
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
964
|
+
this.pushInstruction(`${wType}.${isMin ? "min" : "max"}`);
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (isStr) {
|
|
968
|
+
// next < acc (min) / next > acc (max) ? next : acc
|
|
969
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
970
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
971
|
+
this.pushInstruction({
|
|
972
|
+
op: "call",
|
|
973
|
+
funcIndex: this.mod.getStringCmpImportIndex(isMin ? "<" : ">"),
|
|
974
|
+
});
|
|
975
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
976
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
977
|
+
this.pushInstruction("else");
|
|
978
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
979
|
+
this.pushInstruction("end");
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
983
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
984
|
+
this.pushInstruction({ op: "local.get", index: next });
|
|
985
|
+
this.pushInstruction({ op: "local.get", index: acc });
|
|
986
|
+
this.pushInstruction(`${wType}.${cmp}_${isSigned(goType) ? "s" : "u"}`);
|
|
987
|
+
this.pushInstruction("select");
|
|
988
|
+
}
|
|
989
|
+
this.releaseTemp(next, wType);
|
|
990
|
+
this.releaseTemp(acc, wType);
|
|
991
|
+
}
|
|
992
|
+
|
|
798
993
|
_emitBuiltinCall(call, targetWasmType) {
|
|
799
994
|
const { func } = call;
|
|
800
995
|
if (func.kind !== "Ident") return false;
|
|
@@ -808,6 +1003,9 @@ export class BuiltinsEmitter {
|
|
|
808
1003
|
case "cap":
|
|
809
1004
|
this._emitBuiltinCap(call, targetWasmType);
|
|
810
1005
|
return true;
|
|
1006
|
+
case "new":
|
|
1007
|
+
this._emitBuiltinNew(call);
|
|
1008
|
+
return true;
|
|
811
1009
|
case "make":
|
|
812
1010
|
this._emitBuiltinMake(call);
|
|
813
1011
|
return true;
|
|
@@ -833,6 +1031,19 @@ export class BuiltinsEmitter {
|
|
|
833
1031
|
case "recover":
|
|
834
1032
|
this._emitBuiltinRecover(call, targetWasmType);
|
|
835
1033
|
return true;
|
|
1034
|
+
case "complex":
|
|
1035
|
+
this._emitBuiltinComplex(call, targetWasmType);
|
|
1036
|
+
return true;
|
|
1037
|
+
case "real":
|
|
1038
|
+
this._emitBuiltinReal(call, targetWasmType);
|
|
1039
|
+
return true;
|
|
1040
|
+
case "imag":
|
|
1041
|
+
this._emitBuiltinImag(call, targetWasmType);
|
|
1042
|
+
return true;
|
|
1043
|
+
case "min":
|
|
1044
|
+
case "max":
|
|
1045
|
+
this._emitBuiltinMinMax(call, targetWasmType);
|
|
1046
|
+
return true;
|
|
836
1047
|
default:
|
|
837
1048
|
return false;
|
|
838
1049
|
}
|
|
@@ -845,6 +1056,12 @@ export class BuiltinsEmitter {
|
|
|
845
1056
|
this.emitTestingCall(func, args);
|
|
846
1057
|
return true;
|
|
847
1058
|
}
|
|
1059
|
+
if (
|
|
1060
|
+
func.expr?.name &&
|
|
1061
|
+
(this.resolveLocal(func.expr.name) ||
|
|
1062
|
+
this.mod.resolveGlobal(func.expr.name))
|
|
1063
|
+
)
|
|
1064
|
+
return false;
|
|
848
1065
|
const pkgName = func.expr?.name;
|
|
849
1066
|
switch (pkgName) {
|
|
850
1067
|
case "math":
|
|
@@ -903,6 +1120,14 @@ export class BuiltinsEmitter {
|
|
|
903
1120
|
this.emitBytesNewReader(call, targetWasmType);
|
|
904
1121
|
return true;
|
|
905
1122
|
}
|
|
1123
|
+
if (func.field === "NewBuffer") {
|
|
1124
|
+
this.emitBytesNewBuffer(call, targetWasmType);
|
|
1125
|
+
return true;
|
|
1126
|
+
}
|
|
1127
|
+
if (func.field === "NewBufferString") {
|
|
1128
|
+
this.emitBytesNewBufferString(call, targetWasmType);
|
|
1129
|
+
return true;
|
|
1130
|
+
}
|
|
906
1131
|
this.emitBytesCall(func.field, args, targetWasmType);
|
|
907
1132
|
return true;
|
|
908
1133
|
case "path":
|
|
@@ -961,6 +1186,9 @@ export class BuiltinsEmitter {
|
|
|
961
1186
|
func.expr,
|
|
962
1187
|
args,
|
|
963
1188
|
targetWasmType,
|
|
1189
|
+
recvTypeName === "simd.Mask32x4" ||
|
|
1190
|
+
recvType?.underlying?.simd === "Mask32x4" ||
|
|
1191
|
+
recvType?.simd === "Mask32x4",
|
|
964
1192
|
);
|
|
965
1193
|
}
|
|
966
1194
|
if (
|
|
@@ -983,7 +1211,7 @@ export class BuiltinsEmitter {
|
|
|
983
1211
|
return true;
|
|
984
1212
|
}
|
|
985
1213
|
if (isNonEmptyInterface(recvType, this.mod.checker)) {
|
|
986
|
-
const ifaceName = recvTypeName ??
|
|
1214
|
+
const ifaceName = recvTypeName ?? anonIfaceName(recvType);
|
|
987
1215
|
const dispatchName = `__dispatch_${ifaceName}_${func.field}`;
|
|
988
1216
|
const targetFuncIdx = this.mod.resolveFuncIndex(dispatchName);
|
|
989
1217
|
if (targetFuncIdx !== null) {
|
|
@@ -994,7 +1222,7 @@ export class BuiltinsEmitter {
|
|
|
994
1222
|
const pType = targetParamTypes[i + 1] ?? null;
|
|
995
1223
|
const pGoType = paramGoTypes[i + 1] ?? null;
|
|
996
1224
|
this.emitExpr(args[i], pType);
|
|
997
|
-
this.
|
|
1225
|
+
this._emitCopyIfValue(args[i], pGoType, pType);
|
|
998
1226
|
}
|
|
999
1227
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
1000
1228
|
return true;
|
|
@@ -1016,14 +1244,20 @@ export class BuiltinsEmitter {
|
|
|
1016
1244
|
if (targetFuncIdx !== null) {
|
|
1017
1245
|
const recvWType = targetParamTypes[0] ?? null;
|
|
1018
1246
|
const recvGoType = this.mod.getFuncParamGoTypes(methodName)[0] ?? null;
|
|
1019
|
-
this.emitExpr(func
|
|
1020
|
-
|
|
1247
|
+
this.emitExpr(this._recvOperand(func, recvGoType), recvWType);
|
|
1248
|
+
// `p.M()` with a value receiver reads `*p`: a nil `p` panics here.
|
|
1249
|
+
if (
|
|
1250
|
+
recvGoType?.kind !== "pointer" &&
|
|
1251
|
+
isStructType(recvGoType, this.mod.checker, this.mod)
|
|
1252
|
+
)
|
|
1253
|
+
this._emitNilCheck(func.expr._type);
|
|
1254
|
+
this._emitCopyIfValue(func.expr, recvGoType, recvWType);
|
|
1021
1255
|
const paramGoTypes = this.mod.getFuncParamGoTypes(methodName);
|
|
1022
1256
|
for (let i = 0; i < args.length; i++) {
|
|
1023
1257
|
const pType = targetParamTypes[i + 1] ?? null;
|
|
1024
1258
|
const pGoType = paramGoTypes[i + 1] ?? null;
|
|
1025
1259
|
this.emitExpr(args[i], pType);
|
|
1026
|
-
this.
|
|
1260
|
+
this._emitCopyIfValue(args[i], pGoType, pType);
|
|
1027
1261
|
}
|
|
1028
1262
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
1029
1263
|
return true;
|
|
@@ -1032,6 +1266,43 @@ export class BuiltinsEmitter {
|
|
|
1032
1266
|
return false;
|
|
1033
1267
|
}
|
|
1034
1268
|
|
|
1269
|
+
// The receiver operand of a method call: `p.Get()` with a value receiver
|
|
1270
|
+
// and `p *N` (a named scalar or slice) passes `*p`.
|
|
1271
|
+
_recvOperand(func, recvGoType) {
|
|
1272
|
+
const t = func.expr._type;
|
|
1273
|
+
// A pointer receiver on `*p` gets `p` itself, so the method mutates *p.
|
|
1274
|
+
if (recvGoType?.kind === "pointer") {
|
|
1275
|
+
const pointer = this._structDerefPointer(func.expr);
|
|
1276
|
+
if (pointer) return pointer;
|
|
1277
|
+
}
|
|
1278
|
+
if (
|
|
1279
|
+
t?.kind === "pointer" &&
|
|
1280
|
+
recvGoType?.kind !== "pointer" &&
|
|
1281
|
+
(isScalarType(t.base, this.mod.checker, this.mod) ||
|
|
1282
|
+
isSliceType(t.base, this.mod.checker))
|
|
1283
|
+
)
|
|
1284
|
+
return { kind: "UnaryExpr", op: "*", operand: func.expr, _type: t.base };
|
|
1285
|
+
return this._ptrRecvOperand(func);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// `x.M()` with a pointer receiver on a named scalar value passes `&x`
|
|
1289
|
+
// (the typechecker boxed `x`).
|
|
1290
|
+
_ptrRecvOperand(func) {
|
|
1291
|
+
const t = func.expr._type;
|
|
1292
|
+
if (!func._type?._ptrRecv || t?.kind !== "named") return func.expr;
|
|
1293
|
+
if (
|
|
1294
|
+
!isScalarType(t, this.mod.checker, this.mod) &&
|
|
1295
|
+
!isSliceType(t, this.mod.checker)
|
|
1296
|
+
)
|
|
1297
|
+
return func.expr;
|
|
1298
|
+
return {
|
|
1299
|
+
kind: "UnaryExpr",
|
|
1300
|
+
op: "&",
|
|
1301
|
+
operand: func.expr,
|
|
1302
|
+
_type: { kind: "pointer", base: t },
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1035
1306
|
_emitStdlibReceiverMethod(
|
|
1036
1307
|
recvTypeName,
|
|
1037
1308
|
field,
|
|
@@ -1067,11 +1338,28 @@ export class BuiltinsEmitter {
|
|
|
1067
1338
|
this.emitDurationMethodCall(field, expr, args, targetWasmType);
|
|
1068
1339
|
return true;
|
|
1069
1340
|
}
|
|
1341
|
+
if (
|
|
1342
|
+
recvTypeName === "time.Month" ||
|
|
1343
|
+
recvTypeName === "time.Weekday" ||
|
|
1344
|
+
recvTypeName === "time.Location"
|
|
1345
|
+
) {
|
|
1346
|
+
this.emitTimeAuxMethodCall(
|
|
1347
|
+
recvTypeName,
|
|
1348
|
+
field,
|
|
1349
|
+
expr,
|
|
1350
|
+
args,
|
|
1351
|
+
targetWasmType,
|
|
1352
|
+
);
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1070
1355
|
if (recvTypeName === "io.LimitedReader") {
|
|
1071
1356
|
this.emitIoLimitedReaderMethodCall(field, expr, args, targetWasmType);
|
|
1072
1357
|
return true;
|
|
1073
1358
|
}
|
|
1074
|
-
if (
|
|
1359
|
+
if (
|
|
1360
|
+
(recvTypeName === "sync.Mutex" || recvTypeName === "sync.RWMutex") &&
|
|
1361
|
+
field !== "RLocker"
|
|
1362
|
+
) {
|
|
1075
1363
|
this.emitSyncMutexMethodCall(field, expr, args, targetWasmType);
|
|
1076
1364
|
return true;
|
|
1077
1365
|
}
|
|
@@ -1154,7 +1442,7 @@ export class BuiltinsEmitter {
|
|
|
1154
1442
|
const pType = paramTypes[i] ?? null;
|
|
1155
1443
|
const pGoType = paramGoTypes[i] ?? null;
|
|
1156
1444
|
this.emitExpr(arg, pType);
|
|
1157
|
-
this.
|
|
1445
|
+
this._emitCopyIfValue(arg, pGoType, pType);
|
|
1158
1446
|
}
|
|
1159
1447
|
this.pushInstruction({ op: "call", funcIndex: targetFuncIdx });
|
|
1160
1448
|
return true;
|
|
@@ -1175,6 +1463,8 @@ export class BuiltinsEmitter {
|
|
|
1175
1463
|
|
|
1176
1464
|
const closureTmp = this.acquireTemp(closureWType);
|
|
1177
1465
|
this.emitExpr(func, closureWType);
|
|
1466
|
+
// Calling a nil func value panics like a nil pointer dereference.
|
|
1467
|
+
this._emitNilBranch();
|
|
1178
1468
|
this.pushInstruction({ op: "local.set", index: closureTmp });
|
|
1179
1469
|
|
|
1180
1470
|
// Push param 0: env (anyref)
|
|
@@ -1191,7 +1481,7 @@ export class BuiltinsEmitter {
|
|
|
1191
1481
|
const pWType = closureInfo.paramWTypes[i] ?? null;
|
|
1192
1482
|
const pGoType = closureInfo.sig.params[i] ?? null;
|
|
1193
1483
|
this.emitExpr(arg, pWType);
|
|
1194
|
-
this.
|
|
1484
|
+
this._emitCopyIfValue(arg, pGoType, pWType);
|
|
1195
1485
|
}
|
|
1196
1486
|
|
|
1197
1487
|
// Push funcref
|