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