goscript 0.1.3 → 0.1.4

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 (117) hide show
  1. package/cmd/goscript/cmd_compile.go +28 -8
  2. package/cmd/goscript/cmd_compile_test.go +105 -6
  3. package/compiler/build-flags.go +9 -10
  4. package/compiler/gotest/runner_test.go +127 -0
  5. package/compiler/lowering.go +596 -136
  6. package/compiler/lowering_bench_test.go +350 -0
  7. package/compiler/package-graph.go +61 -4
  8. package/compiler/package-graph_test.go +30 -0
  9. package/compiler/semantic-model-types.go +8 -0
  10. package/compiler/semantic-model.go +447 -22
  11. package/compiler/semantic-model_test.go +138 -0
  12. package/compiler/skeleton_test.go +948 -14
  13. package/compiler/typescript-emitter.go +19 -2
  14. package/dist/gs/builtin/builtin.d.ts +2 -2
  15. package/dist/gs/builtin/builtin.js +20 -0
  16. package/dist/gs/builtin/builtin.js.map +1 -1
  17. package/dist/gs/builtin/slice.js +5 -0
  18. package/dist/gs/builtin/slice.js.map +1 -1
  19. package/dist/gs/builtin/type.d.ts +1 -1
  20. package/dist/gs/builtin/type.js +72 -5
  21. package/dist/gs/builtin/type.js.map +1 -1
  22. package/dist/gs/compress/zlib/index.d.ts +3 -3
  23. package/dist/gs/compress/zlib/index.js +88 -26
  24. package/dist/gs/compress/zlib/index.js.map +1 -1
  25. package/dist/gs/crypto/sha1/index.js +2 -5
  26. package/dist/gs/crypto/sha1/index.js.map +1 -1
  27. package/dist/gs/crypto/sha256/index.js +2 -5
  28. package/dist/gs/crypto/sha256/index.js.map +1 -1
  29. package/dist/gs/crypto/sha512/index.js +2 -5
  30. package/dist/gs/crypto/sha512/index.js.map +1 -1
  31. package/dist/gs/embed/index.d.ts +6 -0
  32. package/dist/gs/embed/index.js +210 -5
  33. package/dist/gs/embed/index.js.map +1 -1
  34. package/dist/gs/fmt/fmt.d.ts +3 -3
  35. package/dist/gs/fmt/fmt.js +29 -16
  36. package/dist/gs/fmt/fmt.js.map +1 -1
  37. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
  38. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  39. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  40. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  41. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  42. package/dist/gs/io/fs/readdir.js +5 -3
  43. package/dist/gs/io/fs/readdir.js.map +1 -1
  44. package/dist/gs/io/io.d.ts +10 -6
  45. package/dist/gs/io/io.js +87 -42
  46. package/dist/gs/io/io.js.map +1 -1
  47. package/dist/gs/math/bits/index.d.ts +26 -5
  48. package/dist/gs/math/bits/index.js +13 -24
  49. package/dist/gs/math/bits/index.js.map +1 -1
  50. package/dist/gs/net/http/index.d.ts +3 -1
  51. package/dist/gs/net/http/index.js +18 -1
  52. package/dist/gs/net/http/index.js.map +1 -1
  53. package/dist/gs/os/types_js.gs.d.ts +6 -2
  54. package/dist/gs/os/types_js.gs.js +169 -8
  55. package/dist/gs/os/types_js.gs.js.map +1 -1
  56. package/dist/gs/reflect/type.d.ts +1 -0
  57. package/dist/gs/reflect/type.js +80 -51
  58. package/dist/gs/reflect/type.js.map +1 -1
  59. package/dist/gs/strings/reader.d.ts +1 -1
  60. package/dist/gs/strings/reader.js +2 -2
  61. package/dist/gs/strings/reader.js.map +1 -1
  62. package/dist/gs/sync/sync.d.ts +2 -1
  63. package/dist/gs/sync/sync.js +37 -16
  64. package/dist/gs/sync/sync.js.map +1 -1
  65. package/dist/gs/syscall/js/index.js +9 -0
  66. package/dist/gs/syscall/js/index.js.map +1 -1
  67. package/dist/gs/testing/testing.js +8 -6
  68. package/dist/gs/testing/testing.js.map +1 -1
  69. package/gs/builtin/builtin.ts +25 -2
  70. package/gs/builtin/runtime-contract.test.ts +45 -0
  71. package/gs/builtin/slice.ts +7 -0
  72. package/gs/builtin/type.ts +85 -5
  73. package/gs/compress/zlib/index.test.ts +97 -0
  74. package/gs/compress/zlib/index.ts +117 -27
  75. package/gs/compress/zlib/meta.json +4 -1
  76. package/gs/crypto/sha1/index.test.ts +19 -2
  77. package/gs/crypto/sha1/index.ts +3 -6
  78. package/gs/crypto/sha256/index.test.ts +14 -2
  79. package/gs/crypto/sha256/index.ts +3 -6
  80. package/gs/crypto/sha512/index.test.ts +17 -2
  81. package/gs/crypto/sha512/index.ts +3 -6
  82. package/gs/embed/index.test.ts +87 -0
  83. package/gs/embed/index.ts +229 -5
  84. package/gs/fmt/fmt.test.ts +41 -3
  85. package/gs/fmt/fmt.ts +40 -17
  86. package/gs/fmt/meta.json +6 -1
  87. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
  88. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
  89. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  90. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  91. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  92. package/gs/io/fs/readdir.test.ts +38 -0
  93. package/gs/io/fs/readdir.ts +7 -3
  94. package/gs/io/io.test.ts +77 -6
  95. package/gs/io/io.ts +114 -52
  96. package/gs/io/meta.json +7 -1
  97. package/gs/math/bits/index.ts +52 -28
  98. package/gs/net/http/index.test.ts +16 -0
  99. package/gs/net/http/index.ts +19 -2
  100. package/gs/os/file_unix_js.test.ts +52 -0
  101. package/gs/os/meta.json +4 -0
  102. package/gs/os/readdir.test.ts +56 -0
  103. package/gs/os/types_js.gs.ts +169 -8
  104. package/gs/reflect/deepequal.test.ts +10 -1
  105. package/gs/reflect/type.ts +91 -56
  106. package/gs/reflect/typefor.test.ts +31 -1
  107. package/gs/strings/meta.json +5 -2
  108. package/gs/strings/reader.test.ts +2 -2
  109. package/gs/strings/reader.ts +2 -2
  110. package/gs/sync/meta.json +1 -0
  111. package/gs/sync/sync.test.ts +41 -1
  112. package/gs/sync/sync.ts +41 -16
  113. package/gs/syscall/js/index.test.ts +18 -0
  114. package/gs/syscall/js/index.ts +12 -0
  115. package/gs/testing/testing.test.ts +32 -3
  116. package/gs/testing/testing.ts +13 -10
  117. package/package.json +1 -1
@@ -1124,7 +1124,7 @@ func isConstGenDecl(decl ast.Decl) bool {
1124
1124
  }
1125
1125
 
1126
1126
  func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([]loweredDecl, []Diagnostic) {
1127
- var decls []loweredDecl
1127
+ decls := make([]loweredDecl, 0, len(decl.Specs))
1128
1128
  var diagnostics []Diagnostic
1129
1129
  for _, spec := range decl.Specs {
1130
1130
  switch typed := spec.(type) {
@@ -1190,7 +1190,7 @@ func (o *LoweringOwner) lowerGenDecl(ctx lowerFileContext, decl *ast.GenDecl) ([
1190
1190
  code := keyword + " " + declName + ": " + variableType + " = " + value
1191
1191
  if lazy {
1192
1192
  keyword = "var"
1193
- code = "var " + declName + ": " + variableType + " = undefined as unknown as " + variableType
1193
+ code = "var " + declName + ": " + variableType
1194
1194
  }
1195
1195
  indexExport := ""
1196
1196
  if ctx.topLevel && name.Name != "_" {
@@ -1402,7 +1402,7 @@ func packageDeclFiles(semPkg *semanticPackage) map[types.Object]string {
1402
1402
  if semPkg == nil || semPkg.source == nil {
1403
1403
  return nil
1404
1404
  }
1405
- declFiles := make(map[types.Object]string)
1405
+ declFiles := make(map[types.Object]string, len(semPkg.declarations))
1406
1406
  for _, decl := range semPkg.declarations {
1407
1407
  if decl.object != nil && decl.position.file != "" {
1408
1408
  declFiles[decl.object] = decl.position.file
@@ -1962,6 +1962,13 @@ func lowerLargeIntegerConstantValue(value constant.Value) (string, bool) {
1962
1962
  return value.ExactString(), true
1963
1963
  }
1964
1964
 
1965
+ func lowerWideIntegerConstantValue(value constant.Value) (string, bool) {
1966
+ if value == nil || value.Kind() != constant.Int || constant.BitLen(value) <= 53 {
1967
+ return "", false
1968
+ }
1969
+ return value.ExactString(), true
1970
+ }
1971
+
1965
1972
  func lowerConstantStringByteSlice(ctx lowerFileContext, expr ast.Expr) (string, bool) {
1966
1973
  value := ctx.semPkg.source.TypesInfo.Types[unwrapParenExpr(expr)].Value
1967
1974
  if value == nil || value.Kind() != constant.String {
@@ -2006,35 +2013,218 @@ func (o *LoweringOwner) lowerGoEmbedValue(
2006
2013
  typ types.Type,
2007
2014
  patterns []string,
2008
2015
  ) (string, []Diagnostic) {
2016
+ if isEmbedFSType(typ) {
2017
+ return o.lowerGoEmbedFSValue(ctx, patterns)
2018
+ }
2009
2019
  if len(patterns) != 1 {
2010
2020
  return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2011
2021
  }
2012
- pattern := strings.Trim(patterns[0], "`\"")
2022
+ cleanPattern, diagnostics := cleanGoEmbedFilePattern(ctx, patterns[0])
2023
+ if len(diagnostics) != 0 {
2024
+ return "", diagnostics
2025
+ }
2026
+ data, diagnostics := readGoEmbedFile(ctx, cleanPattern)
2027
+ if len(diagnostics) != 0 {
2028
+ return "", diagnostics
2029
+ }
2030
+ if isStringType(typ) {
2031
+ return strconv.Quote(string(data)), nil
2032
+ }
2033
+ if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2034
+ return byteSliceLiteral(data), nil
2035
+ }
2036
+ diag := loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")
2037
+ diag.Detail = "target type: " + types.TypeString(typ, func(pkg *types.Package) string {
2038
+ if pkg == nil {
2039
+ return ""
2040
+ }
2041
+ return pkg.Path()
2042
+ })
2043
+ return "", []Diagnostic{diag}
2044
+ }
2045
+
2046
+ func (o *LoweringOwner) lowerGoEmbedFSValue(ctx lowerFileContext, patterns []string) (string, []Diagnostic) {
2047
+ embedAlias := ctx.importPaths["embed"]
2048
+ if embedAlias == "" {
2049
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed FS import")}
2050
+ }
2051
+ if len(patterns) == 0 {
2052
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern list")}
2053
+ }
2054
+
2055
+ filesByPath := make(map[string][]byte)
2056
+ for _, pattern := range patterns {
2057
+ files, diagnostics := expandGoEmbedPattern(ctx, pattern)
2058
+ if len(diagnostics) != 0 {
2059
+ return "", diagnostics
2060
+ }
2061
+ for _, file := range files {
2062
+ filesByPath[file.path] = file.data
2063
+ }
2064
+ }
2065
+ paths := make([]string, 0, len(filesByPath))
2066
+ for path := range filesByPath {
2067
+ paths = append(paths, path)
2068
+ }
2069
+ slices.Sort(paths)
2070
+ entries := make([]string, 0, len(paths))
2071
+ for _, path := range paths {
2072
+ entries = append(entries, "["+strconv.Quote(path)+", "+byteSliceLiteral(filesByPath[path])+"]")
2073
+ }
2074
+ builtinAlias := o.runtimeOwner.BuiltinImport().Alias
2075
+ return builtinAlias + ".markAsStructValue(new " + embedAlias + ".FS(new Map<string, Uint8Array>([" + strings.Join(entries, ", ") + "])))", nil
2076
+ }
2077
+
2078
+ type goEmbedFile struct {
2079
+ path string
2080
+ data []byte
2081
+ }
2082
+
2083
+ func cleanGoEmbedFilePattern(ctx lowerFileContext, pattern string) (string, []Diagnostic) {
2084
+ cleanPattern, _, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2085
+ if len(diagnostics) != 0 {
2086
+ return "", diagnostics
2087
+ }
2088
+ if strings.Contains(cleanPattern, "*") {
2089
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2090
+ }
2091
+ info, err := os.Stat(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2092
+ if err != nil {
2093
+ return "", []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2094
+ }
2095
+ if info.IsDir() {
2096
+ return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed directory target")}
2097
+ }
2098
+ return cleanPattern, nil
2099
+ }
2100
+
2101
+ func cleanGoEmbedPattern(ctx lowerFileContext, pattern string) (string, bool, []Diagnostic) {
2102
+ pattern = strings.Trim(pattern, "`\"")
2103
+ all := false
2104
+ if strings.HasPrefix(pattern, "all:") {
2105
+ all = true
2106
+ pattern = strings.TrimPrefix(pattern, "all:")
2107
+ }
2013
2108
  cleanPattern := path.Clean(pattern)
2014
2109
  if pattern == "" ||
2015
- strings.Contains(pattern, "*") ||
2016
2110
  path.IsAbs(pattern) ||
2017
2111
  cleanPattern == "." ||
2018
2112
  cleanPattern == ".." ||
2019
2113
  strings.HasPrefix(cleanPattern, "../") {
2020
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2114
+ return "", false, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2021
2115
  }
2022
- data, err := os.ReadFile(filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2116
+ return cleanPattern, all, nil
2117
+ }
2118
+
2119
+ func expandGoEmbedPattern(ctx lowerFileContext, pattern string) ([]goEmbedFile, []Diagnostic) {
2120
+ cleanPattern, all, diagnostics := cleanGoEmbedPattern(ctx, pattern)
2121
+ if len(diagnostics) != 0 {
2122
+ return nil, diagnostics
2123
+ }
2124
+ pkgDir := filepath.Dir(ctx.sourcePath)
2125
+ paths := []string{filepath.Join(pkgDir, filepath.FromSlash(cleanPattern))}
2126
+ if strings.Contains(cleanPattern, "*") {
2127
+ matches, err := filepath.Glob(filepath.Join(pkgDir, filepath.FromSlash(cleanPattern)))
2128
+ if err != nil {
2129
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed pattern")}
2130
+ }
2131
+ if len(matches) == 0 {
2132
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed pattern matched no files")}
2133
+ }
2134
+ paths = matches
2135
+ }
2136
+
2137
+ var files []goEmbedFile
2138
+ for _, path := range paths {
2139
+ collected, diagnostics := collectGoEmbedPath(ctx, pkgDir, path, all)
2140
+ if len(diagnostics) != 0 {
2141
+ return nil, diagnostics
2142
+ }
2143
+ files = append(files, collected...)
2144
+ }
2145
+ slices.SortFunc(files, func(a, b goEmbedFile) int {
2146
+ return cmp.Compare(a.path, b.path)
2147
+ })
2148
+ return files, nil
2149
+ }
2150
+
2151
+ func collectGoEmbedPath(ctx lowerFileContext, pkgDir, absPath string, all bool) ([]goEmbedFile, []Diagnostic) {
2152
+ info, err := os.Stat(absPath)
2023
2153
  if err != nil {
2024
- return "", []Diagnostic{{
2025
- Severity: DiagnosticSeverityError,
2026
- Code: "goscript/lowering:embed",
2027
- Message: "failed to read go:embed file",
2028
- Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
2029
- }}
2154
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2030
2155
  }
2031
- if isStringType(typ) {
2032
- return strconv.Quote(string(data)), nil
2156
+ if !info.IsDir() {
2157
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, absPath)
2158
+ if len(diagnostics) != 0 {
2159
+ return nil, diagnostics
2160
+ }
2161
+ return []goEmbedFile{file}, nil
2033
2162
  }
2034
- if slice, ok := types.Unalias(typ).Underlying().(*types.Slice); ok && isByteType(slice.Elem()) {
2035
- return byteSliceLiteral(data), nil
2163
+
2164
+ var files []goEmbedFile
2165
+ if err := filepath.WalkDir(absPath, func(path string, entry os.DirEntry, err error) error {
2166
+ if err != nil {
2167
+ return err
2168
+ }
2169
+ if path != absPath && !all && (strings.HasPrefix(entry.Name(), ".") || strings.HasPrefix(entry.Name(), "_")) {
2170
+ if entry.IsDir() {
2171
+ return filepath.SkipDir
2172
+ }
2173
+ return nil
2174
+ }
2175
+ if entry.IsDir() {
2176
+ return nil
2177
+ }
2178
+ file, diagnostics := readGoEmbedAbsFile(ctx, pkgDir, path)
2179
+ if len(diagnostics) != 0 {
2180
+ return fmt.Errorf("%s", diagnostics[0].Detail)
2181
+ }
2182
+ files = append(files, file)
2183
+ return nil
2184
+ }); err != nil {
2185
+ return nil, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2186
+ }
2187
+ if len(files) == 0 {
2188
+ return nil, []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "go:embed directory matched no files")}
2036
2189
  }
2037
- return "", []Diagnostic{loweringUnsupported("declaration", ctx.semPkg.pkgPath, "unsupported go:embed target type")}
2190
+ return files, nil
2191
+ }
2192
+
2193
+ func readGoEmbedFile(ctx lowerFileContext, cleanPattern string) ([]byte, []Diagnostic) {
2194
+ file, diagnostics := readGoEmbedAbsFile(ctx, filepath.Dir(ctx.sourcePath), filepath.Join(filepath.Dir(ctx.sourcePath), filepath.FromSlash(cleanPattern)))
2195
+ if len(diagnostics) != 0 {
2196
+ return nil, diagnostics
2197
+ }
2198
+ return file.data, nil
2199
+ }
2200
+
2201
+ func readGoEmbedAbsFile(ctx lowerFileContext, pkgDir, absPath string) (goEmbedFile, []Diagnostic) {
2202
+ relPath, err := filepath.Rel(pkgDir, absPath)
2203
+ if err != nil {
2204
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2205
+ }
2206
+ data, err := os.ReadFile(absPath)
2207
+ if err != nil {
2208
+ return goEmbedFile{}, []Diagnostic{goEmbedReadDiagnostic(ctx, err)}
2209
+ }
2210
+ return goEmbedFile{path: filepath.ToSlash(relPath), data: data}, nil
2211
+ }
2212
+
2213
+ func goEmbedReadDiagnostic(ctx lowerFileContext, err error) Diagnostic {
2214
+ return Diagnostic{
2215
+ Severity: DiagnosticSeverityError,
2216
+ Code: "goscript/lowering:embed",
2217
+ Message: "failed to read go:embed file",
2218
+ Detail: ctx.semPkg.pkgPath + ": " + err.Error(),
2219
+ }
2220
+ }
2221
+
2222
+ func isEmbedFSType(typ types.Type) bool {
2223
+ named, _ := types.Unalias(typ).(*types.Named)
2224
+ if named == nil || named.Obj() == nil || named.Obj().Pkg() == nil {
2225
+ return false
2226
+ }
2227
+ return named.Obj().Pkg().Path() == "embed" && named.Obj().Name() == "FS"
2038
2228
  }
2039
2229
 
2040
2230
  func byteSliceLiteral(data []byte) string {
@@ -2202,6 +2392,7 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2202
2392
  name: safeIdentifier(semType.name),
2203
2393
  typeName: runtimeNamedTypeName(semType.named),
2204
2394
  cloneMethod: "clone",
2395
+ fields: make([]loweredStructField, 0, len(semType.fields)),
2205
2396
  }
2206
2397
  for idx, field := range semType.fields {
2207
2398
  structValue := isStructValueType(field.typ)
@@ -2228,9 +2419,12 @@ func (o *LoweringOwner) lowerStructType(ctx lowerFileContext, semType *semanticT
2228
2419
 
2229
2420
  methodDecls := o.methodDeclsForType(ctx, semType.named)
2230
2421
  explicitMethods := make(map[string]bool, len(methodDecls))
2231
- for _, methodDecl := range methodDecls {
2232
- if methodDecl != nil {
2233
- explicitMethods[methodDecl.Name.Name] = true
2422
+ if len(methodDecls) != 0 {
2423
+ lowered.methods = make([]loweredFunction, 0, len(methodDecls))
2424
+ for _, methodDecl := range methodDecls {
2425
+ if methodDecl != nil {
2426
+ explicitMethods[methodDecl.Name.Name] = true
2427
+ }
2234
2428
  }
2235
2429
  }
2236
2430
  var diagnostics []Diagnostic
@@ -3034,105 +3228,113 @@ func (o *LoweringOwner) lowerStmtListAfter(
3034
3228
  ) ([]loweredStmt, []Diagnostic) {
3035
3229
  lowered := make([]loweredStmt, 0, len(stmts))
3036
3230
  var diagnostics []Diagnostic
3037
- gotoSpans := backwardGotoLabelSpans(stmts)
3038
- gotoLabels := make(map[string]bool, len(gotoSpans))
3039
- for label := range gotoSpans {
3040
- gotoLabels[label] = true
3041
- }
3042
- forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3043
- forwardStarts := make(map[int]forwardGotoLabelSpan, len(forwardSpans))
3044
- for label, span := range forwardSpans {
3045
- span.label = label
3046
- group := forwardStarts[span.start]
3047
- if group.forwardLabels == nil {
3048
- group.forwardLabels = make(map[string]bool)
3049
- }
3050
- group.forwardLabels[label] = true
3051
- if group.label == "" || span.labelIdx > group.labelIdx {
3052
- group.label = span.label
3053
- group.start = span.start
3054
- group.labelIdx = span.labelIdx
3055
- }
3056
- forwardStarts[span.start] = group
3231
+ hasGoto := stmtListHasGoto(stmts)
3232
+ var gotoSpans map[string]int
3233
+ var gotoLabels map[string]bool
3234
+ var forwardStarts map[int]forwardGotoLabelSpan
3235
+ if hasGoto {
3236
+ gotoSpans = backwardGotoLabelSpans(stmts)
3237
+ gotoLabels = make(map[string]bool, len(gotoSpans))
3238
+ for label := range gotoSpans {
3239
+ gotoLabels[label] = true
3240
+ }
3241
+ forwardSpans := forwardGotoLabelSpans(stmts, gotoSpans)
3242
+ forwardStarts = make(map[int]forwardGotoLabelSpan, len(forwardSpans))
3243
+ for label, span := range forwardSpans {
3244
+ span.label = label
3245
+ group := forwardStarts[span.start]
3246
+ if group.forwardLabels == nil {
3247
+ group.forwardLabels = make(map[string]bool)
3248
+ }
3249
+ group.forwardLabels[label] = true
3250
+ if group.label == "" || span.labelIdx > group.labelIdx {
3251
+ group.label = span.label
3252
+ group.start = span.start
3253
+ group.labelIdx = span.labelIdx
3254
+ }
3255
+ forwardStarts[span.start] = group
3256
+ }
3057
3257
  }
3058
3258
  for idx := 0; idx < len(stmts); idx++ {
3059
3259
  stmt := stmts[idx]
3060
3260
  startLine := sourceLine(ctx, stmt.Pos())
3061
3261
  leading := leadingStmtLines(ctx, prevEndLine, startLine)
3062
- if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
3063
- clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
3064
- diagnostics = append(diagnostics, clusterDiagnostics...)
3065
- lowered = append(lowered, clusterLowered...)
3066
- if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
3067
- prevEndLine = endLine
3068
- }
3069
- idx = cluster.endIdx
3070
- continue
3071
- }
3072
- if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
3073
- loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3074
- ctx,
3075
- gotoLabels,
3076
- span.label,
3077
- span.labelIdx,
3078
- span.endIdx,
3079
- span.forwardLabel,
3080
- stmts,
3081
- leading,
3082
- )
3083
- diagnostics = append(diagnostics, loopDiagnostics...)
3084
- lowered = append(lowered, loop...)
3085
- if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
3086
- prevEndLine = endLine
3087
- }
3088
- idx = span.endIdx
3089
- continue
3090
- }
3091
- if span, ok := forwardStarts[idx]; ok {
3092
- bodyStmts := stmts[idx:span.labelIdx]
3093
- body, bodyDiagnostics := o.lowerStmtListAfter(
3094
- ctx.withForwardGotos(span.forwardLabels),
3095
- bodyStmts,
3096
- prevEndLine,
3097
- )
3098
- diagnostics = append(diagnostics, bodyDiagnostics...)
3099
- block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3100
- if len(leading) != 0 {
3101
- block.leading = append(leading, block.leading...)
3102
- }
3103
- lowered = append(lowered, block)
3104
- if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
3105
- labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3106
- diagnostics = append(diagnostics, labelDiagnostics...)
3107
- lowered = append(lowered, labelLowered...)
3108
- if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3262
+ if hasGoto {
3263
+ if cluster, ok := gotoStateClusterAt(stmts, idx); ok {
3264
+ clusterLowered, clusterDiagnostics := o.lowerGotoStateCluster(ctx, stmts, cluster, leading)
3265
+ diagnostics = append(diagnostics, clusterDiagnostics...)
3266
+ lowered = append(lowered, clusterLowered...)
3267
+ if endLine := sourceLine(ctx, stmts[cluster.endIdx].End()); endLine != 0 {
3109
3268
  prevEndLine = endLine
3110
3269
  }
3270
+ idx = cluster.endIdx
3271
+ continue
3111
3272
  }
3112
- idx = span.labelIdx
3113
- continue
3114
- }
3115
- if labeled, ok := stmt.(*ast.LabeledStmt); ok {
3116
- label := safeIdentifier(labeled.Label.Name)
3117
- if endIdx, ok := gotoSpans[label]; ok {
3273
+ if span, ok := leadingGotoBackwardLoopSpan(stmts, idx, gotoSpans); ok {
3118
3274
  loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3119
3275
  ctx,
3120
3276
  gotoLabels,
3121
- label,
3122
- idx,
3123
- endIdx,
3124
- "",
3277
+ span.label,
3278
+ span.labelIdx,
3279
+ span.endIdx,
3280
+ span.forwardLabel,
3125
3281
  stmts,
3126
3282
  leading,
3127
3283
  )
3128
3284
  diagnostics = append(diagnostics, loopDiagnostics...)
3129
3285
  lowered = append(lowered, loop...)
3130
- if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3286
+ if endLine := sourceLine(ctx, stmts[span.endIdx].End()); endLine != 0 {
3131
3287
  prevEndLine = endLine
3132
3288
  }
3133
- idx = endIdx
3289
+ idx = span.endIdx
3134
3290
  continue
3135
3291
  }
3292
+ if span, ok := forwardStarts[idx]; ok {
3293
+ bodyStmts := stmts[idx:span.labelIdx]
3294
+ body, bodyDiagnostics := o.lowerStmtListAfter(
3295
+ ctx.withForwardGotos(span.forwardLabels),
3296
+ bodyStmts,
3297
+ prevEndLine,
3298
+ )
3299
+ diagnostics = append(diagnostics, bodyDiagnostics...)
3300
+ block := loweredStmt{hasBlock: true, text: span.label + ":", children: body}
3301
+ if len(leading) != 0 {
3302
+ block.leading = append(leading, block.leading...)
3303
+ }
3304
+ lowered = append(lowered, block)
3305
+ if labeled, ok := stmts[span.labelIdx].(*ast.LabeledStmt); ok {
3306
+ labelLowered, labelDiagnostics := o.lowerStmt(ctx, labeled.Stmt)
3307
+ diagnostics = append(diagnostics, labelDiagnostics...)
3308
+ lowered = append(lowered, labelLowered...)
3309
+ if endLine := sourceLine(ctx, labeled.End()); endLine != 0 {
3310
+ prevEndLine = endLine
3311
+ }
3312
+ }
3313
+ idx = span.labelIdx
3314
+ continue
3315
+ }
3316
+ if labeled, ok := stmt.(*ast.LabeledStmt); ok {
3317
+ label := safeIdentifier(labeled.Label.Name)
3318
+ if endIdx, ok := gotoSpans[label]; ok {
3319
+ loop, loopDiagnostics := o.lowerBackwardGotoLoop(
3320
+ ctx,
3321
+ gotoLabels,
3322
+ label,
3323
+ idx,
3324
+ endIdx,
3325
+ "",
3326
+ stmts,
3327
+ leading,
3328
+ )
3329
+ diagnostics = append(diagnostics, loopDiagnostics...)
3330
+ lowered = append(lowered, loop...)
3331
+ if endLine := sourceLine(ctx, stmts[endIdx].End()); endLine != 0 {
3332
+ prevEndLine = endLine
3333
+ }
3334
+ idx = endIdx
3335
+ continue
3336
+ }
3337
+ }
3136
3338
  }
3137
3339
  if stmtCtx, nextCtx, ok := o.lowerDeclStatementContext(ctx, stmt); ok {
3138
3340
  stmtLowered, stmtDiagnostics := o.lowerStmt(stmtCtx, stmt)
@@ -3204,7 +3406,7 @@ func (o *LoweringOwner) lowerDeclStatementContext(
3204
3406
  if def == nil || aliases[def] != "" {
3205
3407
  continue
3206
3408
  }
3207
- if shortDeclDefShadowsOuterName(name.Name, def) {
3409
+ if shortDeclDefShadowsOuterName(ctx, name.Name, def) || valueSpecUsesOuterName(ctx, valueSpec, name.Name, def) {
3208
3410
  aliases[def] = ctx.tempName("Shadow")
3209
3411
  }
3210
3412
  }
@@ -3452,9 +3654,30 @@ type leadingGotoBackwardLoop struct {
3452
3654
  }
3453
3655
 
3454
3656
  func stmtListNeedsLoopBranchLabel(stmts []ast.Stmt) bool {
3657
+ if !stmtListHasGoto(stmts) {
3658
+ return false
3659
+ }
3455
3660
  return len(backwardGotoLabelSpans(stmts)) != 0
3456
3661
  }
3457
3662
 
3663
+ func stmtListHasGoto(stmts []ast.Stmt) bool {
3664
+ for _, stmt := range stmts {
3665
+ hasGoto := false
3666
+ ast.Inspect(stmt, func(node ast.Node) bool {
3667
+ branch, ok := node.(*ast.BranchStmt)
3668
+ if ok && branch.Tok == token.GOTO && branch.Label != nil {
3669
+ hasGoto = true
3670
+ return false
3671
+ }
3672
+ return !hasGoto
3673
+ })
3674
+ if hasGoto {
3675
+ return true
3676
+ }
3677
+ }
3678
+ return false
3679
+ }
3680
+
3458
3681
  func backwardGotoLabelSpans(stmts []ast.Stmt) map[string]int {
3459
3682
  seenLabels := make(map[string]bool)
3460
3683
  spans := make(map[string]int)
@@ -3734,15 +3957,11 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3734
3957
  if starTarget && stmt.Tok != token.DEFINE {
3735
3958
  pointer, pointerDiagnostics := o.lowerPointerStorageExpr(ctx, star.X)
3736
3959
  diagnostics = append(diagnostics, pointerDiagnostics...)
3737
- if stmt.Tok == token.AND_NOT_ASSIGN {
3738
- stmts = append(stmts, loweredStmt{text: pointer + " = " + pointer + " & ~(" + right + ")"})
3739
- continue
3740
- }
3741
3960
  if value, ok := integerQuotientAssignExpr(targetType, pointer, right, stmt.Tok); ok {
3742
3961
  stmts = append(stmts, loweredStmt{text: value})
3743
3962
  continue
3744
3963
  }
3745
- stmts = append(stmts, loweredStmt{text: pointer + " " + stmt.Tok.String() + " " + right})
3964
+ stmts = append(stmts, loweredStmt{text: pointer + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, pointer, right, stmt.Tok)})
3746
3965
  continue
3747
3966
  }
3748
3967
  if isShortDecl {
@@ -3752,10 +3971,6 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3752
3971
  stmts = append(stmts, loweredStmt{text: "let " + left + o.shortDeclTypeAnnotation(ctx, lhs, stmt.Rhs[idx]) + " = " + right})
3753
3972
  continue
3754
3973
  }
3755
- if stmt.Tok == token.AND_NOT_ASSIGN {
3756
- stmts = append(stmts, loweredStmt{text: left + " = " + left + " & ~(" + right + ")"})
3757
- continue
3758
- }
3759
3974
  if helper, ok := wideIntegerAssignHelper(targetType, stmt.Tok); ok {
3760
3975
  stmts = append(stmts, loweredStmt{text: left + " = " + o.runtimeOwner.QualifiedHelper(helper) + "(" + left + ", " + right + ")"})
3761
3976
  continue
@@ -3768,6 +3983,10 @@ func (o *LoweringOwner) lowerAssignStmt(ctx lowerFileContext, stmt *ast.AssignSt
3768
3983
  if stmt.Tok == token.DEFINE {
3769
3984
  op = "="
3770
3985
  }
3986
+ if stmt.Tok != token.ASSIGN && stmt.Tok != token.DEFINE {
3987
+ stmts = append(stmts, loweredStmt{text: left + " = " + lowerCompoundAssignValue(o.runtimeOwner, targetType, left, right, stmt.Tok)})
3988
+ continue
3989
+ }
3771
3990
  stmts = append(stmts, loweredStmt{text: left + " " + op + " " + right})
3772
3991
  }
3773
3992
  return stmts, diagnostics
@@ -3810,6 +4029,7 @@ func lowerCompoundAssignValue(
3810
4029
  if value, ok := integerQuotientAssignValueExpr(targetType, left, right, tok); ok {
3811
4030
  return value
3812
4031
  }
4032
+ right = "(" + right + ")"
3813
4033
  switch tok {
3814
4034
  case token.ADD_ASSIGN:
3815
4035
  return left + " + " + right
@@ -3830,6 +4050,9 @@ func lowerCompoundAssignValue(
3830
4050
  case token.SHL_ASSIGN:
3831
4051
  return left + " << " + right
3832
4052
  case token.SHR_ASSIGN:
4053
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits <= 32 {
4054
+ return "(" + left + " >>> " + right + ") >>> 0"
4055
+ }
3833
4056
  return left + " >> " + right
3834
4057
  case token.AND_NOT_ASSIGN:
3835
4058
  return left + " & ~(" + right + ")"
@@ -3866,30 +4089,31 @@ func integerQuotientAssignValueExpr(targetType types.Type, left string, right st
3866
4089
  }
3867
4090
 
3868
4091
  func wideIntegerAssignHelper(targetType types.Type, tok token.Token) (RuntimeHelper, bool) {
3869
- if !isFixedWideIntegerType(targetType) {
4092
+ if !isRuntimeWideIntegerType(targetType) {
3870
4093
  return "", false
3871
4094
  }
4095
+ signed := isFixedSignedWideIntegerType(targetType)
3872
4096
  switch tok {
3873
4097
  case token.SHL_ASSIGN:
3874
- return RuntimeHelperUint64Shl, true
4098
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shl, RuntimeHelperInt64Shl), true
3875
4099
  case token.SHR_ASSIGN:
3876
- return RuntimeHelperUint64Shr, true
4100
+ return wideIntegerHelper(signed, RuntimeHelperUint64Shr, RuntimeHelperInt64Shr), true
3877
4101
  case token.MUL_ASSIGN:
3878
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
4102
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mul, RuntimeHelperInt64Mul), true
3879
4103
  case token.QUO_ASSIGN:
3880
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
4104
+ return wideIntegerHelper(signed, RuntimeHelperUint64Div, RuntimeHelperInt64Div), true
3881
4105
  case token.REM_ASSIGN:
3882
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
4106
+ return wideIntegerHelper(signed, RuntimeHelperUint64Mod, RuntimeHelperInt64Mod), true
3883
4107
  case token.ADD_ASSIGN:
3884
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
4108
+ return wideIntegerHelper(signed, RuntimeHelperUint64Add, RuntimeHelperInt64Add), true
3885
4109
  case token.SUB_ASSIGN:
3886
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
4110
+ return wideIntegerHelper(signed, RuntimeHelperUint64Sub, RuntimeHelperInt64Sub), true
3887
4111
  case token.AND_ASSIGN:
3888
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64And, RuntimeHelperInt64And), true
4112
+ return wideIntegerHelper(signed, RuntimeHelperUint64And, RuntimeHelperInt64And), true
3889
4113
  case token.OR_ASSIGN:
3890
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
4114
+ return wideIntegerHelper(signed, RuntimeHelperUint64Or, RuntimeHelperInt64Or), true
3891
4115
  case token.XOR_ASSIGN:
3892
- return wideIntegerHelper(isFixedSignedWideIntegerType(targetType), RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
4116
+ return wideIntegerHelper(signed, RuntimeHelperUint64Xor, RuntimeHelperInt64Xor), true
3893
4117
  default:
3894
4118
  return "", false
3895
4119
  }
@@ -4172,7 +4396,7 @@ func (o *LoweringOwner) lowerShortDeclNewShadowAliases(
4172
4396
  if entry.def == nil || aliases[entry.def] != "" {
4173
4397
  continue
4174
4398
  }
4175
- if shortDeclDefShadowsOuterName(entry.name, entry.def) {
4399
+ if shortDeclDefShadowsOuterName(ctx, entry.name, entry.def) {
4176
4400
  aliases[entry.def] = ctx.tempName("Shadow")
4177
4401
  }
4178
4402
  }
@@ -4201,12 +4425,24 @@ func shortDeclShadowNonValueIdents(ctx lowerFileContext, expr ast.Expr) map[*ast
4201
4425
  return idents
4202
4426
  }
4203
4427
 
4204
- func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
4428
+ func shortDeclDefShadowsOuterName(ctx lowerFileContext, name string, def types.Object) bool {
4205
4429
  for scope := def.Parent(); scope != nil; scope = scope.Parent() {
4206
4430
  if scope == def.Parent() {
4207
4431
  continue
4208
4432
  }
4209
4433
  obj := scope.Lookup(name)
4434
+ if scope.Parent() == types.Universe {
4435
+ if obj == nil {
4436
+ return false
4437
+ }
4438
+ if _, isTypeName := obj.(*types.TypeName); isTypeName {
4439
+ return true
4440
+ }
4441
+ if _, isFunc := obj.(*types.Func); isFunc {
4442
+ return sameSourceFile(ctx, obj.Pos(), def.Pos()) && obj.Pos() < def.Pos()
4443
+ }
4444
+ return false
4445
+ }
4210
4446
  if obj != nil && obj.Pos().IsValid() && obj.Pos() < def.Pos() {
4211
4447
  return true
4212
4448
  }
@@ -4214,6 +4450,40 @@ func shortDeclDefShadowsOuterName(name string, def types.Object) bool {
4214
4450
  return false
4215
4451
  }
4216
4452
 
4453
+ func sameSourceFile(ctx lowerFileContext, left token.Pos, right token.Pos) bool {
4454
+ if !left.IsValid() || !right.IsValid() || ctx.semPkg == nil || ctx.semPkg.source == nil {
4455
+ return false
4456
+ }
4457
+ leftPos := sourcePos(ctx.semPkg.source, left)
4458
+ rightPos := sourcePos(ctx.semPkg.source, right)
4459
+ return leftPos.file != "" && leftPos.file == rightPos.file
4460
+ }
4461
+
4462
+ func valueSpecUsesOuterName(ctx lowerFileContext, spec *ast.ValueSpec, name string, def types.Object) bool {
4463
+ if spec == nil || name == "" || def == nil {
4464
+ return false
4465
+ }
4466
+ usesOuter := false
4467
+ for _, value := range spec.Values {
4468
+ ast.Inspect(value, func(node ast.Node) bool {
4469
+ ident, ok := node.(*ast.Ident)
4470
+ if !ok || ident.Name != name {
4471
+ return true
4472
+ }
4473
+ obj := ctx.semPkg.source.TypesInfo.Uses[ident]
4474
+ if obj != nil && obj != def {
4475
+ usesOuter = true
4476
+ return false
4477
+ }
4478
+ return true
4479
+ })
4480
+ if usesOuter {
4481
+ return true
4482
+ }
4483
+ }
4484
+ return false
4485
+ }
4486
+
4217
4487
  func (o *LoweringOwner) mapIndexDefaultUsesShortDeclName(
4218
4488
  ctx lowerFileContext,
4219
4489
  rhs ast.Expr,
@@ -5273,7 +5543,7 @@ func (o *LoweringOwner) lowerRangeFuncStmt(
5273
5543
  diagnostics = append(diagnostics, assignmentDiagnostics...)
5274
5544
  body = append(assignments, body...)
5275
5545
  }
5276
- async := ctx.asyncFunction
5546
+ async := ctx.asyncFunction || stmtsContainAwait(body) || o.rangeFunctionValueNeedsAwait(ctx, stmt.X)
5277
5547
 
5278
5548
  return loweredStmt{rangeFunc: &loweredRangeFunc{
5279
5549
  value: rangeValue,
@@ -5902,6 +6172,19 @@ func (o *LoweringOwner) lowerComplexEqualityExpr(ctx lowerFileContext, expr *ast
5902
6172
  return value, true
5903
6173
  }
5904
6174
 
6175
+ func (o *LoweringOwner) lowerStructEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
6176
+ leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
6177
+ rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
6178
+ if !isStructComparableType(leftType) || !isStructComparableType(rightType) {
6179
+ return "", false
6180
+ }
6181
+ value := o.runtimeOwner.QualifiedHelper(RuntimeHelperComparableEqual) + "(" + left + ", " + right + ")"
6182
+ if expr.Op == token.NEQ {
6183
+ value = "!" + value
6184
+ }
6185
+ return value, true
6186
+ }
6187
+
5905
6188
  func (o *LoweringOwner) lowerStringEqualityExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
5906
6189
  leftType := ctx.semPkg.source.TypesInfo.TypeOf(expr.X)
5907
6190
  rightType := ctx.semPkg.source.TypesInfo.TypeOf(expr.Y)
@@ -6030,6 +6313,9 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6030
6313
  if value, ok := o.lowerComplexEqualityExpr(ctx, typed, left, right); ok {
6031
6314
  return value, append(leftDiagnostics, rightDiagnostics...)
6032
6315
  }
6316
+ if value, ok := o.lowerStructEqualityExpr(ctx, typed, left, right); ok {
6317
+ return value, append(leftDiagnostics, rightDiagnostics...)
6318
+ }
6033
6319
  if value, ok := o.lowerStringEqualityExpr(ctx, typed, left, right); ok {
6034
6320
  return value, append(leftDiagnostics, rightDiagnostics...)
6035
6321
  }
@@ -6073,6 +6359,10 @@ func (o *LoweringOwner) lowerExpr(ctx lowerFileContext, expr ast.Expr) (string,
6073
6359
  return lowerPrefixUnaryExpr(typed.Op, value), diagnostics
6074
6360
  }
6075
6361
  if typed.Op == token.XOR {
6362
+ if bits, ok := unsignedIntegerBits(ctx.semPkg.source.TypesInfo.TypeOf(typed)); ok && bits <= 32 {
6363
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) +
6364
+ "(~" + value + ", " + strconv.Itoa(bits) + ")", diagnostics
6365
+ }
6076
6366
  return "~" + value, diagnostics
6077
6367
  }
6078
6368
  return value, append(diagnostics, loweringUnsupported("expression", ctx.semPkg.pkgPath, "unsupported unary operator"))
@@ -6155,7 +6445,7 @@ func isLegacyOctalLiteral(value string) bool {
6155
6445
  func (o *LoweringOwner) lowerFuncLit(ctx lowerFileContext, lit *ast.FuncLit) (string, bool, []Diagnostic) {
6156
6446
  signature, _ := ctx.semPkg.source.TypesInfo.TypeOf(lit).(*types.Signature)
6157
6447
  deferState := &loweredDeferState{}
6158
- bodyCtx := ctx.withSignature(signature).withDeferState(deferState).withoutRangeBranch()
6448
+ bodyCtx := ctx.withSignature(signature).withAsyncFunction(false).withDeferState(deferState).withoutRangeBranch()
6159
6449
  asyncCompatibleParams := funcLiteralNeedsAsyncFunctionParamCalls(signature)
6160
6450
  if asyncCompatibleParams || funcLiteralUsesFunctionIdentifierCall(ctx, lit) {
6161
6451
  bodyCtx = bodyCtx.withAsyncFunction(true)
@@ -6276,7 +6566,7 @@ func (o *LoweringOwner) lowerIdent(ctx lowerFileContext, ident *ast.Ident, raw b
6276
6566
  }
6277
6567
  return alias
6278
6568
  }
6279
- if constObj, ok := obj.(*types.Const); ok && ctx.localAliases[obj] != "" {
6569
+ if constObj, ok := obj.(*types.Const); ok && !raw {
6280
6570
  if constValue, ok := lowerConstantValue(constObj.Val()); ok {
6281
6571
  return constValue
6282
6572
  }
@@ -6962,6 +7252,8 @@ func (o *LoweringOwner) lowerConversionExpr(
6962
7252
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperRunesToString) + "(" + value + ")", diagnostics
6963
7253
  case isByteSliceType(sourceType):
6964
7254
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperBytesToString) + "(" + value + ")", diagnostics
7255
+ case overrideNamedStringType(ctx, o, sourceType):
7256
+ return "String(" + value + ")", diagnostics
6965
7257
  case isStringType(sourceType):
6966
7258
  return value, diagnostics
6967
7259
  case isNumericType(sourceType):
@@ -7020,7 +7312,7 @@ func (o *LoweringOwner) lowerConversionExpr(
7020
7312
  return renderNamedStructConversion(conversion), diagnostics
7021
7313
  }
7022
7314
  if isNumericType(targetType) {
7023
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr.Args[0]); ok {
7315
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr.Args[0], targetType); ok {
7024
7316
  return constantValue, diagnostics
7025
7317
  }
7026
7318
  }
@@ -7052,8 +7344,8 @@ func (o *LoweringOwner) lowerConversionExpr(
7052
7344
  }
7053
7345
 
7054
7346
  func (o *LoweringOwner) lowerWideIntegerBinaryExpr(ctx lowerFileContext, expr *ast.BinaryExpr, left string, right string) (string, bool) {
7055
- resultWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7056
- leftWide := isFixedWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
7347
+ resultWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr))
7348
+ leftWide := isRuntimeWideIntegerType(ctx.semPkg.source.TypesInfo.TypeOf(expr.X))
7057
7349
  if !resultWide && !leftWide {
7058
7350
  return "", false
7059
7351
  }
@@ -7329,6 +7621,12 @@ func (o *LoweringOwner) lowerPointerReceiverMethodCall(
7329
7621
  methodMemberName(selector.Sel.Name) + "(" + strings.Join(args, ", ") + ")"
7330
7622
  return call, diagnostics, true
7331
7623
  }
7624
+ if crossPackageUnexportedNamedType(ctx, receiver) {
7625
+ call := o.runtimeOwner.QualifiedHelper(RuntimeHelperPointerValue) +
7626
+ "<any>(" + receiverExpr + ")." + methodMemberName(selector.Sel.Name) +
7627
+ "(" + strings.Join(args, ", ") + ")"
7628
+ return call, diagnostics, true
7629
+ }
7332
7630
  callArgs := append([]string{receiverExpr}, args...)
7333
7631
  call := o.namedTypeExpr(ctx, receiver) + ".prototype." + selector.Sel.Name + ".call(" + strings.Join(callArgs, ", ") + ")"
7334
7632
  return call, diagnostics, true
@@ -8492,12 +8790,40 @@ func (o *LoweringOwner) lowerStructCompositeLit(
8492
8790
  func compositeLiteralFieldNeedsPreEval(ctx lowerFileContext, expr ast.Expr) bool {
8493
8791
  switch typed := unwrapParenExpr(expr).(type) {
8494
8792
  case *ast.CallExpr:
8793
+ for _, arg := range typed.Args {
8794
+ if compositeLiteralFieldNeedsPreEval(ctx, arg) {
8795
+ return true
8796
+ }
8797
+ }
8495
8798
  if ident, ok := typed.Fun.(*ast.Ident); ok && isBuiltinCallTarget(ctx, ident) {
8496
8799
  return false
8497
8800
  }
8498
8801
  return typeFromExpr(ctx, typed.Fun) == nil
8499
8802
  case *ast.UnaryExpr:
8500
- return typed.Op == token.ARROW
8803
+ return typed.Op == token.ARROW || compositeLiteralFieldNeedsPreEval(ctx, typed.X)
8804
+ case *ast.BinaryExpr:
8805
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8806
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Y)
8807
+ case *ast.IndexExpr:
8808
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8809
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Index)
8810
+ case *ast.IndexListExpr:
8811
+ if compositeLiteralFieldNeedsPreEval(ctx, typed.X) {
8812
+ return true
8813
+ }
8814
+ for _, index := range typed.Indices {
8815
+ if compositeLiteralFieldNeedsPreEval(ctx, index) {
8816
+ return true
8817
+ }
8818
+ }
8819
+ return false
8820
+ case *ast.SliceExpr:
8821
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X) ||
8822
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Low) ||
8823
+ compositeLiteralFieldNeedsPreEval(ctx, typed.High) ||
8824
+ compositeLiteralFieldNeedsPreEval(ctx, typed.Max)
8825
+ case *ast.StarExpr:
8826
+ return compositeLiteralFieldNeedsPreEval(ctx, typed.X)
8501
8827
  default:
8502
8828
  return false
8503
8829
  }
@@ -8562,6 +8888,9 @@ func (o *LoweringOwner) lowerArrayCompositeLit(
8562
8888
  lit *ast.CompositeLit,
8563
8889
  array *types.Array,
8564
8890
  ) (string, []Diagnostic) {
8891
+ if len(lit.Elts) == 0 && isByteType(array.Elem()) {
8892
+ return "new Uint8Array(" + strconv.FormatInt(array.Len(), 10) + ")", nil
8893
+ }
8565
8894
  values := make([]string, int(array.Len()))
8566
8895
  for idx := range values {
8567
8896
  values[idx] = o.lowerZeroValueExprFor(ctx, array.Elem())
@@ -8715,7 +9044,7 @@ func (o *LoweringOwner) lowerValueForTarget(
8715
9044
  }
8716
9045
  }
8717
9046
  if isNumericType(targetType) {
8718
- if constantValue, ok := lowerRealNumericConstantExpr(ctx, expr); ok {
9047
+ if constantValue, ok := o.lowerNumericConstantExprForTarget(ctx, expr, targetType); ok {
8719
9048
  return constantValue
8720
9049
  }
8721
9050
  }
@@ -8744,6 +9073,28 @@ func lowerRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) (string,
8744
9073
  }
8745
9074
  }
8746
9075
 
9076
+ func (o *LoweringOwner) lowerNumericConstantExprForTarget(ctx lowerFileContext, expr ast.Expr, targetType types.Type) (string, bool) {
9077
+ if ctx.semPkg == nil || ctx.semPkg.source == nil {
9078
+ return "", false
9079
+ }
9080
+ tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]
9081
+ if ok && tv.Value != nil {
9082
+ if bits, ok := unsignedIntegerBits(targetType); ok && bits >= 64 {
9083
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9084
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperUint) + "(" +
9085
+ strconv.Quote(value) + ", 64)", true
9086
+ }
9087
+ }
9088
+ if bits, ok := signedIntegerBits(targetType); ok && bits >= 64 {
9089
+ if value, ok := lowerWideIntegerConstantValue(tv.Value); ok {
9090
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperInt) + "(" +
9091
+ strconv.Quote(value) + ", 64)", true
9092
+ }
9093
+ }
9094
+ }
9095
+ return lowerRealNumericConstantExpr(ctx, expr)
9096
+ }
9097
+
8747
9098
  func isRealNumericConstantExpr(ctx lowerFileContext, expr ast.Expr) bool {
8748
9099
  if ctx.semPkg != nil && ctx.semPkg.source != nil {
8749
9100
  if tv, ok := ctx.semPkg.source.TypesInfo.Types[expr]; ok && tv.Value != nil {
@@ -8789,6 +9140,9 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8789
9140
  return wrapper
8790
9141
  }
8791
9142
  }
9143
+ if wrapper := o.lowerNumericInterfaceWrapper(ctx, targetType, sourceType, value); wrapper != "" {
9144
+ return wrapper
9145
+ }
8792
9146
  if isInterfaceType(targetType) && isStructValueType(sourceType) {
8793
9147
  if cloneStructValue {
8794
9148
  value = o.lowerStructClone(value)
@@ -8837,6 +9191,25 @@ func (o *LoweringOwner) lowerValueForTargetTypes(
8837
9191
  return value
8838
9192
  }
8839
9193
 
9194
+ func (o *LoweringOwner) lowerNumericInterfaceWrapper(
9195
+ ctx lowerFileContext,
9196
+ targetType types.Type,
9197
+ sourceType types.Type,
9198
+ value string,
9199
+ ) string {
9200
+ if targetType == nil || sourceType == nil || !isInterfaceType(targetType) || isInterfaceType(sourceType) {
9201
+ return ""
9202
+ }
9203
+ basic, ok := types.Unalias(sourceType).(*types.Basic)
9204
+ if !ok || basic.Info()&types.IsNumeric == 0 || basic.Info()&types.IsUntyped != 0 {
9205
+ return ""
9206
+ }
9207
+ return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
9208
+ "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
9209
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", {}, " +
9210
+ o.runtimeTypeInfoExpr(sourceType) + ")"
9211
+ }
9212
+
8840
9213
  func isBasicFixedWideIntegerType(typ types.Type) bool {
8841
9214
  basic, ok := types.Unalias(typ).(*types.Basic)
8842
9215
  if !ok {
@@ -8876,7 +9249,8 @@ func (o *LoweringOwner) lowerNamedValueInterfaceWrapper(
8876
9249
  }
8877
9250
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8878
9251
  "<" + o.tsTypeFor(ctx, targetType) + ">(" + value + ", " +
8879
- strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ")"
9252
+ strconv.Quote(goRuntimeTypeString(sourceType)) + ", " + methods + ", " +
9253
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8880
9254
  }
8881
9255
 
8882
9256
  func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceType types.Type, value string) string {
@@ -8898,7 +9272,8 @@ func (o *LoweringOwner) lowerPrimitiveErrorWrapper(ctx lowerFileContext, sourceT
8898
9272
  }
8899
9273
  return o.runtimeOwner.QualifiedHelper(RuntimeHelperNamedValueInterfaceValue) +
8900
9274
  "<$.GoError>(" + value + ", " + strconv.Quote(goRuntimeTypeString(sourceType)) +
8901
- ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "})"
9275
+ ", {\"Error\": " + o.methodFunctionExpr(ctx, named, fn, "Error") + "}, " +
9276
+ o.runtimeTypeInfoExpr(sourceType) + ")"
8902
9277
  }
8903
9278
 
8904
9279
  func (o *LoweringOwner) lowerStructClone(value string) string {
@@ -8955,7 +9330,7 @@ func (o *LoweringOwner) lowerZeroValueExprFor(ctx lowerFileContext, typ types.Ty
8955
9330
 
8956
9331
  func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ types.Type) string {
8957
9332
  if isFunctionType(typ) {
8958
- return "null as " + o.tsTypeFor(ctx, typ)
9333
+ return "null as unknown as " + o.tsFunctionZeroValueTypeFor(ctx, typ)
8959
9334
  }
8960
9335
  typeParam, ok := types.Unalias(typ).(*types.TypeParam)
8961
9336
  if !ok {
@@ -8972,6 +9347,13 @@ func (o *LoweringOwner) lowerDeclarationZeroValueExpr(ctx lowerFileContext, typ
8972
9347
  "(__typeArgs, " + strconv.Quote(typeParam.Obj().Name()) + ", " + zeroValueExpr(typ) + ")"
8973
9348
  }
8974
9349
 
9350
+ func (o *LoweringOwner) tsFunctionZeroValueTypeFor(ctx lowerFileContext, typ types.Type) string {
9351
+ if signature := unnamedSignatureForType(typ); signature != nil {
9352
+ return o.tsAsyncCompatibleFunctionTypeFor(ctx, signature)
9353
+ }
9354
+ return o.tsTypeFor(ctx, typ)
9355
+ }
9356
+
8975
9357
  func (o *LoweringOwner) runtimeTypeInfoExpr(typ types.Type) string {
8976
9358
  return o.runtimeTypeInfoExprWithSeen(typ, make(map[types.Type]bool))
8977
9359
  }
@@ -9588,6 +9970,11 @@ func namedFunctionType(typ types.Type) *types.Named {
9588
9970
  return named
9589
9971
  }
9590
9972
 
9973
+ func overrideNamedStringType(ctx lowerFileContext, owner *LoweringOwner, typ types.Type) bool {
9974
+ named, _ := types.Unalias(typ).(*types.Named)
9975
+ return named != nil && isStringType(named) && owner.typeUsesOverride(named)
9976
+ }
9977
+
9591
9978
  func isBuiltinErrorType(typ types.Type) bool {
9592
9979
  if typ == nil {
9593
9980
  return false
@@ -9738,6 +10125,16 @@ func isStructValueType(typ types.Type) bool {
9738
10125
  return namedStructType(typ) != nil
9739
10126
  }
9740
10127
 
10128
+ func isStructComparableType(typ types.Type) bool {
10129
+ if typ == nil {
10130
+ return false
10131
+ }
10132
+ if _, ok := types.Unalias(typ).Underlying().(*types.Struct); !ok {
10133
+ return false
10134
+ }
10135
+ return types.Comparable(typ)
10136
+ }
10137
+
9741
10138
  func isPointerToStructType(typ types.Type) bool {
9742
10139
  pointer, ok := types.Unalias(typ).Underlying().(*types.Pointer)
9743
10140
  if !ok {
@@ -9917,6 +10314,14 @@ func isFixedSignedWideIntegerType(typ types.Type) bool {
9917
10314
  return ok && basic.Kind() == types.Int64
9918
10315
  }
9919
10316
 
10317
+ func isRuntimeWideIntegerType(typ types.Type) bool {
10318
+ if isFixedWideIntegerType(typ) {
10319
+ return true
10320
+ }
10321
+ bits, ok := unsignedIntegerBits(typ)
10322
+ return ok && bits > 32
10323
+ }
10324
+
9920
10325
  func isRuneSliceType(typ types.Type) bool {
9921
10326
  slice, ok := types.Unalias(typ).Underlying().(*types.Slice)
9922
10327
  return ok && isRuneType(slice.Elem())
@@ -10002,8 +10407,7 @@ func (o *LoweringOwner) functionAsync(ctx lowerFileContext, fn *types.Func) bool
10002
10407
  if fn == nil || ctx.model == nil {
10003
10408
  return false
10004
10409
  }
10005
- semFn := semanticFunctionFor(ctx.model, fn)
10006
- return semFn != nil && semFn.async
10410
+ return ctx.model.functionAsync(fn)
10007
10411
  }
10008
10412
 
10009
10413
  func (o *LoweringOwner) callNeedsAwait(ctx lowerFileContext, fun ast.Expr) bool {
@@ -10152,6 +10556,18 @@ func (o *LoweringOwner) inferGenericTypeArg(
10152
10556
  }
10153
10557
  return
10154
10558
  }
10559
+ if paramNamed, ok := types.Unalias(paramType).(*types.Named); ok {
10560
+ if argNamed, ok := types.Unalias(argType).(*types.Named); ok &&
10561
+ namedOriginsEqual(paramNamed, argNamed) {
10562
+ paramArgs := paramNamed.TypeArgs()
10563
+ argArgs := argNamed.TypeArgs()
10564
+ if paramArgs != nil && argArgs != nil {
10565
+ for idx := range min(paramArgs.Len(), argArgs.Len()) {
10566
+ o.inferGenericTypeArg(inferred, paramArgs.At(idx), argArgs.At(idx))
10567
+ }
10568
+ }
10569
+ }
10570
+ }
10155
10571
  switch param := types.Unalias(paramType).Underlying().(type) {
10156
10572
  case *types.Slice:
10157
10573
  if arg, ok := types.Unalias(argType).Underlying().(*types.Slice); ok {
@@ -10164,6 +10580,24 @@ func (o *LoweringOwner) inferGenericTypeArg(
10164
10580
  }
10165
10581
  }
10166
10582
 
10583
+ func namedOriginsEqual(a, b *types.Named) bool {
10584
+ if a == nil || b == nil {
10585
+ return false
10586
+ }
10587
+ aOrigin := a.Origin()
10588
+ if aOrigin == nil {
10589
+ aOrigin = a
10590
+ }
10591
+ bOrigin := b.Origin()
10592
+ if bOrigin == nil {
10593
+ bOrigin = b
10594
+ }
10595
+ if aOrigin.Obj() == nil || bOrigin.Obj() == nil {
10596
+ return aOrigin == bOrigin
10597
+ }
10598
+ return aOrigin.Obj() == bOrigin.Obj()
10599
+ }
10600
+
10167
10601
  func (o *LoweringOwner) genericTypeDescriptorExpr(ctx lowerFileContext, typ types.Type) string {
10168
10602
  if typeParam, ok := types.Unalias(typ).(*types.TypeParam); ok && typeParamInScope(ctx, typeParam) {
10169
10603
  return "__typeArgs?.[" + strconv.Quote(typeParam.Obj().Name()) + "] ?? { type: " +
@@ -10377,6 +10811,32 @@ func basicRuntimeName(basic *types.Basic) string {
10377
10811
  return "bool"
10378
10812
  case types.String:
10379
10813
  return "string"
10814
+ case types.Int:
10815
+ return "int"
10816
+ case types.Int8:
10817
+ return "int8"
10818
+ case types.Int16:
10819
+ return "int16"
10820
+ case types.Int32:
10821
+ return "int32"
10822
+ case types.Int64:
10823
+ return "int64"
10824
+ case types.Uint:
10825
+ return "uint"
10826
+ case types.Uint8:
10827
+ return "uint8"
10828
+ case types.Uint16:
10829
+ return "uint16"
10830
+ case types.Uint32:
10831
+ return "uint32"
10832
+ case types.Uint64:
10833
+ return "uint64"
10834
+ case types.Uintptr:
10835
+ return "uintptr"
10836
+ case types.Float32:
10837
+ return "float32"
10838
+ case types.Float64:
10839
+ return "float64"
10380
10840
  case types.Complex64:
10381
10841
  return "complex64"
10382
10842
  case types.Complex128: