goscript 0.0.84 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +23 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +15 -1
- package/dist/gs/builtin/hostio.js +134 -49
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +9 -9
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +27 -0
- package/gs/builtin/hostio.test.ts +177 -0
- package/gs/builtin/hostio.ts +171 -56
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +50 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"go/types"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
func TestSemanticModelBuildsDeclarationFacts(t *testing.T) {
|
|
12
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
13
|
+
"go.mod": "module example.test/semantic\n\ngo 1.25.3\n",
|
|
14
|
+
"main.go": strings.Join([]string{
|
|
15
|
+
"package semantic",
|
|
16
|
+
"import \"fmt\"",
|
|
17
|
+
"type Counter struct { Value int }",
|
|
18
|
+
"const Answer = 42",
|
|
19
|
+
"var Global Counter",
|
|
20
|
+
"func Print() { fmt.Println(Answer) }",
|
|
21
|
+
"",
|
|
22
|
+
}, "\n"),
|
|
23
|
+
})
|
|
24
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
25
|
+
Patterns: []string{"."},
|
|
26
|
+
Dir: moduleDir,
|
|
27
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
28
|
+
DependencyMode: DependencyModeRequested,
|
|
29
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
30
|
+
})
|
|
31
|
+
model := buildSemanticModel(t, graph)
|
|
32
|
+
semPkg := requireSemanticPackage(t, model, "example.test/semantic")
|
|
33
|
+
|
|
34
|
+
for _, decl := range []struct {
|
|
35
|
+
kind string
|
|
36
|
+
name string
|
|
37
|
+
}{
|
|
38
|
+
{kind: "type", name: "Counter"},
|
|
39
|
+
{kind: "const", name: "Answer"},
|
|
40
|
+
{kind: "var", name: "Global"},
|
|
41
|
+
{kind: "func", name: "Print"},
|
|
42
|
+
} {
|
|
43
|
+
if !hasSemanticDeclaration(semPkg, decl.kind, decl.name) {
|
|
44
|
+
t.Fatalf("missing declaration %s %s in %#v", decl.kind, decl.name, semPkg.declarations)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if len(semPkg.imports) != 1 || semPkg.imports[0].path != "fmt" {
|
|
48
|
+
t.Fatalf("unexpected imports: %#v", semPkg.imports)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
global := requireSemanticValue(t, model, graph, "example.test/semantic", "Global")
|
|
52
|
+
if !global.topLevel || global.zeroValueKind != "struct-zero" {
|
|
53
|
+
t.Fatalf("unexpected Global value facts: %#v", global)
|
|
54
|
+
}
|
|
55
|
+
if global.position.file == "" || global.position.line == 0 {
|
|
56
|
+
t.Fatalf("expected Global source position, got %#v", global.position)
|
|
57
|
+
}
|
|
58
|
+
if len(semPkg.initOrder) != 1 || semPkg.initOrder[0].Name() != "Global" {
|
|
59
|
+
t.Fatalf("unexpected init order: %#v", semPkg.initOrder)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func TestSemanticModelRecordsAddressTakenVarRefs(t *testing.T) {
|
|
64
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
65
|
+
"go.mod": "module example.test/varref\n\ngo 1.25.3\n",
|
|
66
|
+
"main.go": strings.Join([]string{
|
|
67
|
+
"package varref",
|
|
68
|
+
"func Use() {",
|
|
69
|
+
" x := 1",
|
|
70
|
+
" p := &x",
|
|
71
|
+
" _ = &p",
|
|
72
|
+
"}",
|
|
73
|
+
"",
|
|
74
|
+
}, "\n"),
|
|
75
|
+
})
|
|
76
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
77
|
+
Patterns: []string{"."},
|
|
78
|
+
Dir: moduleDir,
|
|
79
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
80
|
+
DependencyMode: DependencyModeRequested,
|
|
81
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
82
|
+
})
|
|
83
|
+
model := buildSemanticModel(t, graph)
|
|
84
|
+
|
|
85
|
+
for _, name := range []string{"x", "p"} {
|
|
86
|
+
obj := requireDefinedObject(t, graph, "example.test/varref", name)
|
|
87
|
+
if !model.addressTaken[obj] || !model.needsVarRef[obj] {
|
|
88
|
+
t.Fatalf("expected %s to be address-taken and need VarRef", name)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func TestSemanticModelRecordsStructFieldsAndReceivers(t *testing.T) {
|
|
94
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
95
|
+
"go.mod": "module example.test/structs\n\ngo 1.25.3\n",
|
|
96
|
+
"main.go": strings.Join([]string{
|
|
97
|
+
"package structs",
|
|
98
|
+
"type Counter struct {",
|
|
99
|
+
" // Value counts reads.",
|
|
100
|
+
" Value int",
|
|
101
|
+
" Label string",
|
|
102
|
+
"}",
|
|
103
|
+
"func (c Counter) Read() int { return c.Value }",
|
|
104
|
+
"func (c *Counter) Set(v int) { c.Value = v }",
|
|
105
|
+
"",
|
|
106
|
+
}, "\n"),
|
|
107
|
+
})
|
|
108
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
109
|
+
Patterns: []string{"."},
|
|
110
|
+
Dir: moduleDir,
|
|
111
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
112
|
+
DependencyMode: DependencyModeRequested,
|
|
113
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
114
|
+
})
|
|
115
|
+
model := buildSemanticModel(t, graph)
|
|
116
|
+
counter := requireSemanticType(t, graph, model, "example.test/structs", "Counter")
|
|
117
|
+
|
|
118
|
+
if len(counter.fields) != 2 ||
|
|
119
|
+
counter.fields[0].name != "Value" ||
|
|
120
|
+
counter.fields[1].name != "Label" {
|
|
121
|
+
t.Fatalf("unexpected Counter fields: %#v", counter.fields)
|
|
122
|
+
}
|
|
123
|
+
if counter.fields[0].doc != "Value counts reads." {
|
|
124
|
+
t.Fatalf("unexpected Counter.Value doc: %#v", counter.fields[0].doc)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
read := requireDefinedFunc(t, graph, "example.test/structs", "Read")
|
|
128
|
+
set := requireDefinedFunc(t, graph, "example.test/structs", "Set")
|
|
129
|
+
if model.functions[read].receiver == nil ||
|
|
130
|
+
model.functions[read].receiver.Obj().Name() != "Counter" ||
|
|
131
|
+
model.functions[read].receiverPointer {
|
|
132
|
+
t.Fatalf("unexpected value receiver facts: %#v", model.functions[read])
|
|
133
|
+
}
|
|
134
|
+
if model.functions[set].receiver == nil ||
|
|
135
|
+
model.functions[set].receiver.Obj().Name() != "Counter" ||
|
|
136
|
+
!model.functions[set].receiverPointer {
|
|
137
|
+
t.Fatalf("unexpected pointer receiver facts: %#v", model.functions[set])
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func TestSemanticModelMarksNamedValueForPointerReceiverCall(t *testing.T) {
|
|
142
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
143
|
+
"go.mod": "module example.test/namedrecv\n\ngo 1.25.3\n",
|
|
144
|
+
"main.go": strings.Join([]string{
|
|
145
|
+
"package namedrecv",
|
|
146
|
+
"type Numbers []int",
|
|
147
|
+
"func (n *Numbers) Add(v int) { *n = append(*n, v) }",
|
|
148
|
+
"func Use() {",
|
|
149
|
+
" var n Numbers",
|
|
150
|
+
" n.Add(1)",
|
|
151
|
+
"}",
|
|
152
|
+
"",
|
|
153
|
+
}, "\n"),
|
|
154
|
+
})
|
|
155
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
156
|
+
Patterns: []string{"."},
|
|
157
|
+
Dir: moduleDir,
|
|
158
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
159
|
+
DependencyMode: DependencyModeRequested,
|
|
160
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
161
|
+
})
|
|
162
|
+
model := buildSemanticModel(t, graph)
|
|
163
|
+
found := false
|
|
164
|
+
for obj := range model.needsVarRef {
|
|
165
|
+
if obj.Name() == "n" {
|
|
166
|
+
found = true
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if !found {
|
|
171
|
+
t.Fatalf("expected named slice value receiver call to force VarRef")
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func TestSemanticModelRecordsGeneratedImportNeeds(t *testing.T) {
|
|
176
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
177
|
+
"go.mod": "module example.test/imports\n\ngo 1.25.3\n",
|
|
178
|
+
"main.go": strings.Join([]string{
|
|
179
|
+
"package imports",
|
|
180
|
+
"import \"example.test/imports/subpkg\"",
|
|
181
|
+
"var Zero subpkg.Item",
|
|
182
|
+
"",
|
|
183
|
+
}, "\n"),
|
|
184
|
+
"subpkg/item.go": "package subpkg\ntype Item struct { Value int }\n",
|
|
185
|
+
})
|
|
186
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
187
|
+
Patterns: []string{"."},
|
|
188
|
+
Dir: moduleDir,
|
|
189
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
190
|
+
DependencyMode: DependencyModeRequested,
|
|
191
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
192
|
+
})
|
|
193
|
+
model := buildSemanticModel(t, graph)
|
|
194
|
+
|
|
195
|
+
imports := generatedImportsForFile(t, model, "main.go")
|
|
196
|
+
if !imports["example.test/imports/subpkg"] {
|
|
197
|
+
t.Fatalf("expected generated import for subpkg, got %#v", imports)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
func TestSemanticModelRecordsInterfaceAssertionAndNilFacts(t *testing.T) {
|
|
202
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
203
|
+
"go.mod": "module example.test/interfaces\n\ngo 1.25.3\n",
|
|
204
|
+
"main.go": strings.Join([]string{
|
|
205
|
+
"package interfaces",
|
|
206
|
+
"type Reader interface { Read() int }",
|
|
207
|
+
"type Impl struct{}",
|
|
208
|
+
"func (Impl) Read() int { return 1 }",
|
|
209
|
+
"func Use() {",
|
|
210
|
+
" var i Reader = Impl{}",
|
|
211
|
+
" _, _ = i.(Impl)",
|
|
212
|
+
" var p *Impl = nil",
|
|
213
|
+
" var sink Reader = p",
|
|
214
|
+
" var empty interface{} = nil",
|
|
215
|
+
" _, _ = sink, empty",
|
|
216
|
+
"}",
|
|
217
|
+
"",
|
|
218
|
+
}, "\n"),
|
|
219
|
+
})
|
|
220
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
221
|
+
Patterns: []string{"."},
|
|
222
|
+
Dir: moduleDir,
|
|
223
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
224
|
+
DependencyMode: DependencyModeRequested,
|
|
225
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
226
|
+
})
|
|
227
|
+
model := buildSemanticModel(t, graph)
|
|
228
|
+
semPkg := requireSemanticPackage(t, model, "example.test/interfaces")
|
|
229
|
+
|
|
230
|
+
if len(semPkg.typeAssertions) != 1 ||
|
|
231
|
+
!strings.Contains(semPkg.typeAssertions[0].target.String(), "Impl") {
|
|
232
|
+
t.Fatalf("unexpected type assertions: %#v", semPkg.typeAssertions)
|
|
233
|
+
}
|
|
234
|
+
for _, kind := range []string{"typed-nil", "typed-nil-interface-risk", "nil-interface"} {
|
|
235
|
+
if !hasNilFactKind(semPkg, kind) {
|
|
236
|
+
t.Fatalf("missing nil fact %q in %#v", kind, semPkg.nilFacts)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if !hasInterfaceImplementation(model, "Impl", "Reader", false) {
|
|
240
|
+
t.Fatalf("missing Impl -> Reader interface implementation: %#v", model.interfaceImplementations)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
func TestSemanticModelColorsAsyncFunctionsAndOverrides(t *testing.T) {
|
|
245
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
246
|
+
"go.mod": "module example.test/async\n\ngo 1.25.3\n",
|
|
247
|
+
"main.go": strings.Join([]string{
|
|
248
|
+
"package async",
|
|
249
|
+
"import \"sync\"",
|
|
250
|
+
"type Locker interface { Lock() }",
|
|
251
|
+
"type AsyncLocker struct { ch chan struct{} }",
|
|
252
|
+
"func (a *AsyncLocker) Lock() { <-a.ch }",
|
|
253
|
+
"func UseInterface(l Locker) { l.Lock() }",
|
|
254
|
+
"func CallChannel(a *AsyncLocker) { a.Lock() }",
|
|
255
|
+
"func UseMutex(mu *sync.Mutex) { mu.Lock() }",
|
|
256
|
+
"func Immediate() {}",
|
|
257
|
+
"",
|
|
258
|
+
}, "\n"),
|
|
259
|
+
})
|
|
260
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
261
|
+
Patterns: []string{"."},
|
|
262
|
+
Dir: moduleDir,
|
|
263
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
264
|
+
DependencyMode: DependencyModeAll,
|
|
265
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
266
|
+
})
|
|
267
|
+
model := buildSemanticModel(t, graph)
|
|
268
|
+
|
|
269
|
+
for _, name := range []string{"UseInterface", "CallChannel", "UseMutex"} {
|
|
270
|
+
fn := requireDefinedFunc(t, graph, "example.test/async", name)
|
|
271
|
+
if !model.functions[fn].async {
|
|
272
|
+
t.Fatalf("expected %s to be async, got %#v", name, model.functions[fn])
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
immediate := requireDefinedFunc(t, graph, "example.test/async", "Immediate")
|
|
276
|
+
if model.functions[immediate].async {
|
|
277
|
+
t.Fatalf("did not expect Immediate to be async: %#v", model.functions[immediate])
|
|
278
|
+
}
|
|
279
|
+
if !hasInterfaceImplementation(model, "AsyncLocker", "Locker", true) {
|
|
280
|
+
t.Fatalf("missing *AsyncLocker -> Locker implementation: %#v", model.interfaceImplementations)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
func buildSemanticModel(t *testing.T, graph *PackageGraph) *SemanticModel {
|
|
285
|
+
t.Helper()
|
|
286
|
+
|
|
287
|
+
model, diagnostics := NewSemanticModelOwner(NewOverrideRegistryOwner()).Build(context.Background(), graph)
|
|
288
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
289
|
+
t.Fatalf("semantic model build failed: %#v", diagnostics)
|
|
290
|
+
}
|
|
291
|
+
if model == nil {
|
|
292
|
+
t.Fatalf("semantic model build returned nil")
|
|
293
|
+
}
|
|
294
|
+
return model
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
func requireSemanticPackage(t *testing.T, model *SemanticModel, pkgPath string) *semanticPackage {
|
|
298
|
+
t.Helper()
|
|
299
|
+
|
|
300
|
+
semPkg := model.packages[pkgPath]
|
|
301
|
+
if semPkg == nil {
|
|
302
|
+
t.Fatalf("missing semantic package %q in %#v", pkgPath, model.packages)
|
|
303
|
+
}
|
|
304
|
+
return semPkg
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
func hasSemanticDeclaration(semPkg *semanticPackage, kind string, name string) bool {
|
|
308
|
+
for _, decl := range semPkg.declarations {
|
|
309
|
+
if decl.kind == kind && decl.name == name {
|
|
310
|
+
return true
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
func requireSemanticValue(
|
|
317
|
+
t *testing.T,
|
|
318
|
+
model *SemanticModel,
|
|
319
|
+
graph *PackageGraph,
|
|
320
|
+
pkgPath string,
|
|
321
|
+
name string,
|
|
322
|
+
) *semanticValue {
|
|
323
|
+
t.Helper()
|
|
324
|
+
|
|
325
|
+
obj := requireDefinedObject(t, graph, pkgPath, name)
|
|
326
|
+
value := model.values[obj]
|
|
327
|
+
if value == nil {
|
|
328
|
+
t.Fatalf("missing semantic value for %s", name)
|
|
329
|
+
}
|
|
330
|
+
return value
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
func requireSemanticType(
|
|
334
|
+
t *testing.T,
|
|
335
|
+
graph *PackageGraph,
|
|
336
|
+
model *SemanticModel,
|
|
337
|
+
pkgPath string,
|
|
338
|
+
name string,
|
|
339
|
+
) *semanticType {
|
|
340
|
+
t.Helper()
|
|
341
|
+
|
|
342
|
+
obj, _ := requireDefinedObject(t, graph, pkgPath, name).(*types.TypeName)
|
|
343
|
+
if obj == nil {
|
|
344
|
+
t.Fatalf("defined object %s is not a type", name)
|
|
345
|
+
}
|
|
346
|
+
named, _ := obj.Type().(*types.Named)
|
|
347
|
+
if named == nil {
|
|
348
|
+
t.Fatalf("defined type %s is not named", name)
|
|
349
|
+
}
|
|
350
|
+
semType := model.types[named]
|
|
351
|
+
if semType == nil {
|
|
352
|
+
t.Fatalf("missing semantic type for %s", name)
|
|
353
|
+
}
|
|
354
|
+
return semType
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
func requireDefinedFunc(t *testing.T, graph *PackageGraph, pkgPath string, name string) *types.Func {
|
|
358
|
+
t.Helper()
|
|
359
|
+
|
|
360
|
+
fn, _ := requireDefinedObject(t, graph, pkgPath, name).(*types.Func)
|
|
361
|
+
if fn == nil {
|
|
362
|
+
t.Fatalf("defined object %s is not a function", name)
|
|
363
|
+
}
|
|
364
|
+
return fn
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
func requireDefinedObject(t *testing.T, graph *PackageGraph, pkgPath string, name string) types.Object {
|
|
368
|
+
t.Helper()
|
|
369
|
+
|
|
370
|
+
pkg := graph.packagesByPath[pkgPath]
|
|
371
|
+
if pkg == nil {
|
|
372
|
+
t.Fatalf("missing loaded package %q", pkgPath)
|
|
373
|
+
}
|
|
374
|
+
for ident, obj := range pkg.TypesInfo.Defs {
|
|
375
|
+
if ident.Name == name && obj != nil {
|
|
376
|
+
return obj
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
t.Fatalf("missing defined object %s in %s", name, pkgPath)
|
|
380
|
+
return nil
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
func generatedImportsForFile(t *testing.T, model *SemanticModel, base string) map[string]bool {
|
|
384
|
+
t.Helper()
|
|
385
|
+
|
|
386
|
+
for file, imports := range model.generatedImports {
|
|
387
|
+
if filepath.Base(file) == base {
|
|
388
|
+
return imports
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
t.Fatalf("missing generated imports for %s in %#v", base, model.generatedImports)
|
|
392
|
+
return nil
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
func hasNilFactKind(semPkg *semanticPackage, kind string) bool {
|
|
396
|
+
for _, fact := range semPkg.nilFacts {
|
|
397
|
+
if fact.kind == kind {
|
|
398
|
+
return true
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return false
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
func hasInterfaceImplementation(model *SemanticModel, typ string, iface string, pointer bool) bool {
|
|
405
|
+
for _, implementation := range model.interfaceImplementations {
|
|
406
|
+
if implementation.pointer != pointer ||
|
|
407
|
+
implementation.typ == nil ||
|
|
408
|
+
implementation.iface == nil {
|
|
409
|
+
continue
|
|
410
|
+
}
|
|
411
|
+
if implementation.typ.Obj().Name() == typ && implementation.iface.Obj().Name() == iface {
|
|
412
|
+
return true
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return false
|
|
416
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import "context"
|
|
4
|
+
|
|
5
|
+
// CompileService owns the v2 compiler pipeline.
|
|
6
|
+
type CompileService struct {
|
|
7
|
+
requestOwner *CompileRequestOwner
|
|
8
|
+
graphOwner *PackageGraphOwner
|
|
9
|
+
semanticOwner *SemanticModelOwner
|
|
10
|
+
loweringOwner *LoweringOwner
|
|
11
|
+
emitterOwner *TypeScriptEmitOwner
|
|
12
|
+
runtimeOwner *RuntimeContractOwner
|
|
13
|
+
overrideOwner *OverrideRegistryOwner
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// NewCompileService creates a compile service with every pipeline owner.
|
|
17
|
+
func NewCompileService() *CompileService {
|
|
18
|
+
overrideOwner := NewOverrideRegistryOwner()
|
|
19
|
+
runtimeOwner := NewRuntimeContractOwner()
|
|
20
|
+
return &CompileService{
|
|
21
|
+
requestOwner: NewCompileRequestOwner(),
|
|
22
|
+
graphOwner: NewPackageGraphOwner(),
|
|
23
|
+
semanticOwner: NewSemanticModelOwner(overrideOwner),
|
|
24
|
+
loweringOwner: NewLoweringOwner(runtimeOwner, overrideOwner),
|
|
25
|
+
emitterOwner: NewTypeScriptEmitOwner(runtimeOwner),
|
|
26
|
+
runtimeOwner: runtimeOwner,
|
|
27
|
+
overrideOwner: overrideOwner,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// RequestOwner returns the compile request owner.
|
|
32
|
+
func (s *CompileService) RequestOwner() *CompileRequestOwner {
|
|
33
|
+
return s.requestOwner
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// PackageGraphOwner returns the package graph owner.
|
|
37
|
+
func (s *CompileService) PackageGraphOwner() *PackageGraphOwner {
|
|
38
|
+
return s.graphOwner
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// SemanticModelOwner returns the semantic model owner.
|
|
42
|
+
func (s *CompileService) SemanticModelOwner() *SemanticModelOwner {
|
|
43
|
+
return s.semanticOwner
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// LoweringOwner returns the lowering owner.
|
|
47
|
+
func (s *CompileService) LoweringOwner() *LoweringOwner {
|
|
48
|
+
return s.loweringOwner
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// TypeScriptEmitOwner returns the TypeScript emit owner.
|
|
52
|
+
func (s *CompileService) TypeScriptEmitOwner() *TypeScriptEmitOwner {
|
|
53
|
+
return s.emitterOwner
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// RuntimeContractOwner returns the runtime contract owner.
|
|
57
|
+
func (s *CompileService) RuntimeContractOwner() *RuntimeContractOwner {
|
|
58
|
+
return s.runtimeOwner
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// OverrideRegistryOwner returns the override registry owner.
|
|
62
|
+
func (s *CompileService) OverrideRegistryOwner() *OverrideRegistryOwner {
|
|
63
|
+
return s.overrideOwner
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Compile runs one request through the v2 pipeline.
|
|
67
|
+
func (s *CompileService) Compile(ctx context.Context, req *CompileRequest) (*CompilationResult, error) {
|
|
68
|
+
if err := ctx.Err(); err != nil {
|
|
69
|
+
return nil, err
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
result := &CompilationResult{}
|
|
73
|
+
if req != nil {
|
|
74
|
+
result.OriginalPackages = append([]string(nil), req.Patterns...)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
diagnostics := s.requestOwner.Validate(req)
|
|
78
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
79
|
+
result.Diagnostics = diagnostics
|
|
80
|
+
return result, NewCompileError(diagnostics)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
graph, graphDiagnostics := s.graphOwner.Load(ctx, req)
|
|
84
|
+
diagnostics = append(diagnostics, graphDiagnostics...)
|
|
85
|
+
if graph != nil {
|
|
86
|
+
result.OriginalPackages = append([]string(nil), graph.RequestedPackagePaths...)
|
|
87
|
+
}
|
|
88
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
89
|
+
result.Diagnostics = diagnostics
|
|
90
|
+
return result, NewCompileError(diagnostics)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
semanticModel, semanticDiagnostics := s.semanticOwner.Build(ctx, graph)
|
|
94
|
+
diagnostics = append(diagnostics, semanticDiagnostics...)
|
|
95
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
96
|
+
result.Diagnostics = diagnostics
|
|
97
|
+
return result, NewCompileError(diagnostics)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
overridePlan, overrideDiagnostics := s.overrideOwner.CopyPlan(ctx, req, graph)
|
|
101
|
+
diagnostics = append(diagnostics, overrideDiagnostics...)
|
|
102
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
103
|
+
result.Diagnostics = diagnostics
|
|
104
|
+
return result, NewCompileError(diagnostics)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
loweredProgram, loweringDiagnostics := s.loweringOwner.Build(ctx, semanticModel)
|
|
108
|
+
diagnostics = append(diagnostics, loweringDiagnostics...)
|
|
109
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
110
|
+
result.Diagnostics = diagnostics
|
|
111
|
+
return result, NewCompileError(diagnostics)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
compiledPackages, emitDiagnostics := s.emitterOwner.Emit(ctx, req, loweredProgram)
|
|
115
|
+
diagnostics = append(diagnostics, emitDiagnostics...)
|
|
116
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
117
|
+
result.Diagnostics = diagnostics
|
|
118
|
+
return result, NewCompileError(diagnostics)
|
|
119
|
+
}
|
|
120
|
+
result.CompiledPackages = append(result.CompiledPackages, compiledPackages...)
|
|
121
|
+
|
|
122
|
+
copiedPackages, copyDiagnostics := s.overrideOwner.CopyPackages(ctx, req, overridePlan)
|
|
123
|
+
diagnostics = append(diagnostics, copyDiagnostics...)
|
|
124
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
125
|
+
result.CopiedPackages = append(result.CopiedPackages, copiedPackages...)
|
|
126
|
+
result.Diagnostics = diagnostics
|
|
127
|
+
return result, NewCompileError(diagnostics)
|
|
128
|
+
}
|
|
129
|
+
result.CopiedPackages = append(result.CopiedPackages, copiedPackages...)
|
|
130
|
+
|
|
131
|
+
result.Diagnostics = diagnostics
|
|
132
|
+
return result, nil
|
|
133
|
+
}
|