gofront 1.8.0 → 1.9.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.
Files changed (177) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -4
  3. package/src/backend/js/expressions.js +849 -371
  4. package/src/backend/js/index.js +241 -147
  5. package/src/backend/js/natives.js +383 -0
  6. package/src/backend/js/runtime.js +512 -2547
  7. package/src/backend/js/statements.js +506 -103
  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 +177 -13
  11. package/src/backend/shared/fixed-float.js +20 -0
  12. package/src/backend/shared/fmt-types.js +63 -171
  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 +643 -256
  16. package/src/backend/wasm/emit-exprs.js +124 -57
  17. package/src/backend/wasm/emit-maps.js +17 -367
  18. package/src/backend/wasm/emit-stmts.js +325 -75
  19. package/src/backend/wasm/emit.js +104 -13
  20. package/src/backend/wasm/globals.js +47 -8
  21. package/src/backend/wasm/glue.js +2 -4
  22. package/src/backend/wasm/index.js +36 -530
  23. package/src/backend/wasm/method-expr.js +12 -1
  24. package/src/backend/wasm/module-emitter.js +92 -717
  25. package/src/backend/wasm/monomorph.js +103 -6
  26. package/src/backend/wasm/natives.js +596 -0
  27. package/src/backend/wasm/prescan.js +5 -153
  28. package/src/backend/wasm/prune-funcs.js +89 -0
  29. package/src/backend/wasm/stdlib/index.js +2 -32
  30. package/src/backend/wasm/types.js +68 -20
  31. package/src/backend/wasm/variadic.js +3 -3
  32. package/src/cli/cli-core.js +5 -1
  33. package/src/cli/test-runner.js +115 -342
  34. package/src/compiler.js +108 -130
  35. package/src/lexer/lexer.js +105 -11
  36. package/src/lexer/templ-lexer.js +61 -18
  37. package/src/lexer/tokens.js +1 -0
  38. package/src/link/stdlib.js +354 -132
  39. package/src/link/type-names.js +148 -0
  40. package/src/link/wasm.js +30 -6
  41. package/src/lower/bounds.js +153 -0
  42. package/src/lower/captures.js +92 -33
  43. package/src/lower/embedding.js +32 -3
  44. package/src/lower/errors-as.js +196 -0
  45. package/src/lower/fmt-formatters.js +905 -0
  46. package/src/lower/functions.js +2 -0
  47. package/src/lower/gen-types.js +274 -0
  48. package/src/lower/index.js +7 -1
  49. package/src/lower/json-codecs.js +228 -247
  50. package/src/lower/ownership.js +25 -7
  51. package/src/lower/reachability.js +69 -51
  52. package/src/lower/walk.js +12 -0
  53. package/src/parser/declarations.js +28 -5
  54. package/src/parser/expressions.js +86 -16
  55. package/src/parser/statements.js +1 -0
  56. package/src/parser/templ.js +44 -5
  57. package/src/parser/types.js +1 -0
  58. package/src/resolver.js +1 -2
  59. package/src/typechecker/assignability.js +124 -11
  60. package/src/typechecker/const-fold.js +70 -27
  61. package/src/typechecker/constants.js +32 -6
  62. package/src/typechecker/expressions.js +326 -98
  63. package/src/typechecker/index.js +208 -33
  64. package/src/typechecker/init-order.js +136 -40
  65. package/src/typechecker/operand-text.js +40 -0
  66. package/src/typechecker/resolve.js +192 -36
  67. package/src/typechecker/statements.js +122 -11
  68. package/src/typechecker/stdlib/excluded.js +9 -5
  69. package/src/typechecker/stdlib/index.js +25 -9
  70. package/src/typechecker/termination.js +10 -1
  71. package/src/typechecker/types.js +203 -573
  72. package/stdlib/bytes/buffer.go +479 -0
  73. package/stdlib/bytes/bytes.go +1010 -0
  74. package/stdlib/bytes/reader.go +161 -0
  75. package/stdlib/context/context.go +115 -0
  76. package/stdlib/crypto/rand/rand.go +34 -0
  77. package/stdlib/crypto/sha256/sha256.go +249 -0
  78. package/stdlib/encoding/base64/base64.go +331 -0
  79. package/stdlib/encoding/binary/binary.go +332 -0
  80. package/stdlib/encoding/hex/hex.go +140 -0
  81. package/stdlib/encoding/json/json.go +62 -0
  82. package/stdlib/errors/errors.go +174 -0
  83. package/stdlib/fmt/errors.go +110 -0
  84. package/stdlib/fmt/format.go +732 -0
  85. package/stdlib/fmt/print.go +1232 -0
  86. package/stdlib/gom/gom.go +293 -0
  87. package/stdlib/html/html.go +251 -0
  88. package/stdlib/internal/fmtrt/fmtrt.go +163 -0
  89. package/stdlib/internal/jsonrt/dec.go +171 -38
  90. package/stdlib/internal/jsonrt/enc.go +186 -36
  91. package/stdlib/internal/jsonrt/scanner.go +17 -8
  92. package/stdlib/io/io.go +157 -1
  93. package/stdlib/maps/maps.go +131 -0
  94. package/stdlib/math/bits/bits.go +507 -0
  95. package/stdlib/math/extra.go +16 -14
  96. package/stdlib/math/math.go +439 -0
  97. package/stdlib/math/rand/rand.go +297 -0
  98. package/stdlib/os/os.go +93 -0
  99. package/stdlib/path/filepath/filepath.go +47 -0
  100. package/stdlib/path/path.go +394 -0
  101. package/stdlib/regexp/regexp.go +231 -0
  102. package/stdlib/slices/slices.go +526 -0
  103. package/stdlib/slices/sort.go +209 -0
  104. package/stdlib/slices/zsort_cmp.go +480 -0
  105. package/stdlib/slices/zsort_ordered.go +482 -0
  106. package/stdlib/sort/sort.go +391 -452
  107. package/stdlib/sort/zsort_func.go +480 -0
  108. package/stdlib/sort/zsort_iface.go +480 -0
  109. package/stdlib/strconv/float.go +1699 -0
  110. package/stdlib/strconv/isprint.go +752 -0
  111. package/stdlib/strconv/quote.go +235 -50
  112. package/stdlib/strconv/strconv.go +616 -0
  113. package/stdlib/strings/builder.go +95 -0
  114. package/stdlib/strings/reader.go +163 -0
  115. package/stdlib/strings/replacer.go +102 -0
  116. package/stdlib/strings/strings.go +807 -0
  117. package/stdlib/sync/sync.go +268 -0
  118. package/stdlib/testing/async_js.go +61 -0
  119. package/stdlib/testing/benchmark.go +297 -0
  120. package/stdlib/testing/testing.go +523 -0
  121. package/stdlib/time/duration.go +233 -0
  122. package/stdlib/time/format.go +745 -0
  123. package/stdlib/time/parse.go +790 -0
  124. package/stdlib/time/sleep_js.go +63 -0
  125. package/stdlib/time/time.go +834 -0
  126. package/stdlib/unicode/unicode.go +141 -3
  127. package/stdlib/unicode/utf8/utf8.go +464 -0
  128. package/src/backend/js/fmt-runtime.js +0 -573
  129. package/src/backend/js/stdlib/base64.js +0 -12
  130. package/src/backend/js/stdlib/binary.js +0 -102
  131. package/src/backend/js/stdlib/bits.js +0 -119
  132. package/src/backend/js/stdlib/builder.js +0 -98
  133. package/src/backend/js/stdlib/bytes.js +0 -368
  134. package/src/backend/js/stdlib/errors.js +0 -45
  135. package/src/backend/js/stdlib/fmt.js +0 -517
  136. package/src/backend/js/stdlib/gom.js +0 -155
  137. package/src/backend/js/stdlib/hex.js +0 -17
  138. package/src/backend/js/stdlib/html.js +0 -20
  139. package/src/backend/js/stdlib/io.js +0 -137
  140. package/src/backend/js/stdlib/json.js +0 -1167
  141. package/src/backend/js/stdlib/maps.js +0 -37
  142. package/src/backend/js/stdlib/math.js +0 -85
  143. package/src/backend/js/stdlib/os.js +0 -13
  144. package/src/backend/js/stdlib/path.js +0 -48
  145. package/src/backend/js/stdlib/rand.js +0 -32
  146. package/src/backend/js/stdlib/regexp.js +0 -54
  147. package/src/backend/js/stdlib/sha256.js +0 -12
  148. package/src/backend/js/stdlib/shared.js +0 -17
  149. package/src/backend/js/stdlib/simd.js +0 -34
  150. package/src/backend/js/stdlib/slices.js +0 -107
  151. package/src/backend/js/stdlib/sort.js +0 -30
  152. package/src/backend/js/stdlib/strconv.js +0 -79
  153. package/src/backend/js/stdlib/strings.js +0 -301
  154. package/src/backend/js/stdlib/sync.js +0 -13
  155. package/src/backend/js/stdlib/testing.js +0 -41
  156. package/src/backend/js/stdlib/time.js +0 -152
  157. package/src/backend/js/stdlib/unicode.js +0 -25
  158. package/src/backend/js/stdlib/utf8.js +0 -26
  159. package/src/backend/wasm/stdlib/bytes.js +0 -6716
  160. package/src/backend/wasm/stdlib/core.js +0 -10278
  161. package/src/backend/wasm/stdlib/io.js +0 -3578
  162. package/src/backend/wasm/stdlib/packages.js +0 -2402
  163. package/src/backend/wasm/stdlib/pure.js +0 -720
  164. package/src/backend/wasm/stdlib/time.js +0 -2229
  165. package/src/typechecker/stdlib/core.js +0 -1079
  166. package/src/typechecker/stdlib/extended.js +0 -1210
  167. package/stdlib/bytes/iter.go +0 -192
  168. package/stdlib/bytes/search.go +0 -240
  169. package/stdlib/bytes/split.go +0 -218
  170. package/stdlib/errors/overlay.go +0 -12
  171. package/stdlib/maps/iter.go +0 -65
  172. package/stdlib/slices/extra.go +0 -73
  173. package/stdlib/slices/iter.go +0 -113
  174. package/stdlib/strings/extra.go +0 -35
  175. package/stdlib/strings/iter.go +0 -122
  176. package/stdlib/sync/extra.go +0 -105
  177. 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
@@ -591,18 +590,6 @@ export function compileWasmModule(
591
590
  _mapInfo: mapInfo,
592
591
  _rootFuncDecl: null,
593
592
  });
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
593
  }
607
594
 
608
595
  // 1e2. `gofront/shared` linear-memory helpers (only when imported).
@@ -650,9 +637,7 @@ export function compileWasmModule(
650
637
  });
651
638
  }
652
639
 
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));
640
+ // 1e3. Runtime helpers: error values and interface equality.
656
641
  mod.usesAnyEq = _usesAnyEq(funcDecls, mod);
657
642
  const ANY_T = { kind: "basic", name: "any" };
658
643
  const STR_T = { kind: "basic", name: "string" };
@@ -680,6 +665,25 @@ export function compileWasmModule(
680
665
  ),
681
666
  );
682
667
  }
668
+ // `x.(T)` outside comma-ok form panics with the dynamic type's name.
669
+ mod.usesTypeAssertFail = funcDecls.some((fn) =>
670
+ _someNode(fn.body, (n) => n.kind === "TypeAssertExpr" && !n._commaOk),
671
+ );
672
+ if (mod.usesTypeAssertFail) {
673
+ funcDecls.push(
674
+ helper(
675
+ "__ta_fail",
676
+ [
677
+ { name: "v", type: ANY_T },
678
+ { name: "src", type: STR_T },
679
+ { name: "target", type: STR_T },
680
+ { name: "iface", type: BOOL_T },
681
+ ],
682
+ null,
683
+ "ta_fail",
684
+ ),
685
+ );
686
+ }
683
687
  mod.usesAnyHash = false;
684
688
  for (const info of mod.mapTypes.values()) {
685
689
  if (isInterfaceType(info.keyGoType, checker)) {
@@ -714,88 +718,8 @@ export function compileWasmModule(
714
718
  _methodName: "Error",
715
719
  },
716
720
  ),
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
- ),
721
+ helper("__mk_error", [{ name: "msg", type: STR_T }], ANY_T, "mk_error"),
737
722
  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
723
  );
800
724
  }
801
725
 
@@ -806,6 +730,7 @@ export function compileWasmModule(
806
730
 
807
731
  // 2. Pre-scan for needed imports so import func indices are fixed
808
732
  for (const fn of funcDecls) {
733
+ if (fn.intrinsic) prepareWasmIntrinsic(mod, fn);
809
734
  _scanImportsInBody(fn.body, mod);
810
735
  }
811
736
  if (boundaryMeta) scanBoundaryImports(mod, boundaryMeta);
@@ -859,8 +784,11 @@ export function compileWasmModule(
859
784
  fn._forceExport ||
860
785
  (!fn._isGlobalInit &&
861
786
  !fn._isRuntimeHelper &&
862
- !fn._isIoHelper &&
863
- !fn._isPhase7Helper &&
787
+ !fn._isMapHelper &&
788
+ !fn._isInterfaceDispatcher &&
789
+ !fn._isSharedHelper &&
790
+ !fn._isRuntimePanic &&
791
+ !fn._isIndexPanic &&
864
792
  (options.exportAll ||
865
793
  fn.name === "main" ||
866
794
  (fn.name[0] >= "A" && fn.name[0] <= "Z") ||
@@ -899,8 +827,7 @@ export function compileWasmModule(
899
827
  const funcIdx = mod.getStringImportIndex();
900
828
  emitter.pushInstruction({ op: "i32.const", value: strIdx });
901
829
  emitter.pushInstruction({ op: "call", funcIndex: funcIdx });
902
- emitter.pushInstruction("any.convert_extern");
903
- emitter.emitPanicThrow();
830
+ emitter.emitRuntimePanicThrow();
904
831
  } else if (fn._isPushPanic) {
905
832
  const panicNodeTypeIndex = mod.getPanicNodeTypeIndex();
906
833
  const panicGlobal = mod.getPanicGlobalIndex();
@@ -922,8 +849,8 @@ export function compileWasmModule(
922
849
  emitter.emitSharedHelper(fn);
923
850
  } else if (fn._isRuntimeHelper) {
924
851
  emitter.emitRuntimeHelper(fn);
925
- } else if (fn._isIoHelper || fn._isPhase7Helper) {
926
- emitter.emitIoHelper(fn);
852
+ } else if (fn.intrinsic) {
853
+ emitWasmIntrinsic(emitter, fn);
927
854
  } else if (fn.body) {
928
855
  emitter.emitFunctionBody(fn.body);
929
856
  }
@@ -961,7 +888,6 @@ export function compileWasmModule(
961
888
  facade = generateFacade(boundaryMeta, {
962
889
  stringTable: mod.stringTable,
963
890
  callMain: Boolean(options.callMain) && mod.funcMap.has("main"),
964
- stdlibEnv: mod.usesStdlibEnv,
965
891
  });
966
892
  }
967
893
 
@@ -978,6 +904,7 @@ export function compileWasmModule(
978
904
  sourceMappingURL: options.sourceMappingURL ?? null,
979
905
  };
980
906
 
907
+ pruneUnusedFuncs(moduleIR);
981
908
  const wasmBytes = encodeModule(moduleIR);
982
909
  const watText = options.emitWat ? emitWat(moduleIR) : null;
983
910
 
@@ -1037,428 +964,7 @@ function _collectInterfaceDispatchers(progs, funcDecls, mod, checker) {
1037
964
  });
1038
965
  }
1039
966
 
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
967
  for (const info of interfaceCalls.values()) {
1090
968
  funcDecls.push(_makeInterfaceDispatcher(info, checker));
1091
969
  }
1092
970
  }
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,