gofront 1.8.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.
Files changed (178) hide show
  1. package/README.md +3 -3
  2. package/package.json +6 -5
  3. package/src/backend/js/expressions.js +1157 -408
  4. package/src/backend/js/index.js +327 -153
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +559 -2552
  7. package/src/backend/js/statements.js +670 -158
  8. package/src/backend/js/stdlib/index.js +45 -93
  9. package/src/backend/js/templ.js +32 -45
  10. package/src/backend/js/type-info.js +298 -19
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +91 -170
  13. package/src/backend/shared/host-unicode.js +36 -0
  14. package/src/backend/wasm/boundary.js +490 -965
  15. package/src/backend/wasm/emit-builtins.js +884 -256
  16. package/src/backend/wasm/emit-exprs.js +185 -77
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-shared.js +4 -1
  19. package/src/backend/wasm/emit-stmts.js +524 -240
  20. package/src/backend/wasm/emit.js +176 -38
  21. package/src/backend/wasm/globals.js +48 -8
  22. package/src/backend/wasm/glue.js +2 -4
  23. package/src/backend/wasm/index.js +44 -530
  24. package/src/backend/wasm/method-expr.js +12 -1
  25. package/src/backend/wasm/module-emitter.js +299 -770
  26. package/src/backend/wasm/monomorph.js +139 -8
  27. package/src/backend/wasm/natives.js +600 -0
  28. package/src/backend/wasm/prescan.js +5 -153
  29. package/src/backend/wasm/prune-funcs.js +89 -0
  30. package/src/backend/wasm/stdlib/index.js +2 -32
  31. package/src/backend/wasm/types.js +97 -20
  32. package/src/backend/wasm/variadic.js +9 -4
  33. package/src/cli/cli-core.js +5 -1
  34. package/src/cli/test-runner.js +115 -342
  35. package/src/compiler.js +113 -130
  36. package/src/lexer/lexer.js +106 -11
  37. package/src/lexer/templ-lexer.js +61 -18
  38. package/src/lexer/tokens.js +1 -0
  39. package/src/link/stdlib.js +355 -132
  40. package/src/link/type-names.js +204 -0
  41. package/src/link/wasm.js +30 -6
  42. package/src/lower/bounds.js +153 -0
  43. package/src/lower/captures.js +92 -33
  44. package/src/lower/embedding.js +62 -5
  45. package/src/lower/errors-as.js +196 -0
  46. package/src/lower/fmt-formatters.js +929 -0
  47. package/src/lower/functions.js +225 -7
  48. package/src/lower/gen-types.js +293 -0
  49. package/src/lower/index.js +14 -2
  50. package/src/lower/json-codecs.js +334 -245
  51. package/src/lower/ownership.js +25 -7
  52. package/src/lower/reachability.js +69 -51
  53. package/src/lower/walk.js +12 -0
  54. package/src/parser/declarations.js +30 -5
  55. package/src/parser/expressions.js +111 -57
  56. package/src/parser/statements.js +108 -0
  57. package/src/parser/templ.js +44 -5
  58. package/src/parser/types.js +12 -0
  59. package/src/resolver.js +1 -2
  60. package/src/typechecker/assignability.js +214 -19
  61. package/src/typechecker/const-fold.js +70 -27
  62. package/src/typechecker/constants.js +156 -8
  63. package/src/typechecker/expressions.js +490 -108
  64. package/src/typechecker/index.js +346 -42
  65. package/src/typechecker/init-order.js +136 -40
  66. package/src/typechecker/operand-text.js +41 -0
  67. package/src/typechecker/resolve.js +490 -65
  68. package/src/typechecker/statements.js +288 -27
  69. package/src/typechecker/stdlib/excluded.js +9 -5
  70. package/src/typechecker/stdlib/index.js +25 -9
  71. package/src/typechecker/termination.js +10 -1
  72. package/src/typechecker/types.js +287 -575
  73. package/stdlib/bytes/buffer.go +479 -0
  74. package/stdlib/bytes/bytes.go +1010 -0
  75. package/stdlib/bytes/reader.go +161 -0
  76. package/stdlib/context/context.go +115 -0
  77. package/stdlib/crypto/rand/rand.go +34 -0
  78. package/stdlib/crypto/sha256/sha256.go +249 -0
  79. package/stdlib/encoding/base64/base64.go +331 -0
  80. package/stdlib/encoding/binary/binary.go +332 -0
  81. package/stdlib/encoding/hex/hex.go +140 -0
  82. package/stdlib/encoding/json/json.go +62 -0
  83. package/stdlib/errors/errors.go +174 -0
  84. package/stdlib/fmt/errors.go +110 -0
  85. package/stdlib/fmt/format.go +732 -0
  86. package/stdlib/fmt/print.go +1232 -0
  87. package/stdlib/gom/gom.go +293 -0
  88. package/stdlib/html/html.go +251 -0
  89. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  90. package/stdlib/internal/jsonrt/dec.go +171 -38
  91. package/stdlib/internal/jsonrt/enc.go +186 -36
  92. package/stdlib/internal/jsonrt/scanner.go +17 -8
  93. package/stdlib/io/io.go +157 -1
  94. package/stdlib/maps/maps.go +131 -0
  95. package/stdlib/math/bits/bits.go +507 -0
  96. package/stdlib/math/extra.go +16 -14
  97. package/stdlib/math/math.go +439 -0
  98. package/stdlib/math/rand/rand.go +297 -0
  99. package/stdlib/os/os.go +93 -0
  100. package/stdlib/path/filepath/filepath.go +47 -0
  101. package/stdlib/path/path.go +394 -0
  102. package/stdlib/regexp/regexp.go +231 -0
  103. package/stdlib/slices/slices.go +526 -0
  104. package/stdlib/slices/sort.go +209 -0
  105. package/stdlib/slices/zsort_cmp.go +480 -0
  106. package/stdlib/slices/zsort_ordered.go +482 -0
  107. package/stdlib/sort/sort.go +391 -452
  108. package/stdlib/sort/zsort_func.go +480 -0
  109. package/stdlib/sort/zsort_iface.go +480 -0
  110. package/stdlib/strconv/float.go +1699 -0
  111. package/stdlib/strconv/isprint.go +752 -0
  112. package/stdlib/strconv/quote.go +235 -50
  113. package/stdlib/strconv/strconv.go +616 -0
  114. package/stdlib/strings/builder.go +95 -0
  115. package/stdlib/strings/reader.go +163 -0
  116. package/stdlib/strings/replacer.go +102 -0
  117. package/stdlib/strings/strings.go +807 -0
  118. package/stdlib/sync/sync.go +268 -0
  119. package/stdlib/testing/async_js.go +61 -0
  120. package/stdlib/testing/benchmark.go +297 -0
  121. package/stdlib/testing/testing.go +523 -0
  122. package/stdlib/time/duration.go +233 -0
  123. package/stdlib/time/format.go +745 -0
  124. package/stdlib/time/parse.go +790 -0
  125. package/stdlib/time/sleep_js.go +63 -0
  126. package/stdlib/time/time.go +834 -0
  127. package/stdlib/unicode/unicode.go +141 -3
  128. package/stdlib/unicode/utf8/utf8.go +464 -0
  129. package/src/backend/js/fmt-runtime.js +0 -573
  130. package/src/backend/js/stdlib/base64.js +0 -12
  131. package/src/backend/js/stdlib/binary.js +0 -102
  132. package/src/backend/js/stdlib/bits.js +0 -119
  133. package/src/backend/js/stdlib/builder.js +0 -98
  134. package/src/backend/js/stdlib/bytes.js +0 -368
  135. package/src/backend/js/stdlib/errors.js +0 -45
  136. package/src/backend/js/stdlib/fmt.js +0 -517
  137. package/src/backend/js/stdlib/gom.js +0 -155
  138. package/src/backend/js/stdlib/hex.js +0 -17
  139. package/src/backend/js/stdlib/html.js +0 -20
  140. package/src/backend/js/stdlib/io.js +0 -137
  141. package/src/backend/js/stdlib/json.js +0 -1167
  142. package/src/backend/js/stdlib/maps.js +0 -37
  143. package/src/backend/js/stdlib/math.js +0 -85
  144. package/src/backend/js/stdlib/os.js +0 -13
  145. package/src/backend/js/stdlib/path.js +0 -48
  146. package/src/backend/js/stdlib/rand.js +0 -32
  147. package/src/backend/js/stdlib/regexp.js +0 -54
  148. package/src/backend/js/stdlib/sha256.js +0 -12
  149. package/src/backend/js/stdlib/shared.js +0 -17
  150. package/src/backend/js/stdlib/simd.js +0 -34
  151. package/src/backend/js/stdlib/slices.js +0 -107
  152. package/src/backend/js/stdlib/sort.js +0 -30
  153. package/src/backend/js/stdlib/strconv.js +0 -79
  154. package/src/backend/js/stdlib/strings.js +0 -301
  155. package/src/backend/js/stdlib/sync.js +0 -13
  156. package/src/backend/js/stdlib/testing.js +0 -41
  157. package/src/backend/js/stdlib/time.js +0 -152
  158. package/src/backend/js/stdlib/unicode.js +0 -25
  159. package/src/backend/js/stdlib/utf8.js +0 -26
  160. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  161. package/src/backend/wasm/stdlib/core.js +0 -10278
  162. package/src/backend/wasm/stdlib/io.js +0 -3578
  163. package/src/backend/wasm/stdlib/packages.js +0 -2402
  164. package/src/backend/wasm/stdlib/pure.js +0 -720
  165. package/src/backend/wasm/stdlib/time.js +0 -2229
  166. package/src/typechecker/stdlib/core.js +0 -1079
  167. package/src/typechecker/stdlib/extended.js +0 -1210
  168. package/stdlib/bytes/iter.go +0 -192
  169. package/stdlib/bytes/search.go +0 -240
  170. package/stdlib/bytes/split.go +0 -218
  171. package/stdlib/errors/overlay.go +0 -12
  172. package/stdlib/maps/iter.go +0 -65
  173. package/stdlib/slices/extra.go +0 -73
  174. package/stdlib/slices/iter.go +0 -113
  175. package/stdlib/strings/extra.go +0 -35
  176. package/stdlib/strings/iter.go +0 -122
  177. package/stdlib/sync/extra.go +0 -105
  178. package/stdlib/unicode/utf8/bytes.go +0 -239
@@ -23,18 +23,17 @@ import {
23
23
  import { desugarMethodExprs } from "./method-expr.js";
24
24
  import { ModuleEmitter } from "./module-emitter.js";
25
25
  import { hasGenerics, monomorphise } from "./monomorph.js";
26
+ import { emitWasmIntrinsic, prepareWasmIntrinsic } from "./natives.js";
26
27
  import { hasNativeWasmOpt, optimizeWasm } from "./optimize.js";
27
28
  import {
28
29
  _scanFuncSigInterfaces,
29
30
  _scanImportsInBody,
30
31
  _scanInterfaceCallNodes,
31
32
  _scanInterfaceTypeDecls,
33
+ _someNode,
32
34
  _usesAnyEq,
33
- _usesFmtAny,
34
- _usesTestingCleanup,
35
- _usesTestingRun,
36
- importsAnyOf,
37
35
  } from "./prescan.js";
36
+ import { pruneUnusedFuncs } from "./prune-funcs.js";
38
37
  import {
39
38
  ERROR_STRUCT,
40
39
  getMapKeyValTypes,
@@ -84,8 +83,7 @@ function emitIndexPanicBody(mod, emitter) {
84
83
  concat();
85
84
  emitter.pushInstruction("end");
86
85
  concat();
87
- emitter.pushInstruction("any.convert_extern");
88
- emitter.emitPanicThrow();
86
+ emitter.emitRuntimePanicThrow();
89
87
  }
90
88
 
91
89
  function peepholeOptimize(instructions) {
@@ -176,6 +174,7 @@ export function compileWasmModule(
176
174
 
177
175
  const mod = new ModuleEmitter(resolvedChecker, resolvedLowerResult, progs, {
178
176
  bundledPackages: options.bundledPackages,
177
+ natives: options.natives,
179
178
  });
180
179
 
181
180
  // 1. Collect all functions, methods, and package-level globals
@@ -260,6 +259,7 @@ export function compileWasmModule(
260
259
  _isClosure: true,
261
260
  _isYieldClosure: Boolean(node._isYieldClosure),
262
261
  _iterStateName: node._iterStateName ?? null,
262
+ _forStmt: node._forStmt ?? null,
263
263
  _funcLit: node,
264
264
  _rootFuncDecl: rootFn,
265
265
  _srcFile: rootFn?._srcFile ?? null,
@@ -591,18 +591,6 @@ export function compileWasmModule(
591
591
  _mapInfo: mapInfo,
592
592
  _rootFuncDecl: null,
593
593
  });
594
- // clone
595
- funcDecls.push({
596
- kind: "FuncDecl",
597
- name: mapInfo.cloneFuncName,
598
- params: [{ name: "m", type: mapInfo.wType }],
599
- returnType: mapInfo.wType,
600
- body: { kind: "Block", stmts: [], list: [] },
601
- _isMapHelper: true,
602
- _mapHelperKind: "clone",
603
- _mapInfo: mapInfo,
604
- _rootFuncDecl: null,
605
- });
606
594
  }
607
595
 
608
596
  // 1e2. `gofront/shared` linear-memory helpers (only when imported).
@@ -650,9 +638,7 @@ export function compileWasmModule(
650
638
  });
651
639
  }
652
640
 
653
- // 1e3. Runtime helpers: error values, interface equality, t.Run callback.
654
- mod.usesTestingRun = funcDecls.some((fn) => _usesTestingRun(fn.body));
655
- mod.usesTestingCleanup = funcDecls.some((fn) => _usesTestingCleanup(fn.body));
641
+ // 1e3. Runtime helpers: error values and interface equality.
656
642
  mod.usesAnyEq = _usesAnyEq(funcDecls, mod);
657
643
  const ANY_T = { kind: "basic", name: "any" };
658
644
  const STR_T = { kind: "basic", name: "string" };
@@ -680,6 +666,25 @@ export function compileWasmModule(
680
666
  ),
681
667
  );
682
668
  }
669
+ // `x.(T)` outside comma-ok form panics with the dynamic type's name.
670
+ mod.usesTypeAssertFail = funcDecls.some((fn) =>
671
+ _someNode(fn.body, (n) => n.kind === "TypeAssertExpr" && !n._commaOk),
672
+ );
673
+ if (mod.usesTypeAssertFail) {
674
+ funcDecls.push(
675
+ helper(
676
+ "__ta_fail",
677
+ [
678
+ { name: "v", type: ANY_T },
679
+ { name: "src", type: STR_T },
680
+ { name: "target", type: STR_T },
681
+ { name: "iface", type: BOOL_T },
682
+ ],
683
+ null,
684
+ "ta_fail",
685
+ ),
686
+ );
687
+ }
683
688
  mod.usesAnyHash = false;
684
689
  for (const info of mod.mapTypes.values()) {
685
690
  if (isInterfaceType(info.keyGoType, checker)) {
@@ -697,6 +702,13 @@ export function compileWasmModule(
697
702
  ),
698
703
  );
699
704
  }
705
+ // fmt's %p identity of a reference in an `any`: a defined map or func type
706
+ // is boxed there, so the helper hands the host the boxed reference.
707
+ if (funcDecls.some((fn) => fn.intrinsic === "fmt_ptr_id")) {
708
+ funcDecls.push(
709
+ helper("__any_ref", [{ name: "a", type: ANY_T }], ANY_T, "any_ref"),
710
+ );
711
+ }
700
712
  if (mod.hasErrorType) {
701
713
  const errPtr = {
702
714
  kind: "pointer",
@@ -714,88 +726,8 @@ export function compileWasmModule(
714
726
  _methodName: "Error",
715
727
  },
716
728
  ),
717
- helper(
718
- `${ERROR_STRUCT}.Unwrap`,
719
- [{ name: "e", type: errPtr }],
720
- ANY_T,
721
- "error_cause",
722
- {
723
- _isMethod: true,
724
- _recvTypeName: ERROR_STRUCT,
725
- _methodName: "Unwrap",
726
- },
727
- ),
728
- helper(
729
- "__mk_error",
730
- [
731
- { name: "msg", type: STR_T },
732
- { name: "cause", type: ANY_T },
733
- ],
734
- ANY_T,
735
- "mk_error",
736
- ),
729
+ helper("__mk_error", [{ name: "msg", type: STR_T }], ANY_T, "mk_error"),
737
730
  helper("__error_str", [{ name: "e", type: ANY_T }], STR_T, "error_str"),
738
- {
739
- kind: "FuncDecl",
740
- name: "__errors_unwrap",
741
- params: [{ name: "__recv", type: ANY_T }],
742
- returnType: ANY_T,
743
- body: { kind: "Block", stmts: [], list: [] },
744
- _isInterfaceDispatcher: true,
745
- _softDispatch: true,
746
- _ifaceName: "error",
747
- _ifaceType: null,
748
- _methodName: "Unwrap",
749
- _rootFuncDecl: null,
750
- },
751
- helper(
752
- "__errors_is",
753
- [
754
- { name: "err", type: ANY_T },
755
- { name: "target", type: ANY_T },
756
- ],
757
- BOOL_T,
758
- "errors_is",
759
- ),
760
- );
761
- }
762
- if (mod.usesTestingRun) {
763
- funcDecls.push(
764
- helper(
765
- "__testing_run_cb",
766
- [
767
- { name: "fn", type: ANY_T },
768
- {
769
- name: "t",
770
- type: {
771
- kind: "pointer",
772
- base: { kind: "named", name: "testing.T" },
773
- },
774
- },
775
- ],
776
- null,
777
- "testing_run_cb",
778
- { _forceExport: true },
779
- ),
780
- );
781
- }
782
- if (mod.usesTestingCleanup) {
783
- funcDecls.push(
784
- helper(
785
- "__testing_cleanup_cb",
786
- [{ name: "fn", type: ANY_T }],
787
- null,
788
- "testing_cleanup_cb",
789
- { _forceExport: true },
790
- ),
791
- );
792
- }
793
- _registerIoSyntheticMethods(funcDecls, mod, STR_T, progs);
794
- // `__any_fmt` turns an `any` operand of fmt into the host value; its body
795
- // is emitted last-but-one so every type registered by user code is seen.
796
- if (_usesFmtAny(funcDecls, mod)) {
797
- funcDecls.push(
798
- helper("__any_fmt", [{ name: "a", type: ANY_T }], STR_T, "any_fmt"),
799
731
  );
800
732
  }
801
733
 
@@ -806,6 +738,7 @@ export function compileWasmModule(
806
738
 
807
739
  // 2. Pre-scan for needed imports so import func indices are fixed
808
740
  for (const fn of funcDecls) {
741
+ if (fn.intrinsic) prepareWasmIntrinsic(mod, fn);
809
742
  _scanImportsInBody(fn.body, mod);
810
743
  }
811
744
  if (boundaryMeta) scanBoundaryImports(mod, boundaryMeta);
@@ -859,8 +792,11 @@ export function compileWasmModule(
859
792
  fn._forceExport ||
860
793
  (!fn._isGlobalInit &&
861
794
  !fn._isRuntimeHelper &&
862
- !fn._isIoHelper &&
863
- !fn._isPhase7Helper &&
795
+ !fn._isMapHelper &&
796
+ !fn._isInterfaceDispatcher &&
797
+ !fn._isSharedHelper &&
798
+ !fn._isRuntimePanic &&
799
+ !fn._isIndexPanic &&
864
800
  (options.exportAll ||
865
801
  fn.name === "main" ||
866
802
  (fn.name[0] >= "A" && fn.name[0] <= "Z") ||
@@ -899,8 +835,7 @@ export function compileWasmModule(
899
835
  const funcIdx = mod.getStringImportIndex();
900
836
  emitter.pushInstruction({ op: "i32.const", value: strIdx });
901
837
  emitter.pushInstruction({ op: "call", funcIndex: funcIdx });
902
- emitter.pushInstruction("any.convert_extern");
903
- emitter.emitPanicThrow();
838
+ emitter.emitRuntimePanicThrow();
904
839
  } else if (fn._isPushPanic) {
905
840
  const panicNodeTypeIndex = mod.getPanicNodeTypeIndex();
906
841
  const panicGlobal = mod.getPanicGlobalIndex();
@@ -922,8 +857,8 @@ export function compileWasmModule(
922
857
  emitter.emitSharedHelper(fn);
923
858
  } else if (fn._isRuntimeHelper) {
924
859
  emitter.emitRuntimeHelper(fn);
925
- } else if (fn._isIoHelper || fn._isPhase7Helper) {
926
- emitter.emitIoHelper(fn);
860
+ } else if (fn.intrinsic) {
861
+ emitWasmIntrinsic(emitter, fn);
927
862
  } else if (fn.body) {
928
863
  emitter.emitFunctionBody(fn.body);
929
864
  }
@@ -961,7 +896,6 @@ export function compileWasmModule(
961
896
  facade = generateFacade(boundaryMeta, {
962
897
  stringTable: mod.stringTable,
963
898
  callMain: Boolean(options.callMain) && mod.funcMap.has("main"),
964
- stdlibEnv: mod.usesStdlibEnv,
965
899
  });
966
900
  }
967
901
 
@@ -978,6 +912,7 @@ export function compileWasmModule(
978
912
  sourceMappingURL: options.sourceMappingURL ?? null,
979
913
  };
980
914
 
915
+ pruneUnusedFuncs(moduleIR);
981
916
  const wasmBytes = encodeModule(moduleIR);
982
917
  const watText = options.emitWat ? emitWat(moduleIR) : null;
983
918
 
@@ -1037,428 +972,7 @@ function _collectInterfaceDispatchers(progs, funcDecls, mod, checker) {
1037
972
  });
1038
973
  }
1039
974
 
1040
- const hasIo = importsAnyOf(progs, [
1041
- "io",
1042
- "fmt",
1043
- "strings",
1044
- "bytes",
1045
- "crypto/sha256",
1046
- "sha256",
1047
- "encoding/binary",
1048
- "binary",
1049
- "encoding/hex",
1050
- "hex",
1051
- "encoding/base64",
1052
- "base64",
1053
- ]);
1054
- if (hasIo) {
1055
- const byteSliceType = {
1056
- kind: "slice",
1057
- elem: { kind: "basic", name: "byte" },
1058
- };
1059
- const intErrReturns = [
1060
- { kind: "basic", name: "int" },
1061
- { kind: "interface", name: "error" },
1062
- ];
1063
- if (!interfaceCalls.has("io.Reader.Read")) {
1064
- interfaceCalls.set("io.Reader.Read", {
1065
- ifaceName: "io.Reader",
1066
- ifaceType: checker?.types?.get("io.Reader"),
1067
- methodName: "Read",
1068
- methodSig: {
1069
- kind: "func",
1070
- params: [byteSliceType],
1071
- returns: intErrReturns,
1072
- },
1073
- });
1074
- }
1075
- if (!interfaceCalls.has("io.Writer.Write")) {
1076
- interfaceCalls.set("io.Writer.Write", {
1077
- ifaceName: "io.Writer",
1078
- ifaceType: checker?.types?.get("io.Writer"),
1079
- methodName: "Write",
1080
- methodSig: {
1081
- kind: "func",
1082
- params: [byteSliceType],
1083
- returns: intErrReturns,
1084
- },
1085
- });
1086
- }
1087
- }
1088
-
1089
975
  for (const info of interfaceCalls.values()) {
1090
976
  funcDecls.push(_makeInterfaceDispatcher(info, checker));
1091
977
  }
1092
978
  }
1093
-
1094
- function _registerIoSyntheticMethods(funcDecls, mod, strType, programs) {
1095
- const progs = Array.isArray(programs) ? programs : [programs];
1096
- const hasStrings = importsAnyOf(progs, ["strings"]);
1097
- const hasBytes = importsAnyOf(progs, ["bytes"]);
1098
- const hasIo = importsAnyOf(progs, ["io"]);
1099
-
1100
- const BYTE_SLICE_T = {
1101
- kind: "slice",
1102
- elem: { kind: "basic", name: "byte" },
1103
- };
1104
- const INT_T = { kind: "basic", name: "int" };
1105
- const ERR_T = { kind: "interface", name: "error" };
1106
- const INT_ERR_RET = { kind: "tuple", types: [INT_T, ERR_T] };
1107
- const ioHelper = (name, params, returnType, kind, extra = {}) => ({
1108
- kind: "FuncDecl",
1109
- name,
1110
- params,
1111
- returnType,
1112
- body: { kind: "Block", stmts: [], list: [] },
1113
- _isIoHelper: kind,
1114
- _rootFuncDecl: null,
1115
- ...extra,
1116
- });
1117
-
1118
- if (hasStrings && mod.structTypes.has("strings.Builder")) {
1119
- const bPtr = {
1120
- kind: "pointer",
1121
- base: { kind: "named", name: "strings.Builder" },
1122
- };
1123
- funcDecls.push(
1124
- ioHelper(
1125
- "strings.Builder.Write",
1126
- [
1127
- { name: "b", type: bPtr },
1128
- { name: "p", type: BYTE_SLICE_T },
1129
- ],
1130
- INT_ERR_RET,
1131
- "builder_write",
1132
- {
1133
- _isMethod: true,
1134
- _recvTypeName: "strings.Builder",
1135
- _methodName: "Write",
1136
- },
1137
- ),
1138
- ioHelper(
1139
- "strings.Builder.WriteString",
1140
- [
1141
- { name: "b", type: bPtr },
1142
- { name: "s", type: strType },
1143
- ],
1144
- INT_ERR_RET,
1145
- "builder_write_string",
1146
- {
1147
- _isMethod: true,
1148
- _recvTypeName: "strings.Builder",
1149
- _methodName: "WriteString",
1150
- },
1151
- ),
1152
- );
1153
- }
1154
- if (hasBytes && mod.structTypes.has("bytes.Buffer")) {
1155
- const bPtr = {
1156
- kind: "pointer",
1157
- base: { kind: "named", name: "bytes.Buffer" },
1158
- };
1159
- funcDecls.push(
1160
- ioHelper(
1161
- "bytes.Buffer.Write",
1162
- [
1163
- { name: "b", type: bPtr },
1164
- { name: "p", type: BYTE_SLICE_T },
1165
- ],
1166
- INT_ERR_RET,
1167
- "buffer_write",
1168
- {
1169
- _isMethod: true,
1170
- _recvTypeName: "bytes.Buffer",
1171
- _methodName: "Write",
1172
- },
1173
- ),
1174
- ioHelper(
1175
- "bytes.Buffer.WriteString",
1176
- [
1177
- { name: "b", type: bPtr },
1178
- { name: "s", type: strType },
1179
- ],
1180
- INT_ERR_RET,
1181
- "buffer_write_string",
1182
- {
1183
- _isMethod: true,
1184
- _recvTypeName: "bytes.Buffer",
1185
- _methodName: "WriteString",
1186
- },
1187
- ),
1188
- ioHelper(
1189
- "bytes.Buffer.Read",
1190
- [
1191
- { name: "b", type: bPtr },
1192
- { name: "p", type: BYTE_SLICE_T },
1193
- ],
1194
- INT_ERR_RET,
1195
- "buffer_read",
1196
- {
1197
- _isMethod: true,
1198
- _recvTypeName: "bytes.Buffer",
1199
- _methodName: "Read",
1200
- },
1201
- ),
1202
- );
1203
- }
1204
- if (hasStrings && mod.structTypes.has("strings.Reader")) {
1205
- const rPtr = {
1206
- kind: "pointer",
1207
- base: { kind: "named", name: "strings.Reader" },
1208
- };
1209
- funcDecls.push(
1210
- ioHelper(
1211
- "strings.Reader.Read",
1212
- [
1213
- { name: "r", type: rPtr },
1214
- { name: "p", type: BYTE_SLICE_T },
1215
- ],
1216
- INT_ERR_RET,
1217
- "strings_reader_read",
1218
- {
1219
- _isMethod: true,
1220
- _recvTypeName: "strings.Reader",
1221
- _methodName: "Read",
1222
- },
1223
- ),
1224
- ioHelper(
1225
- "strings.Reader.Len",
1226
- [{ name: "r", type: rPtr }],
1227
- INT_T,
1228
- "strings_reader_len",
1229
- {
1230
- _isMethod: true,
1231
- _recvTypeName: "strings.Reader",
1232
- _methodName: "Len",
1233
- },
1234
- ),
1235
- ioHelper(
1236
- "strings.Reader.Reset",
1237
- [
1238
- { name: "r", type: rPtr },
1239
- { name: "s", type: strType },
1240
- ],
1241
- null,
1242
- "strings_reader_reset",
1243
- {
1244
- _isMethod: true,
1245
- _recvTypeName: "strings.Reader",
1246
- _methodName: "Reset",
1247
- },
1248
- ),
1249
- );
1250
- }
1251
- if (hasBytes && mod.structTypes.has("bytes.Reader")) {
1252
- const rPtr = {
1253
- kind: "pointer",
1254
- base: { kind: "named", name: "bytes.Reader" },
1255
- };
1256
- funcDecls.push(
1257
- ioHelper(
1258
- "bytes.Reader.Read",
1259
- [
1260
- { name: "r", type: rPtr },
1261
- { name: "p", type: BYTE_SLICE_T },
1262
- ],
1263
- INT_ERR_RET,
1264
- "bytes_reader_read",
1265
- { _isMethod: true, _recvTypeName: "bytes.Reader", _methodName: "Read" },
1266
- ),
1267
- ioHelper(
1268
- "bytes.Reader.Len",
1269
- [{ name: "r", type: rPtr }],
1270
- INT_T,
1271
- "bytes_reader_len",
1272
- { _isMethod: true, _recvTypeName: "bytes.Reader", _methodName: "Len" },
1273
- ),
1274
- ioHelper(
1275
- "bytes.Reader.Reset",
1276
- [
1277
- { name: "r", type: rPtr },
1278
- { name: "b", type: BYTE_SLICE_T },
1279
- ],
1280
- null,
1281
- "bytes_reader_reset",
1282
- {
1283
- _isMethod: true,
1284
- _recvTypeName: "bytes.Reader",
1285
- _methodName: "Reset",
1286
- },
1287
- ),
1288
- );
1289
- }
1290
- if (hasIo && mod.structTypes.has("io.discard")) {
1291
- const dPtr = {
1292
- kind: "pointer",
1293
- base: { kind: "named", name: "io.discard" },
1294
- };
1295
- funcDecls.push(
1296
- ioHelper(
1297
- "io.discard.Write",
1298
- [
1299
- { name: "d", type: dPtr },
1300
- { name: "p", type: BYTE_SLICE_T },
1301
- ],
1302
- INT_ERR_RET,
1303
- "discard_write",
1304
- { _isMethod: true, _recvTypeName: "io.discard", _methodName: "Write" },
1305
- ),
1306
- ioHelper(
1307
- "io.discard.WriteString",
1308
- [
1309
- { name: "d", type: dPtr },
1310
- { name: "s", type: strType },
1311
- ],
1312
- INT_ERR_RET,
1313
- "discard_write_string",
1314
- {
1315
- _isMethod: true,
1316
- _recvTypeName: "io.discard",
1317
- _methodName: "WriteString",
1318
- },
1319
- ),
1320
- );
1321
- }
1322
- if (hasIo && mod.structTypes.has("io.LimitedReader")) {
1323
- const lrPtr = {
1324
- kind: "pointer",
1325
- base: { kind: "named", name: "io.LimitedReader" },
1326
- };
1327
- funcDecls.push(
1328
- ioHelper(
1329
- "io.LimitedReader.Read",
1330
- [
1331
- { name: "l", type: lrPtr },
1332
- { name: "p", type: BYTE_SLICE_T },
1333
- ],
1334
- INT_ERR_RET,
1335
- "limited_reader_read",
1336
- {
1337
- _isMethod: true,
1338
- _recvTypeName: "io.LimitedReader",
1339
- _methodName: "Read",
1340
- },
1341
- ),
1342
- );
1343
- }
1344
- const hasOs = importsAnyOf(progs, ["os"]);
1345
- if (hasOs && mod.structTypes.has("os.File")) {
1346
- const fPtr = {
1347
- kind: "pointer",
1348
- base: { kind: "named", name: "os.File" },
1349
- };
1350
- funcDecls.push(
1351
- ioHelper(
1352
- "os.File.Write",
1353
- [
1354
- { name: "f", type: fPtr },
1355
- { name: "p", type: BYTE_SLICE_T },
1356
- ],
1357
- INT_ERR_RET,
1358
- "os_file_write",
1359
- { _isMethod: true, _recvTypeName: "os.File", _methodName: "Write" },
1360
- ),
1361
- ioHelper(
1362
- "os.File.WriteString",
1363
- [
1364
- { name: "f", type: fPtr },
1365
- { name: "s", type: strType },
1366
- ],
1367
- INT_ERR_RET,
1368
- "os_file_write_string",
1369
- {
1370
- _isMethod: true,
1371
- _recvTypeName: "os.File",
1372
- _methodName: "WriteString",
1373
- },
1374
- ),
1375
- ioHelper(
1376
- "os.File.Read",
1377
- [
1378
- { name: "f", type: fPtr },
1379
- { name: "p", type: BYTE_SLICE_T },
1380
- ],
1381
- INT_ERR_RET,
1382
- "os_file_read",
1383
- { _isMethod: true, _recvTypeName: "os.File", _methodName: "Read" },
1384
- ),
1385
- ioHelper(
1386
- "os.File.Close",
1387
- [{ name: "f", type: fPtr }],
1388
- ERR_T,
1389
- "os_file_close",
1390
- { _isMethod: true, _recvTypeName: "os.File", _methodName: "Close" },
1391
- ),
1392
- );
1393
- }
1394
- const hasSha256 = importsAnyOf(progs, ["crypto/sha256", "sha256"]);
1395
- if (
1396
- hasSha256 &&
1397
- (mod.structTypes.has("sha256.digest") ||
1398
- mod.structTypes.has("crypto/sha256.digest"))
1399
- ) {
1400
- const dPtr = {
1401
- kind: "pointer",
1402
- base: { kind: "named", name: "sha256.digest" },
1403
- };
1404
- funcDecls.push(
1405
- ioHelper(
1406
- "sha256.digest.Write",
1407
- [
1408
- { name: "d", type: dPtr },
1409
- { name: "p", type: BYTE_SLICE_T },
1410
- ],
1411
- INT_ERR_RET,
1412
- "sha256_write",
1413
- {
1414
- _isMethod: true,
1415
- _recvTypeName: "sha256.digest",
1416
- _methodName: "Write",
1417
- },
1418
- ),
1419
- ioHelper(
1420
- "sha256.digest.Sum",
1421
- [
1422
- { name: "d", type: dPtr },
1423
- { name: "b", type: BYTE_SLICE_T },
1424
- ],
1425
- BYTE_SLICE_T,
1426
- "sha256_sum",
1427
- { _isMethod: true, _recvTypeName: "sha256.digest", _methodName: "Sum" },
1428
- ),
1429
- ioHelper(
1430
- "sha256.digest.Reset",
1431
- [{ name: "d", type: dPtr }],
1432
- null,
1433
- "sha256_reset",
1434
- {
1435
- _isMethod: true,
1436
- _recvTypeName: "sha256.digest",
1437
- _methodName: "Reset",
1438
- },
1439
- ),
1440
- ioHelper(
1441
- "sha256.digest.Size",
1442
- [{ name: "d", type: dPtr }],
1443
- INT_T,
1444
- "sha256_size",
1445
- {
1446
- _isMethod: true,
1447
- _recvTypeName: "sha256.digest",
1448
- _methodName: "Size",
1449
- },
1450
- ),
1451
- ioHelper(
1452
- "sha256.digest.BlockSize",
1453
- [{ name: "d", type: dPtr }],
1454
- INT_T,
1455
- "sha256_block_size",
1456
- {
1457
- _isMethod: true,
1458
- _recvTypeName: "sha256.digest",
1459
- _methodName: "BlockSize",
1460
- },
1461
- ),
1462
- );
1463
- }
1464
- }
@@ -96,6 +96,10 @@ function forwardingFuncLit(sel, recvName = "recv$") {
96
96
  };
97
97
  }
98
98
 
99
+ function isInterfaceRecv(t) {
100
+ return (t?.underlying ?? t)?.kind === "interface";
101
+ }
102
+
99
103
  function methodValueLit(sel) {
100
104
  const fnType = sel._type;
101
105
  let recvType = sel.expr._type;
@@ -143,7 +147,14 @@ function methodValueLit(sel) {
143
147
  returnType: typeToTypeNode(fnType),
144
148
  body: {
145
149
  kind: "Block",
146
- stmts: [{ kind: "ReturnStmt", values: [inner] }],
150
+ stmts: [
151
+ // A method value on a nil interface panics when it is
152
+ // evaluated, not when it is called.
153
+ ...(isInterfaceRecv(recvType)
154
+ ? [{ kind: "NilCheckStmt", expr: ident(recvName, recvType, sel) }]
155
+ : []),
156
+ { kind: "ReturnStmt", values: [inner] },
157
+ ],
147
158
  },
148
159
  _type: outerType,
149
160
  _line: sel._line,