types.go raw
1 // Package mxssa defines the Moxie SSA intermediate representation.
2 // It replaces golang.org/x/tools/go/ssa in B3 when the native type checker
3 // and SSA builder are complete.
4 //
5 // The type system mirrors go/ssa's structure with typecheck.Type replacing
6 // go/types.Type throughout. The builder accepts *syntax.File + typecheck.Info
7 // instead of go/ast.File + types.Info.
8 package mxssa
9
10 import (
11 "go/constant"
12 "go/token"
13
14 "moxie/typecheck"
15 )
16
17 // ─── Interfaces ───────────────────────────────────────────────────────────────
18
19 // Value is anything that produces a value in the SSA program.
20 type Value interface {
21 // Name returns the SSA name of this value.
22 Name() string
23 // String returns a human-readable representation.
24 String() string
25 // Type returns the type of this value.
26 Type() typecheck.Type
27 // Parent returns the enclosing function, or nil for package-level values.
28 Parent() *Function
29 // Referrers returns the instruction list that use this value.
30 // The caller may append to it.
31 Referrers() *[]Instruction
32 // Pos returns the source position.
33 Pos() token.Pos
34
35 setType(typecheck.Type)
36 setName(string)
37 addReferrer(Instruction)
38 }
39
40 // Instruction is a statement in a BasicBlock.
41 type Instruction interface {
42 // Block returns the enclosing basic block.
43 Block() *BasicBlock
44 // Parent returns the enclosing function.
45 Parent() *Function
46 // Pos returns the source position.
47 Pos() token.Pos
48 // Operands fills rands with pointers to operand Values and returns the slice.
49 // Used for graph traversal and register renaming.
50 Operands(rands []*Value) []*Value
51 // String returns a disassembly-style representation.
52 String() string
53
54 setBlock(*BasicBlock)
55 }
56
57 // Member is a package-level declaration: function, variable, const, or type.
58 type Member interface {
59 Name() string
60 String() string
61 RelString(*typecheck.Package) string
62 Pos() token.Pos
63 Type() typecheck.Type
64 Package() *Package
65 Object() typecheck.Object
66 }
67
68 // ─── Program / Package ────────────────────────────────────────────────────────
69
70 // Program is the top-level container for all packages in an SSA program.
71 type Program struct {
72 Fset *token.FileSet
73 imported map[string]*Package
74 packages map[*typecheck.Package]*Package
75 }
76
77 func NewProgram(fset *token.FileSet) *Program {
78 return &Program{
79 Fset: fset,
80 imported: map[string]*Package{},
81 packages: map[*typecheck.Package]*Package{},
82 }
83 }
84
85 // ImportedPackage returns the package for the given import path, or nil.
86 func (prog *Program) ImportedPackage(path string) *Package {
87 return prog.imported[path]
88 }
89
90 // Package is a single package in SSA form.
91 type Package struct {
92 Prog *Program
93 Pkg *typecheck.Package
94 Members map[string]Member
95 init *Function
96 debug bool
97 }
98
99 func (p *Package) Func(name string) *Function {
100 m, _ := p.Members[name].(*Function)
101 return m
102 }
103
104 // ─── Function ─────────────────────────────────────────────────────────────────
105
106 // Function is a named or anonymous function in SSA form.
107 type Function struct {
108 name string
109 object *typecheck.Func
110 Signature *typecheck.Signature
111 pos token.Pos
112
113 Synthetic string // "" for real source functions
114
115 Pkg *Package
116 Prog *Program
117
118 // Body (nil if external)
119 Params []*Parameter
120 FreeVars []*FreeVar
121 Locals []*Alloc
122 Blocks []*BasicBlock
123 Recover *BasicBlock
124 AnonFuncs []*Function
125
126 referrers []Instruction
127 parent *Function
128
129 // type parameter info (generics)
130 typeparams []typecheck.Type
131 typeargs []typecheck.Type
132
133 // builder state (cleared after Build)
134 currentBlock *BasicBlock
135 vars map[typecheck.Object]Value
136 results []*Alloc
137 }
138
139 func (f *Function) Name() string { return f.name }
140 func (f *Function) String() string { return f.name }
141 func (f *Function) Pos() token.Pos { return f.pos }
142 func (f *Function) Type() typecheck.Type {
143 if f.Signature == nil {
144 return nil
145 }
146 return f.Signature
147 }
148 func (f *Function) Parent() *Function { return f.parent }
149 func (f *Function) Referrers() *[]Instruction { return &f.referrers }
150 func (f *Function) Package() *Package { return f.Pkg }
151 func (f *Function) Object() typecheck.Object { return f.object }
152 func (f *Function) RelString(from *typecheck.Package) string {
153 if from != nil && f.Pkg != nil && f.Pkg.Pkg == from {
154 return f.name
155 }
156 if f.Pkg != nil {
157 return f.Pkg.Pkg.Path() + "." + f.name
158 }
159 return f.name
160 }
161 func (f *Function) TypeParams() []typecheck.Type { return f.typeparams }
162 func (f *Function) Syntax() any { return nil }
163
164 func (f *Function) setName(n string) { f.name = n }
165 func (f *Function) setType(t typecheck.Type) {}
166 func (f *Function) addReferrer(i Instruction) { f.referrers = append(f.referrers, i) }
167
168 // ─── BasicBlock ───────────────────────────────────────────────────────────────
169
170 // BasicBlock is a maximal sequence of non-branching instructions.
171 type BasicBlock struct {
172 Index int
173 Comment string
174 parent *Function
175 Instrs []Instruction
176 Preds []*BasicBlock
177 Succs []*BasicBlock
178 }
179
180 func (b *BasicBlock) Parent() *Function { return b.parent }
181
182 // NewBasicBlock appends a new basic block to the function.
183 func NewBasicBlock(parent *Function, comment string) *BasicBlock {
184 b := &BasicBlock{
185 Index: len(parent.Blocks),
186 Comment: comment,
187 parent: parent,
188 }
189 parent.Blocks = append(parent.Blocks, b)
190 return b
191 }
192
193 // ─── register (shared embed for instructions that define a value) ─────────────
194
195 type register struct {
196 anInstruction
197 name string
198 typ typecheck.Type
199 pos token.Pos
200 referrers []Instruction
201 }
202
203 func (r *register) Name() string { return r.name }
204 func (r *register) Type() typecheck.Type { return r.typ }
205 func (r *register) Pos() token.Pos { return r.pos }
206 func (r *register) Referrers() *[]Instruction { return &r.referrers }
207 func (r *register) Parent() *Function { return r.block.parent }
208 func (r *register) setName(n string) { r.name = n }
209 func (r *register) setType(t typecheck.Type) { r.typ = t }
210 func (r *register) addReferrer(i Instruction) { r.referrers = append(r.referrers, i) }
211
212 // anInstruction is embedded by all Instructions.
213 type anInstruction struct {
214 block *BasicBlock
215 }
216
217 func (a *anInstruction) Block() *BasicBlock { return a.block }
218 func (a *anInstruction) Parent() *Function { return a.block.parent }
219 func (a *anInstruction) setBlock(b *BasicBlock) { a.block = b }
220
221 // ─── Package-level values ─────────────────────────────────────────────────────
222
223 // Global is a package-level variable.
224 type Global struct {
225 name string
226 object *typecheck.Var
227 typ typecheck.Type
228 pos token.Pos
229 pkg *Package
230
231 referrers []Instruction
232 }
233
234 func (g *Global) Name() string { return g.name }
235 func (g *Global) String() string { return g.pkg.Pkg.Path() + "." + g.name }
236 func (g *Global) Type() typecheck.Type { return g.typ }
237 func (g *Global) Pos() token.Pos { return g.pos }
238 func (g *Global) Parent() *Function { return nil }
239 func (g *Global) Referrers() *[]Instruction { return &g.referrers }
240 func (g *Global) Package() *Package { return g.pkg }
241 func (g *Global) Object() typecheck.Object { return g.object }
242 func (g *Global) RelString(from *typecheck.Package) string {
243 if from != nil && g.pkg != nil && g.pkg.Pkg == from {
244 return g.name
245 }
246 return g.String()
247 }
248 func (g *Global) setName(n string) { g.name = n }
249 func (g *Global) setType(t typecheck.Type) { g.typ = t }
250 func (g *Global) addReferrer(i Instruction) { g.referrers = append(g.referrers, i) }
251
252 // Type_ is a package-level named type member (named Type to avoid collision).
253 type Type_ struct {
254 object *typecheck.TypeName
255 pkg *Package
256 }
257
258 func (t *Type_) Name() string { return t.object.Name() }
259 func (t *Type_) String() string { return t.pkg.Pkg.Path() + "." + t.object.Name() }
260 func (t *Type_) Type() typecheck.Type { return t.object.Type() }
261 func (t *Type_) Pos() token.Pos { return 0 }
262 func (t *Type_) Package() *Package { return t.pkg }
263 func (t *Type_) Object() typecheck.Object { return t.object }
264 func (t *Type_) RelString(from *typecheck.Package) string {
265 if from != nil && t.pkg != nil && t.pkg.Pkg == from {
266 return t.object.Name()
267 }
268 return t.String()
269 }
270
271 // NamedConst is a package-level named constant.
272 type NamedConst struct {
273 object *typecheck.Const
274 Value *Const
275 pkg *Package
276 }
277
278 func (c *NamedConst) Name() string { return c.object.Name() }
279 func (c *NamedConst) String() string { return c.pkg.Pkg.Path() + "." + c.object.Name() }
280 func (c *NamedConst) Type() typecheck.Type { return c.object.Type() }
281 func (c *NamedConst) Pos() token.Pos { return 0 }
282 func (c *NamedConst) Package() *Package { return c.pkg }
283 func (c *NamedConst) Object() typecheck.Object { return c.object }
284 func (c *NamedConst) RelString(from *typecheck.Package) string {
285 if from != nil && c.pkg != nil && c.pkg.Pkg == from {
286 return c.object.Name()
287 }
288 return c.String()
289 }
290
291 // ─── Parameter / FreeVar / Const / Builtin ────────────────────────────────────
292
293 // Parameter is a function parameter (includes method receiver).
294 type Parameter struct {
295 name string
296 object *typecheck.Var
297 typ typecheck.Type
298 pos token.Pos
299 parent *Function
300 referrers []Instruction
301 }
302
303 func (p *Parameter) Name() string { return p.name }
304 func (p *Parameter) String() string { return p.name }
305 func (p *Parameter) Type() typecheck.Type { return p.typ }
306 func (p *Parameter) Pos() token.Pos { return p.pos }
307 func (p *Parameter) Parent() *Function { return p.parent }
308 func (p *Parameter) Referrers() *[]Instruction { return &p.referrers }
309 func (p *Parameter) Object() typecheck.Object { return p.object }
310 func (p *Parameter) setName(n string) { p.name = n }
311 func (p *Parameter) setType(t typecheck.Type) { p.typ = t }
312 func (p *Parameter) addReferrer(i Instruction) { p.referrers = append(p.referrers, i) }
313
314 // FreeVar is a free variable captured by a closure.
315 type FreeVar struct {
316 name string
317 typ typecheck.Type
318 pos token.Pos
319 parent *Function
320 referrers []Instruction
321 }
322
323 func (v *FreeVar) Name() string { return v.name }
324 func (v *FreeVar) String() string { return v.name }
325 func (v *FreeVar) Type() typecheck.Type { return v.typ }
326 func (v *FreeVar) Pos() token.Pos { return v.pos }
327 func (v *FreeVar) Parent() *Function { return v.parent }
328 func (v *FreeVar) Referrers() *[]Instruction { return &v.referrers }
329 func (v *FreeVar) setName(n string) { v.name = n }
330 func (v *FreeVar) setType(t typecheck.Type) { v.typ = t }
331 func (v *FreeVar) addReferrer(i Instruction) { v.referrers = append(v.referrers, i) }
332 func (v *FreeVar) Operands(rands []*Value) []*Value { return rands }
333
334 // Const is a constant value.
335 type Const struct {
336 typ typecheck.Type
337 val constant.Value
338 referrers []Instruction
339 }
340
341 func NewConst(val constant.Value, typ typecheck.Type) *Const {
342 return &Const{typ: typ, val: val}
343 }
344
345 func (c *Const) Name() string {
346 if c.val == nil {
347 return "nil"
348 }
349 return c.val.String()
350 }
351 func (c *Const) String() string { return c.Name() }
352 func (c *Const) Type() typecheck.Type { return c.typ }
353 func (c *Const) Pos() token.Pos { return 0 }
354 func (c *Const) Parent() *Function { return nil }
355 func (c *Const) Referrers() *[]Instruction { return &c.referrers }
356 func (c *Const) Value() constant.Value { return c.val }
357 func (c *Const) setName(n string) {}
358 func (c *Const) setType(t typecheck.Type) { c.typ = t }
359 func (c *Const) addReferrer(i Instruction) { c.referrers = append(c.referrers, i) }
360
361 // BuiltinID identifies a Go built-in function.
362 type BuiltinID int
363
364 const (
365 BuiltinAppend BuiltinID = iota
366 BuiltinCap
367 BuiltinClear
368 BuiltinClose
369 BuiltinComplex
370 BuiltinCopy
371 BuiltinDelete
372 BuiltinImag
373 BuiltinLen
374 BuiltinMake
375 BuiltinMax
376 BuiltinMin
377 BuiltinNew
378 BuiltinPanic
379 BuiltinPrint
380 BuiltinPrintln
381 BuiltinReal
382 BuiltinRecover
383 )
384
385 // Builtin represents a use of a Go built-in as a function value.
386 type Builtin struct {
387 id BuiltinID
388 name string
389 referrers []Instruction
390 }
391
392 func (b *Builtin) Name() string { return b.name }
393 func (b *Builtin) String() string { return b.name }
394 func (b *Builtin) Type() typecheck.Type { return nil }
395 func (b *Builtin) Pos() token.Pos { return 0 }
396 func (b *Builtin) Parent() *Function { return nil }
397 func (b *Builtin) Referrers() *[]Instruction { return &b.referrers }
398 func (b *Builtin) ID() BuiltinID { return b.id }
399 func (b *Builtin) setName(n string) { b.name = n }
400 func (b *Builtin) setType(t typecheck.Type) {}
401 func (b *Builtin) addReferrer(i Instruction) { b.referrers = append(b.referrers, i) }
402
403 // ─── CallCommon ───────────────────────────────────────────────────────────────
404
405 // CallCommon describes a function or method call.
406 // It is shared between Call, Go, and Defer instructions.
407 type CallCommon struct {
408 Value Value // for static call: *Function or *Builtin; for interface call: the receiver
409 Method *typecheck.Func // non-nil for interface calls; nil for static calls
410 Args []Value
411 pos token.Pos
412 IsInvoke bool // true for interface method calls
413 }
414
415 func (c *CallCommon) Pos() token.Pos { return c.pos }
416
417 func (c *CallCommon) Operands(rands []*Value) []*Value {
418 rands = append(rands, &c.Value)
419 for i := range c.Args {
420 rands = append(rands, &c.Args[i])
421 }
422 return rands
423 }
424
425 // ─── Instructions ─────────────────────────────────────────────────────────────
426
427 // Alloc allocates space for a variable of type T.
428 // Heap == true means heap allocation (new(T) or &T{}).
429 // Heap == false means stack allocation (function-local var).
430 type Alloc struct {
431 register
432 Heap bool
433 Comment string
434 }
435
436 func (a *Alloc) Operands(rands []*Value) []*Value { return rands }
437 func (a *Alloc) String() string {
438 if a.Heap {
439 return "new " + a.typ.String()
440 }
441 return "local " + a.typ.String()
442 }
443
444 // Phi is a Φ-node: a join point that selects a value based on the predecessor.
445 type Phi struct {
446 register
447 Comment string
448 Edges []Value // must match len(block.Preds)
449 }
450
451 func (p *Phi) Operands(rands []*Value) []*Value {
452 for i := range p.Edges {
453 rands = append(rands, &p.Edges[i])
454 }
455 return rands
456 }
457 func (p *Phi) String() string { return "phi " + p.Comment }
458
459 // Call is a function call: result = f(args...).
460 type Call struct {
461 register
462 Call CallCommon
463 }
464
465 func (c *Call) Operands(rands []*Value) []*Value { return c.Call.Operands(rands) }
466 func (c *Call) Common() *CallCommon { return &c.Call }
467 func (c *Call) String() string { return "call " + c.Call.Value.Name() }
468
469 // BinOp is a binary operation: result = X op Y.
470 type BinOp struct {
471 register
472 Op token.Token
473 X Value
474 Y Value
475 }
476
477 func (b *BinOp) Operands(rands []*Value) []*Value {
478 return append(rands, &b.X, &b.Y)
479 }
480 func (b *BinOp) String() string { return "binop " + b.Op.String() }
481
482 // UnOp is a unary operation: result = op X.
483 type UnOp struct {
484 register
485 Op token.Token
486 X Value
487 CommaOk bool // for *x yielding (T, bool)
488 }
489
490 func (u *UnOp) Operands(rands []*Value) []*Value {
491 return append(rands, &u.X)
492 }
493 func (u *UnOp) String() string { return "unop " + u.Op.String() }
494
495 // ChangeType is a type change with no runtime effect (type assertion on interface).
496 type ChangeType struct {
497 register
498 X Value
499 }
500
501 func (c *ChangeType) Operands(rands []*Value) []*Value { return append(rands, &c.X) }
502 func (c *ChangeType) String() string { return "changetype " + c.typ.String() }
503
504 // Convert is a value conversion T(x).
505 type Convert struct {
506 register
507 X Value
508 }
509
510 func (c *Convert) Operands(rands []*Value) []*Value { return append(rands, &c.X) }
511 func (c *Convert) String() string { return "convert " + c.typ.String() }
512
513 // ChangeInterface changes the interface type of a value.
514 type ChangeInterface struct {
515 register
516 X Value
517 }
518
519 func (c *ChangeInterface) Operands(rands []*Value) []*Value { return append(rands, &c.X) }
520 func (c *ChangeInterface) String() string { return "changeinterface" }
521
522 // SliceToArrayPointer converts a slice to an array pointer.
523 type SliceToArrayPointer struct {
524 register
525 X Value
526 }
527
528 func (s *SliceToArrayPointer) Operands(rands []*Value) []*Value { return append(rands, &s.X) }
529 func (s *SliceToArrayPointer) String() string { return "slicearrptr" }
530
531 // MakeInterface boxes a value into an interface.
532 type MakeInterface struct {
533 register
534 X Value
535 }
536
537 func (m *MakeInterface) Operands(rands []*Value) []*Value { return append(rands, &m.X) }
538 func (m *MakeInterface) String() string { return "makeinterface " + m.X.Type().String() }
539
540 // MakeClosure creates a closure: {fn, freevar...}.
541 type MakeClosure struct {
542 register
543 Fn Value // *Function
544 Bindings []Value // free variable bindings (in order)
545 }
546
547 func (m *MakeClosure) Operands(rands []*Value) []*Value {
548 rands = append(rands, &m.Fn)
549 for i := range m.Bindings {
550 rands = append(rands, &m.Bindings[i])
551 }
552 return rands
553 }
554 func (m *MakeClosure) String() string { return "makeclosure" }
555
556 // MakeMap allocates a new map.
557 type MakeMap struct {
558 register
559 Reserve Value // initial capacity hint (may be nil)
560 }
561
562 func (m *MakeMap) Operands(rands []*Value) []*Value {
563 if m.Reserve != nil {
564 return append(rands, &m.Reserve)
565 }
566 return rands
567 }
568 func (m *MakeMap) String() string { return "makemap " + m.typ.String() }
569
570 // MakeChan allocates a new channel.
571 type MakeChan struct {
572 register
573 Size Value // buffer size (may be nil for unbuffered)
574 }
575
576 func (m *MakeChan) Operands(rands []*Value) []*Value {
577 if m.Size != nil {
578 return append(rands, &m.Size)
579 }
580 return rands
581 }
582 func (m *MakeChan) String() string { return "makechan " + m.typ.String() }
583
584 // MakeSlice allocates a new slice.
585 type MakeSlice struct {
586 register
587 Len Value
588 Cap Value
589 }
590
591 func (m *MakeSlice) Operands(rands []*Value) []*Value {
592 rands = append(rands, &m.Len)
593 if m.Cap != nil {
594 rands = append(rands, &m.Cap)
595 }
596 return rands
597 }
598 func (m *MakeSlice) String() string { return "makeslice " + m.typ.String() }
599
600 // Slice produces a slice of x[low:high:max].
601 type Slice struct {
602 register
603 X Value // slice, string, or *array
604 Low Value // may be nil
605 High Value // may be nil
606 Max Value // may be nil (3-index slice only)
607 }
608
609 func (s *Slice) Operands(rands []*Value) []*Value {
610 rands = append(rands, &s.X)
611 if s.Low != nil {
612 rands = append(rands, &s.Low)
613 }
614 if s.High != nil {
615 rands = append(rands, &s.High)
616 }
617 if s.Max != nil {
618 rands = append(rands, &s.Max)
619 }
620 return rands
621 }
622 func (s *Slice) String() string { return "slice" }
623
624 // FieldAddr computes &struct.field.
625 type FieldAddr struct {
626 register
627 X Value
628 Field int
629 }
630
631 func (f *FieldAddr) Operands(rands []*Value) []*Value { return append(rands, &f.X) }
632 func (f *FieldAddr) String() string { return "fieldaddr" }
633
634 // Field extracts a field from a struct value (by copy).
635 type Field struct {
636 register
637 X Value
638 Field int
639 }
640
641 func (f *Field) Operands(rands []*Value) []*Value { return append(rands, &f.X) }
642 func (f *Field) String() string { return "field" }
643
644 // IndexAddr computes &x[i].
645 type IndexAddr struct {
646 register
647 X Value
648 Index Value
649 }
650
651 func (i *IndexAddr) Operands(rands []*Value) []*Value {
652 return append(rands, &i.X, &i.Index)
653 }
654 func (i *IndexAddr) String() string { return "indexaddr" }
655
656 // Index extracts an element from an array (by copy).
657 type Index struct {
658 register
659 X Value
660 Index Value
661 }
662
663 func (i *Index) Operands(rands []*Value) []*Value {
664 return append(rands, &i.X, &i.Index)
665 }
666 func (i *Index) String() string { return "index" }
667
668 // Lookup computes x[key] for a map, and optionally returns (v, ok).
669 type Lookup struct {
670 register
671 X Value
672 Index Value
673 CommaOk bool
674 }
675
676 func (l *Lookup) Operands(rands []*Value) []*Value {
677 return append(rands, &l.X, &l.Index)
678 }
679 func (l *Lookup) String() string { return "lookup" }
680
681 // SelectState describes a case in a select statement.
682 type SelectState struct {
683 Dir token.Token // token.SEND or token.RECV
684 Chan Value
685 Send Value // nil for recv
686 Pos token.Pos
687 DebugRef0 Value
688 }
689
690 // Select implements a select statement.
691 type Select struct {
692 register
693 States []*SelectState
694 Blocking bool
695 }
696
697 func (s *Select) Operands(rands []*Value) []*Value {
698 for _, st := range s.States {
699 rands = append(rands, &st.Chan)
700 if st.Send != nil {
701 rands = append(rands, &st.Send)
702 }
703 }
704 return rands
705 }
706 func (s *Select) String() string { return "select" }
707
708 // Range creates an iterator for ranging over a string or map.
709 type Range struct {
710 register
711 X Value
712 }
713
714 func (r *Range) Operands(rands []*Value) []*Value { return append(rands, &r.X) }
715 func (r *Range) String() string { return "range" }
716
717 // Next advances an iterator: (ok, k, v) = next(iter).
718 type Next struct {
719 register
720 Iter Value
721 IsString bool
722 }
723
724 func (n *Next) Operands(rands []*Value) []*Value { return append(rands, &n.Iter) }
725 func (n *Next) String() string { return "next" }
726
727 // TypeAssert tests or converts an interface value: v, ok = x.(T).
728 type TypeAssert struct {
729 register
730 X Value
731 AssertedType typecheck.Type
732 CommaOk bool
733 }
734
735 func (t *TypeAssert) Operands(rands []*Value) []*Value { return append(rands, &t.X) }
736 func (t *TypeAssert) String() string { return "typeassert " + t.AssertedType.String() }
737
738 // Extract extracts the ith component from a multi-return tuple.
739 type Extract struct {
740 register
741 Tuple Value
742 Index int
743 }
744
745 func (e *Extract) Operands(rands []*Value) []*Value { return append(rands, &e.Tuple) }
746 func (e *Extract) String() string { return "extract" }
747
748 // ─── Terminator instructions ──────────────────────────────────────────────────
749
750 // Jump is an unconditional branch.
751 type Jump struct {
752 anInstruction
753 Comment string
754 }
755
756 func (j *Jump) Operands(rands []*Value) []*Value { return rands }
757 func (j *Jump) Pos() token.Pos { return 0 }
758 func (j *Jump) String() string { return "jump → " + j.Comment }
759
760 // If is a conditional branch: if cond goto t else f.
761 type If struct {
762 anInstruction
763 Cond Value
764 }
765
766 func (i *If) Operands(rands []*Value) []*Value { return append(rands, &i.Cond) }
767 func (i *If) Pos() token.Pos { return 0 }
768 func (i *If) String() string { return "if " + i.Cond.Name() }
769
770 // Return returns from the current function.
771 type Return struct {
772 anInstruction
773 Results []Value
774 pos token.Pos
775 }
776
777 func (r *Return) Operands(rands []*Value) []*Value {
778 for i := range r.Results {
779 rands = append(rands, &r.Results[i])
780 }
781 return rands
782 }
783 func (r *Return) Pos() token.Pos { return r.pos }
784 func (r *Return) String() string { return "return" }
785
786 // RunDefers executes all deferred calls.
787 type RunDefers struct {
788 anInstruction
789 }
790
791 func (rd *RunDefers) Operands(rands []*Value) []*Value { return rands }
792 func (rd *RunDefers) Pos() token.Pos { return 0 }
793 func (rd *RunDefers) String() string { return "rundefers" }
794
795 // Panic triggers a runtime panic.
796 type Panic struct {
797 anInstruction
798 X Value
799 pos token.Pos
800 }
801
802 func (p *Panic) Operands(rands []*Value) []*Value { return append(rands, &p.X) }
803 func (p *Panic) Pos() token.Pos { return p.pos }
804 func (p *Panic) String() string { return "panic" }
805
806 // ─── Spawn / goroutine instructions ──────────────────────────────────────────
807
808 // Go starts a goroutine (go stmt). In Moxie this is blocked; in stdlib code it
809 // may still appear. Kept for compatibility with stdlib imports until B3.
810 type Go struct {
811 anInstruction
812 Call CallCommon
813 pos token.Pos
814 }
815
816 func (g *Go) Operands(rands []*Value) []*Value { return g.Call.Operands(rands) }
817 func (g *Go) Pos() token.Pos { return g.pos }
818 func (g *Go) Common() *CallCommon { return &g.Call }
819 func (g *Go) String() string { return "go" }
820
821 // Defer queues a deferred call.
822 type Defer struct {
823 anInstruction
824 Call CallCommon
825 pos token.Pos
826 }
827
828 func (d *Defer) Operands(rands []*Value) []*Value { return d.Call.Operands(rands) }
829 func (d *Defer) Pos() token.Pos { return d.pos }
830 func (d *Defer) Common() *CallCommon { return &d.Call }
831 func (d *Defer) String() string { return "defer" }
832
833 // ─── Side-effecting instructions ──────────────────────────────────────────────
834
835 // Send sends a value on a channel.
836 type Send struct {
837 anInstruction
838 Chan Value
839 X Value
840 pos token.Pos
841 }
842
843 func (s *Send) Operands(rands []*Value) []*Value { return append(rands, &s.Chan, &s.X) }
844 func (s *Send) Pos() token.Pos { return s.pos }
845 func (s *Send) String() string { return "send" }
846
847 // Store stores a value at an address.
848 type Store struct {
849 anInstruction
850 Addr Value
851 Val Value
852 pos token.Pos
853 }
854
855 func (s *Store) Operands(rands []*Value) []*Value { return append(rands, &s.Addr, &s.Val) }
856 func (s *Store) Pos() token.Pos { return s.pos }
857 func (s *Store) String() string { return "store" }
858
859 // MapUpdate sets a map entry: m[k] = v.
860 type MapUpdate struct {
861 anInstruction
862 Map Value
863 Key Value
864 Value Value
865 pos token.Pos
866 }
867
868 func (m *MapUpdate) Operands(rands []*Value) []*Value {
869 return append(rands, &m.Map, &m.Key, &m.Value)
870 }
871 func (m *MapUpdate) Pos() token.Pos { return m.pos }
872 func (m *MapUpdate) String() string { return "mapupdate" }
873
874 // DebugRef is a debug reference: associates an ast node with a value.
875 // Used to generate DWARF variable entries.
876 type DebugRef struct {
877 anInstruction
878 Expr any // the syntax node (kept as any to avoid syntax import cycle)
879 object typecheck.Object
880 IsAddr bool
881 X Value
882 }
883
884 func (d *DebugRef) Operands(rands []*Value) []*Value { return append(rands, &d.X) }
885 func (d *DebugRef) Pos() token.Pos { return 0 }
886 func (d *DebugRef) Object() typecheck.Object { return d.object }
887 func (d *DebugRef) String() string { return "debugref" }
888