ssa_builder.mx raw

   1  package main
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/mxutil"
   5  	"git.smesh.lol/moxie/pkg/syntax"
   6  	"git.smesh.lol/moxie/pkg/token"
   7  	. "git.smesh.lol/moxie/pkg/types"
   8  )
   9  
  10  func asType(t Type) (tv Type) { return t }
  11  
  12  // ssaConstEqual compares two SSAConst values for equality.
  13  // Used to fold constant switch cases at SSA build time.
  14  func ssaConstEqual(a, b *SSAConst) (eq bool) {
  15  	if a.val == nil && b.val == nil {
  16  		return true
  17  	}
  18  	if a.val == nil || b.val == nil {
  19  		return false
  20  	}
  21  	switch av := a.val.(type) {
  22  	case *ConstStr:
  23  		if bv, ok := b.val.(*ConstStr); ok {
  24  			if len(av.S) != len(bv.S) {
  25  				return false
  26  			}
  27  			for i := int32(0); i < len(av.S); i++ {
  28  				if av.S[i] != bv.S[i] {
  29  					return false
  30  				}
  31  			}
  32  			return true
  33  		}
  34  	case *ConstInt:
  35  		if bv, ok := b.val.(*ConstInt); ok {
  36  			return av.V == bv.V
  37  		}
  38  	case *ConstBool:
  39  		if bv, ok := b.val.(*ConstBool); ok {
  40  			return av.V == bv.V
  41  		}
  42  	}
  43  	return false
  44  }
  45  
  46  // CreatePackage builds the SSA Package from type-checked syntax files.
  47  func (prog *SSAProgram) CreatePackage(pkg *TCPackage, files []*syntax.File, info *Info) (s *SSAPackage) {
  48  	p := &SSAPackage{
  49  		Prog:    prog,
  50  		Pkg:     pkg,
  51  		Members: map[string]SSAMember{},
  52  	}
  53  	prog.packages[pkg] = p
  54  	prog.imported[pkg.Path] = p
  55  
  56  	pb := &ssaPkgBuilder{pkg: p, info: info, prog: prog}
  57  
  58  	// Imports are file-scoped: each file gets a scope (parent = pkg scope)
  59  	// holding its own PkgName bindings, so two files can bind the same
  60  	// local name to different packages. The driver concatenates all package
  61  	// files into one syntax.File with a hoisted+deduped import block, so the
  62  	// per-file association comes from mxutil.ConcatImportSegs (per-file import
  63  	// specs + concat start line), and decls map to their file's scope by
  64  	// position.
  65  	pb.fileScopes = map[*syntax.File]*Scope{}
  66  	pb.varInitScopes = map[*syntax.VarDecl]*Scope{}
  67  	for _, f := range files {
  68  		pb.fileScopes[f] = NewScope(pkg.Scope)
  69  	}
  70  	pb.buildImportSegScopes()
  71  
  72  	for _, f := range files {
  73  		if f == nil {
  74  			continue
  75  		}
  76  		pb.curFileScope = pb.fileScopes[f]
  77  		pb.registerImportsAndTypes(f)
  78  	}
  79  	for _, f := range files {
  80  		pb.curFileScope = pb.fileScopes[f]
  81  		pb.registerFile(f)
  82  	}
  83  	for _, f := range files {
  84  		pb.curFileScope = pb.fileScopes[f]
  85  		pb.buildFile(f)
  86  	}
  87  	pb.curFileScope = nil
  88  	if len(pb.varInits) > 0 {
  89  		pb.buildVarInits()
  90  	}
  91  	return p
  92  }
  93  
  94  // ssaPkgBuilder builds one SSAPackage.
  95  type ssaPkgBuilder struct {
  96  	pkg           *SSAPackage
  97  	info          *Info
  98  	prog          *SSAProgram
  99  	varInits      []*syntax.VarDecl
 100  	fileScopes    map[*syntax.File]*Scope
 101  	curFileScope  *Scope
 102  	varInitScopes map[*syntax.VarDecl]*Scope
 103  	segScopes     []segScope
 104  }
 105  
 106  // segScope is one source file's import scope in the concatenated package
 107  // stream, keyed by the concat line its body starts at.
 108  type segScope struct {
 109  	outStart int32
 110  	scope    *Scope
 111  }
 112  
 113  // buildImportSegScopes turns the driver's per-file import segments into
 114  // scopes holding each file's PkgName bindings.
 115  func (pb *ssaPkgBuilder) buildImportSegScopes() {
 116  	pb.segScopes = nil
 117  	for si := 0; si < len(mxutil.ConcatImportSegs); si++ {
 118  		seg := mxutil.ConcatImportSegs[si]
 119  		sc := NewScope(pb.pkg.Pkg.Scope)
 120  		for _, spec := range seg.Specs {
 121  			path := mxutil.ExtractQuoted(spec)
 122  			if path == "" {
 123  				continue
 124  			}
 125  			alias := importSpecAlias(spec)
 126  			if alias == "." || alias == "_" {
 127  				continue
 128  			}
 129  			target := pb.resolveImportTarget(path)
 130  			if target == nil {
 131  				continue
 132  			}
 133  			localName := alias
 134  			if localName == "" {
 135  				localName = target.Name
 136  			}
 137  			if localName == "" {
 138  				for i := len(path) - 1; i >= 0; i-- {
 139  					if path[i] == '/' {
 140  						localName = path[i+1:]
 141  						break
 142  					}
 143  				}
 144  				if localName == "" {
 145  					localName = path
 146  				}
 147  			}
 148  			sc.Insert(NewPkgName(nil, localName, target))
 149  		}
 150  		push(pb.segScopes, segScope{outStart: seg.OutStart, scope: sc})
 151  	}
 152  }
 153  
 154  // importSpecAlias returns the local alias of a raw import spec line
 155  // (`alias "path"`), or "" when the spec has no alias.
 156  func importSpecAlias(spec string) (s string) {
 157  	for i := int32(0); i < int32(len(spec)); i++ {
 158  		if spec[i] == '"' {
 159  			return mxutil.TrimSpace(spec[:i])
 160  		}
 161  	}
 162  	return ""
 163  }
 164  
 165  func (pb *ssaPkgBuilder) resolveImportTarget(path string) (t *TCPackage) {
 166  	impPkg := pb.prog.ImportedPackage(path)
 167  	if impPkg != nil && impPkg.Pkg != nil {
 168  		return impPkg.Pkg
 169  	}
 170  	return cctx.universe.Registry[path]
 171  }
 172  
 173  // declScope returns the import scope of the source file a decl came from.
 174  // Decls before the first segment (the hoisted import block) get nil.
 175  func (pb *ssaPkgBuilder) declScope(d syntax.Decl) (sc *Scope) {
 176  	if len(pb.segScopes) == 0 {
 177  		return pb.curFileScope
 178  	}
 179  	// Pos() lives on the embedded node base; interface dispatch does not
 180  	// cover embedded-base methods of another package's types, so switch on
 181  	// the concrete decl types.
 182  	line := int32(0)
 183  	switch dd := d.(type) {
 184  	case *syntax.ImportDecl:
 185  		dp := dd.Pos()
 186  		line = int32(dp.Line())
 187  	case *syntax.ConstDecl:
 188  		dp := dd.Pos()
 189  		line = int32(dp.Line())
 190  	case *syntax.TypeDecl:
 191  		dp := dd.Pos()
 192  		line = int32(dp.Line())
 193  	case *syntax.VarDecl:
 194  		dp := dd.Pos()
 195  		line = int32(dp.Line())
 196  	case *syntax.FuncDecl:
 197  		dp := dd.Pos()
 198  		line = int32(dp.Line())
 199  	}
 200  	// Parser positions are 0-based (p.pos subtracts Linebase); seg outStart
 201  	// is a 1-based concat line. Convert at this boundary.
 202  	line++
 203  	var best *Scope
 204  	for i := 0; i < len(pb.segScopes); i++ {
 205  		if pb.segScopes[i].outStart <= line {
 206  			best = pb.segScopes[i].scope
 207  		}
 208  	}
 209  	return best
 210  }
 211  
 212  func (pb *ssaPkgBuilder) registerImportsAndTypes(f *syntax.File) {
 213  	for _, d := range f.DeclList {
 214  		if d == nil {
 215  			continue
 216  		}
 217  		pb.curFileScope = pb.declScope(d)
 218  		switch dd := d.(type) {
 219  		case *syntax.ImportDecl:
 220  			pb.registerImport(dd)
 221  		case *syntax.TypeDecl:
 222  			pb.registerType(dd)
 223  		default:
 224  		}
 225  	}
 226  }
 227  
 228  func (pb *ssaPkgBuilder) registerFile(f *syntax.File) {
 229  	for _, d := range f.DeclList {
 230  		pb.curFileScope = pb.declScope(d)
 231  		switch dd := d.(type) {
 232  		case *syntax.FuncDecl:
 233  			pb.registerFunc(dd)
 234  		case *syntax.VarDecl:
 235  			pb.registerVar(dd)
 236  		case *syntax.ConstDecl:
 237  			pb.registerConst(dd)
 238  		}
 239  	}
 240  }
 241  
 242  func (pb *ssaPkgBuilder) registerImport(d *syntax.ImportDecl) {
 243  	if d.Path == nil {
 244  		return
 245  	}
 246  	path := d.Path.Value
 247  	if len(path) >= 2 && path[0] == '"' {
 248  		path = path[1 : len(path)-1]
 249  	}
 250  	localName := ""
 251  	if d.LocalPkgName != nil {
 252  		localName = d.LocalPkgName.Value
 253  	}
 254  	target := pb.resolveImportTarget(path)
 255  	if target == nil {
 256  		return
 257  	}
 258  	// Default name is the package clause name, NOT the path tail: the two
 259  	// differ for packages like crypto/ec (package btcec).
 260  	if localName == "" {
 261  		localName = target.Name
 262  	}
 263  	if localName == "" {
 264  		for i := len(path) - 1; i >= 0; i-- {
 265  			if path[i] == '/' {
 266  				localName = path[i+1:]
 267  				break
 268  			}
 269  		}
 270  		if localName == "" {
 271  			localName = path
 272  		}
 273  	}
 274  	if localName == "." || localName == "_" {
 275  		return
 276  	}
 277  	// Track all direct imports regardless of local-name collisions.
 278  	tcp := pb.pkg.Pkg
 279  	found := false
 280  	for _, ip := range tcp.Imports {
 281  		if ip == target {
 282  			found = true
 283  			break
 284  		}
 285  	}
 286  	if !found {
 287  		push(tcp.Imports, target)
 288  	}
 289  	pn := NewPkgName(nil, localName, target)
 290  	// File scope binding wins over a same-named import in another file.
 291  	if pb.curFileScope != nil {
 292  		pb.curFileScope.Insert(pn)
 293  	}
 294  	// Legacy fallback for lookup paths without file context: first-wins.
 295  	if existing := pb.pkg.Pkg.Scope.Lookup(localName); existing != nil {
 296  		return
 297  	}
 298  	pb.pkg.Pkg.Scope.Insert(pn)
 299  }
 300  
 301  func pkgResolveTypeAST(pkg *SSAPackage, e syntax.Expr) (t Type) {
 302  	if e == nil {
 303  		return nil
 304  	}
 305  	switch ev := e.(type) {
 306  	case *syntax.Name:
 307  		if _, obj := Universe.LookupParent(ev.Value); obj != nil {
 308  			if tn, ok := obj.(*TypeName); ok {
 309  				return tn.Typ
 310  			}
 311  		}
 312  		if pkg != nil {
 313  			obj := pkg.Pkg.Scope.Lookup(ev.Value)
 314  			if tn, ok := obj.(*TypeName); ok {
 315  				return tn.Typ
 316  			}
 317  		}
 318  	case *syntax.Operation:
 319  		if ev.Y == nil && ev.Op == token.Mul {
 320  			base := pkgResolveTypeAST(pkg, ev.X)
 321  			if base != nil {
 322  				return NewPointer(base)
 323  			}
 324  		}
 325  	case *syntax.ArrayType:
 326  		elem := pkgResolveTypeAST(pkg, ev.Elem)
 327  		if elem != nil {
 328  			n := int64(-1)
 329  			if lit, ok := ev.Len.(*syntax.BasicLit); ok {
 330  				n = ssaParseInt64(lit.Value)
 331  			}
 332  			return NewArray(elem, n)
 333  		}
 334  	case *syntax.SliceType:
 335  		elem := pkgResolveTypeAST(pkg, ev.Elem)
 336  		if elem != nil {
 337  			if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
 338  				return Typ[TCString]
 339  			}
 340  			return NewSlice(elem)
 341  		}
 342  	case *syntax.MapType:
 343  		key := pkgResolveTypeAST(pkg, ev.Key)
 344  		val := pkgResolveTypeAST(pkg, ev.Value)
 345  		if key != nil && val != nil {
 346  			return NewTCMap(key, val)
 347  		}
 348  	case *syntax.FuncType:
 349  		return pkgResolveSigAST(pkg, ev)
 350  	case *syntax.SelectorExpr:
 351  		if x, ok := ev.X.(*syntax.Name); ok {
 352  			pn, _ := pkg.Pkg.Scope.Lookup(x.Value).(*PkgName)
 353  			if pn != nil && pn.Imported != nil {
 354  				sel := pn.Imported.Scope.Lookup(ev.Sel.Value)
 355  				if tn, ok2 := sel.(*TypeName); ok2 {
 356  					return tn.Typ
 357  				}
 358  			}
 359  		}
 360  	case *syntax.InterfaceType:
 361  		return resolveInterfaceFromAST(ev)
 362  	case *syntax.DotsType:
 363  		elem := pkgResolveTypeAST(pkg, ev.Elem)
 364  		if elem != nil {
 365  			if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
 366  				return Typ[TCString]
 367  			}
 368  			return NewSlice(elem)
 369  		}
 370  	}
 371  	return nil
 372  }
 373  
 374  func pkgResolveSigAST(pkg *SSAPackage, ft *syntax.FuncType) (s *Signature) {
 375  	if ft == nil {
 376  		return nil
 377  	}
 378  	var params []*TCVar
 379  	for _, p := range ft.ParamList {
 380  		typ := pkgResolveTypeAST(pkg, p.Type)
 381  		pname := ""
 382  		if p.Name != nil {
 383  			pname = p.Name.Value
 384  		}
 385  		push(params, NewTCVar(nil, pname, typ))
 386  	}
 387  	var results []*TCVar
 388  	for _, r := range ft.ResultList {
 389  		typ := pkgResolveTypeAST(pkg, r.Type)
 390  		rname := ""
 391  		if r.Name != nil {
 392  			rname = r.Name.Value
 393  		}
 394  		push(results, NewTCVar(nil, rname, typ))
 395  	}
 396  	variadic := false
 397  	if len(ft.ParamList) > 0 {
 398  		if _, ok := ft.ParamList[len(ft.ParamList)-1].Type.(*syntax.DotsType); ok {
 399  			variadic = true
 400  		}
 401  	}
 402  	var pTuple, rTuple *Tuple
 403  	if len(params) > 0 {
 404  		pTuple = NewTuple(params...)
 405  	}
 406  	if len(results) > 0 {
 407  		rTuple = NewTuple(results...)
 408  	}
 409  	return NewSignature(nil, pTuple, rTuple, variadic)
 410  }
 411  
 412  func (pb *ssaPkgBuilder) registerFunc(d *syntax.FuncDecl) {
 413  	if len(d.TParamList) > 0 {
 414  		return
 415  	}
 416  	if d.Recv != nil {
 417  		pb.registerMethod(d)
 418  		return
 419  	}
 420  	if d.Name.Value == "init" {
 421  		mxutil.WriteStr(2, "compile error: init() is not allowed; use main() for package initialization\n")
 422  		return
 423  	}
 424  	var obj *TCFunc
 425  	if o := pb.pkg.Pkg.Scope.Lookup(d.Name.Value); o != nil {
 426  		obj, _ = o.(*TCFunc)
 427  	}
 428  	var sig *Signature
 429  	if obj != nil {
 430  		sig, _ = obj.Typ.(*Signature)
 431  	}
 432  	if sig == nil && d.Type != nil {
 433  		sig = pkgResolveSigAST(pb.pkg, d.Type)
 434  	}
 435  	fn := &SSAFunction{
 436  		name:      d.Name.Value,
 437  		object:    obj,
 438  		Signature: sig,
 439  		pos:       0,
 440  		Pkg:       pb.pkg,
 441  		Prog:      pb.prog,
 442  	}
 443  	if cctx.compileExportMap != nil {
 444  		if ename, ok := cctx.compileExportMap[d.Name.Value]; ok {
 445  			fn.externalSymbol = ename
 446  			fn.isExternC = true
 447  		}
 448  	}
 449  	if d.Body == nil && isNoContextExtern(pb.pkg.Pkg.Path, d.Name.Value) {
 450  		fn.isExternC = true
 451  	}
 452  	pb.pkg.SetMember(fn.name, fn)
 453  }
 454  
 455  func checkInitBody(body *syntax.BlockStmt) (s string) {
 456  	for _, st := range body.List {
 457  		if err := checkInitStmt(st); err != "" {
 458  			return err
 459  		}
 460  	}
 461  	return ""
 462  }
 463  
 464  func checkInitStmt(s syntax.Stmt) (sv string) {
 465  	switch ss := s.(type) {
 466  	case *syntax.SelectStmt:
 467  		_ = ss
 468  		return "select{} not allowed in init()"
 469  	case *syntax.BlockStmt:
 470  		for _, sub := range ss.List {
 471  			if err := checkInitStmt(sub); err != "" {
 472  				return err
 473  			}
 474  		}
 475  	case *syntax.IfStmt:
 476  		if ss.Then != nil {
 477  			if err := checkInitStmt(ss.Then); err != "" {
 478  				return err
 479  			}
 480  		}
 481  		if ss.Else != nil {
 482  			if err := checkInitStmt(ss.Else); err != "" {
 483  				return err
 484  			}
 485  		}
 486  	case *syntax.ForStmt:
 487  		if ss.Body != nil {
 488  			if err := checkInitStmt(ss.Body); err != "" {
 489  				return err
 490  			}
 491  		}
 492  	case *syntax.SwitchStmt:
 493  		for _, cc := range ss.Body {
 494  			for _, sub := range cc.Body {
 495  				if err := checkInitStmt(sub); err != "" {
 496  					return err
 497  				}
 498  			}
 499  		}
 500  	case *syntax.ExprStmt:
 501  		if err := checkInitExpr(ss.X); err != "" {
 502  			return err
 503  		}
 504  	}
 505  	return ""
 506  }
 507  
 508  func checkInitExpr(x syntax.Expr) (s string) {
 509  	if x == nil {
 510  		return ""
 511  	}
 512  	if c, ok := x.(*syntax.CallExpr); ok {
 513  		if n, ok2 := c.Fun.(*syntax.Name); ok2 && n.Value == "spawn" {
 514  			return "spawn() not allowed in init()"
 515  		}
 516  	}
 517  	return ""
 518  }
 519  
 520  func isNoContextExtern(pkg, name string) (ok bool) {
 521  	if pkg == "internal/runtime/syscall" && name == "Syscall6" {
 522  		return true
 523  	}
 524  	if pkg == "syscall" {
 525  		switch name {
 526  		case "runtime_entersyscall", "runtime_exitsyscall",
 527  			"Exit", "Getpagesize", "gettimeofday",
 528  			"runtime_BeforeExec", "runtime_AfterExec",
 529  			"runtime_BeforeFork", "runtime_AfterFork", "runtime_AfterForkInChild":
 530  			return true
 531  		}
 532  	}
 533  	if pkg == "os" {
 534  		switch name {
 535  		case "putchar", "getchar", "buffered", "gosched", "runtime_args":
 536  			return true
 537  		}
 538  	}
 539  	return false
 540  }
 541  
 542  func (pb *ssaPkgBuilder) registerMethod(d *syntax.FuncDecl) {
 543  	recvTypeName := ssaRecvTypeName(d.Recv)
 544  	if recvTypeName == "" {
 545  		return
 546  	}
 547  	// All methods use (*Type).Method naming regardless of receiver type.
 548  	mangledName := "(*" | recvTypeName | ")." | d.Name.Value
 549  	var obj *TCFunc
 550  	obj = pb.findMethod(recvTypeName, d.Name.Value)
 551  	var sig *Signature
 552  	if obj != nil {
 553  		sig, _ = obj.Typ.(*Signature)
 554  	}
 555  	if sig == nil && d.Type != nil {
 556  		sig = pkgResolveSigAST(pb.pkg, d.Type)
 557  	}
 558  	if sig == nil {
 559  		mxutil.WriteStr(2, "WARN: nil sig for method " | mangledName | "\n")
 560  	}
 561  	fn := &SSAFunction{
 562  		name:      mangledName,
 563  		object:    obj,
 564  		Signature: sig,
 565  		pos:       0,
 566  		Pkg:       pb.pkg,
 567  		Prog:      pb.prog,
 568  	}
 569  	pb.pkg.SetMember(mangledName, fn)
 570  }
 571  
 572  func ssaRecvTypeName(recv *syntax.Field) (s string) {
 573  	if recv == nil {
 574  		return ""
 575  	}
 576  	switch t := recv.Type.(type) {
 577  	case *syntax.Name:
 578  		return t.Value
 579  	case *syntax.Operation:
 580  		if t.Y == nil && t.Op == token.Mul {
 581  			if n, ok := t.X.(*syntax.Name); ok {
 582  				return n.Value
 583  			}
 584  		}
 585  	}
 586  	return ""
 587  }
 588  
 589  func ssaRecvIsPtr(recv *syntax.Field) (ok bool) {
 590  	if recv == nil {
 591  		return false
 592  	}
 593  	if op, ok2 := recv.Type.(*syntax.Operation); ok2 {
 594  		return op.Y == nil && op.Op == token.Mul
 595  	}
 596  	return false
 597  }
 598  
 599  func (pb *ssaPkgBuilder) findMethod(typeName string, methodName string) (t *TCFunc) {
 600  	obj := pb.pkg.Pkg.Scope.Lookup(typeName)
 601  	if obj == nil && Universe != nil {
 602  		obj = Universe.Lookup(typeName)
 603  	}
 604  	if obj == nil {
 605  		return nil
 606  	}
 607  	tn, ok := obj.(*TypeName)
 608  	if !ok {
 609  		return nil
 610  	}
 611  	switch tt := tn.Typ.(type) {
 612  	case *Named:
 613  		for i := int32(0); i < tt.NumMethods(); i++ {
 614  			m := tt.Method(i)
 615  			if m.Name == methodName {
 616  				return m
 617  			}
 618  		}
 619  	case *Basic:
 620  		for i := int32(0); i < tt.NumMethods(); i++ {
 621  			m := tt.Method(i)
 622  			if m.Name == methodName {
 623  				return m
 624  			}
 625  		}
 626  	}
 627  	return nil
 628  }
 629  
 630  func (pb *ssaPkgBuilder) registerVar(d *syntax.VarDecl) {
 631  	for _, name := range d.NameList {
 632  		var obj *TCVar
 633  		if o := pb.pkg.Pkg.Scope.Lookup(name.Value); o != nil {
 634  			obj, _ = o.(*TCVar)
 635  		}
 636  		var typ Type
 637  		if obj != nil {
 638  			typ = obj.Typ
 639  		}
 640  		if typ == nil && d.Type != nil {
 641  			typ = pkgResolveTypeAST(pb.pkg, d.Type)
 642  		}
 643  		if typ == nil && d.Values != nil {
 644  			typ = pkgResolveTypeAST(pb.pkg, d.Values)
 645  		}
 646  		g := &SSAGlobal{
 647  			name:   name.Value,
 648  			object: obj,
 649  			typ:    NewPointer(typ),
 650  			pos:    0,
 651  			pkg:    pb.pkg,
 652  		}
 653  		pb.pkg.SetMember(name.Value, g)
 654  	}
 655  	if d.Values != nil {
 656  		push(pb.varInits, d)
 657  		pb.varInitScopes[d] = pb.curFileScope
 658  	}
 659  }
 660  
 661  func (pb *ssaPkgBuilder) registerType(d *syntax.TypeDecl) {
 662  	var obj *TypeName
 663  	if o := pb.pkg.Pkg.Scope.Lookup(d.Name.Value); o != nil {
 664  		obj, _ = o.(*TypeName)
 665  	}
 666  	if obj == nil {
 667  		underlying := pkgResolveTypeAST(pb.pkg, d.Type)
 668  		if underlying == nil {
 669  			underlying = &TCStruct{}
 670  		}
 671  		named := NewNamed(NewTypeName(pb.pkg.Pkg, d.Name.Value, nil), underlying)
 672  		named.Obj.Typ = named
 673  		pb.pkg.Pkg.Scope.Insert(named.Obj)
 674  		obj = named.Obj
 675  	}
 676  	t := &SSAType_{object: obj, pkg: pb.pkg}
 677  	pb.pkg.SetMember(d.Name.Value, t)
 678  }
 679  
 680  func (pb *ssaPkgBuilder) registerConst(d *syntax.ConstDecl) {
 681  	for _, name := range d.NameList {
 682  		var obj *TCConst
 683  		if o := pb.pkg.Pkg.Scope.Lookup(name.Value); o != nil {
 684  			obj, _ = o.(*TCConst)
 685  		}
 686  		if obj == nil {
 687  			continue
 688  		}
 689  		c := &SSANamedConst{
 690  			object: obj,
 691  			Value:  &SSAConst{typ: obj.Typ, val: localizeConstVal(obj.Val, obj.Typ)},
 692  			pkg:    pb.pkg,
 693  		}
 694  		pb.pkg.SetMember(name.Value, c)
 695  	}
 696  }
 697  
 698  func (pb *ssaPkgBuilder) buildFile(f *syntax.File) {
 699  	for _, d := range f.DeclList {
 700  		if fd, ok := d.(*syntax.FuncDecl); ok {
 701  			pb.curFileScope = pb.declScope(d)
 702  			if fd.Recv != nil {
 703  				ssaRecvTypeName(fd.Recv)
 704  			}
 705  			pb.buildFunc(fd)
 706  		}
 707  	}
 708  }
 709  
 710  func (pb *ssaPkgBuilder) buildVarInits() {
 711  	sig := &Signature{
 712  		Params:  NewTuple(),
 713  		Results: NewTuple(),
 714  	}
 715  	fn, _ := pb.pkg.Members["main"].(*SSAFunction)
 716  	if fn == nil {
 717  		fn = &SSAFunction{
 718  			name:      "main",
 719  			Signature: sig,
 720  			Pkg:       pb.pkg,
 721  			Prog:      pb.prog,
 722  		}
 723  		pb.pkg.SetMember("main", fn)
 724  	}
 725  	if len(fn.Blocks) > 0 {
 726  		initSig := &Signature{Params: NewTuple(), Results: NewTuple()}
 727  		initFn := &SSAFunction{
 728  			name:      "__varinit",
 729  			Signature: initSig,
 730  			Pkg:       pb.pkg,
 731  			Prog:      pb.prog,
 732  		}
 733  		pb.pkg.SetMember("__varinit", initFn)
 734  		fb2 := newSSAFuncBuilder(initFn, pb.info)
 735  		entry2 := fb2.newBlock("entry")
 736  		fb2.currentBlock = entry2
 737  		for _, d := range pb.varInits {
 738  			if d.Values == nil {
 739  				continue
 740  			}
 741  			fb2.fileScope = pb.varInitScopes[d]
 742  			rhs := fb2.buildExpr(d.Values)
 743  			if rhs == nil {
 744  				continue
 745  			}
 746  			for _, name := range d.NameList {
 747  				if name.Value == "_" {
 748  					continue
 749  				}
 750  				fb2.buildStore(name, rhs)
 751  			}
 752  		}
 753  		fb2.emit(&SSAReturn{})
 754  		// Inject call to __varinit at start of main
 755  		callInstr := &SSACall{Call: SSACallCommon{Value: initFn}}
 756  		callInstr.name = "vinit"
 757  		oldEntry := fn.Blocks[0]
 758  		n := int32(len(oldEntry.Instrs))
 759  		combined := []SSAInstruction{:n+1}
 760  		combined[0] = callInstr
 761  		for i := int32(0); i < n; i++ {
 762  			combined[i+1] = oldEntry.Instrs[i]
 763  		}
 764  		oldEntry.Instrs = combined
 765  		return
 766  	}
 767  	fb := newSSAFuncBuilder(fn, pb.info)
 768  	entry := fb.newBlock("entry")
 769  	fb.currentBlock = entry
 770  	for _, d := range pb.varInits {
 771  		if d.Values == nil {
 772  			continue
 773  		}
 774  		fb.fileScope = pb.varInitScopes[d]
 775  		rhs := fb.buildExpr(d.Values)
 776  		if rhs == nil {
 777  			continue
 778  		}
 779  		for _, name := range d.NameList {
 780  			if name.Value == "_" {
 781  				continue
 782  			}
 783  			fb.buildStore(name, rhs)
 784  		}
 785  	}
 786  	fb.emit(&SSAReturn{})
 787  }
 788  
 789  func (pb *ssaPkgBuilder) buildFunc(d *syntax.FuncDecl) {
 790  	if len(d.TParamList) > 0 {
 791  		return
 792  	}
 793  	if d.Body == nil {
 794  		return
 795  	}
 796  	name := d.Name.Value
 797  	if d.Recv != nil {
 798  		rtn := ssaRecvTypeName(d.Recv)
 799  		if rtn != "" {
 800  			name = "(*" | rtn | ")." | d.Name.Value
 801  		}
 802  	}
 803  	member := pb.pkg.Members[name]
 804  	if member == nil {
 805  		mxutil.WriteStr(2, "WARN: buildFunc no member for " | name | "\n")
 806  		return
 807  	}
 808  	fn, ok := member.(*SSAFunction)
 809  	if !ok || fn == nil {
 810  		mxutil.WriteStr(2, "WARN: buildFunc member not SSAFunction for " | name | "\n")
 811  		return
 812  	}
 813  	fb := newSSAFuncBuilder(fn, pb.info)
 814  	fb.fileScope = pb.curFileScope
 815  	fb.buildBody(d)
 816  }
 817  
 818  // ssaFuncBuilder builds one SSAFunction body.
 819  type ssaFuncBuilder struct {
 820  	fn           *SSAFunction
 821  	info         *Info
 822  	parent       *ssaFuncBuilder
 823  	currentBlock *SSABasicBlock
 824  	vars         map[Object]*SSAAlloc
 825  	localTypes   map[string]Type
 826  	localConsts  map[string]*SSAConst
 827  	freeVarPtrs  map[string]*SSAFreeVar
 828  	namedResults []*SSAAlloc
 829  	paramAllocas []*SSAAlloc
 830  	tailBlock    *SSABasicBlock
 831  	counter      int32
 832  
 833  	loops        []ssaLoopState
 834  	pendingLabel string
 835  	labels       map[string]*SSABasicBlock
 836  	deferred     int32
 837  	typeSubst    map[string]Type
 838  	srcScope     *Scope
 839  	fileScope    *Scope // imports of the file declaring this function
 840  	decl         *syntax.FuncDecl
 841  	scopeID      int32
 842  	nextScopeID  int32
 843  }
 844  
 845  type ssaLoopState struct {
 846  	label string
 847  	body  *SSABasicBlock
 848  	post  *SSABasicBlock
 849  	done  *SSABasicBlock
 850  }
 851  
 852  func newSSAFuncBuilder(fn *SSAFunction, info *Info) (p *ssaFuncBuilder) {
 853  	return &ssaFuncBuilder{
 854  		fn:         fn,
 855  		info:       info,
 856  		vars:       map[Object]*SSAAlloc{},
 857  		localTypes: map[string]Type{},
 858  	}
 859  }
 860  
 861  func (fb *ssaFuncBuilder) newBlock(comment string) (s *SSABasicBlock) {
 862  	b := NewSSABasicBlock(fb.fn, comment)
 863  	b.ScopeID = fb.scopeID
 864  	return b
 865  }
 866  
 867  func (fb *ssaFuncBuilder) enterScope() (prev int32) {
 868  	fb.nextScopeID++
 869  	prev = fb.scopeID
 870  	fb.scopeID = fb.nextScopeID
 871  	return prev
 872  }
 873  
 874  func (fb *ssaFuncBuilder) exitScope(old int32) {
 875  	fb.scopeID = old
 876  }
 877  
 878  func (fb *ssaFuncBuilder) labelBlock(name string) (s *SSABasicBlock) {
 879  	if fb.labels == nil {
 880  		fb.labels = map[string]*SSABasicBlock{}
 881  	}
 882  	if lb := fb.labels[name]; lb != nil {
 883  		return lb
 884  	}
 885  	nb := fb.newBlock("label." + name)
 886  	fb.labels[name] = nb
 887  	return nb
 888  }
 889  
 890  func (fb *ssaFuncBuilder) emit(instr SSAInstruction) {
 891  	if fb.currentBlock == nil {
 892  		return
 893  	}
 894  	instr.setBlock(fb.currentBlock)
 895  	push(fb.currentBlock.Instrs, instr)
 896  }
 897  
 898  func (fb *ssaFuncBuilder) nextName() (s string) {
 899  	fb.counter++
 900  	return "t" | ssaItoa(fb.counter)
 901  }
 902  
 903  func (fb *ssaFuncBuilder) buildBody(d *syntax.FuncDecl) {
 904  	fb.decl = d
 905  	entry := fb.newBlock("entry")
 906  	fb.currentBlock = entry
 907  
 908  	sig := fb.fn.Signature
 909  	if sig == nil {
 910  		return
 911  	}
 912  	params := sig.Params
 913  	if d.Recv != nil {
 914  		recv := sig.Recv
 915  		if recv != nil {
 916  			recvName := recv.Name
 917  			if recvName == "" && d.Recv.Name != nil {
 918  				recvName = d.Recv.Name.Value
 919  			}
 920  			// All receivers are ptr in Moxie. If the type checker says
 921  			// value receiver, wrap in pointer so the SSA type is *T.
 922  			recvType := recv.Typ
 923  			isValRecv := false
 924  			if _, isP := SafeUnderlying(recvType).(*Pointer); !isP {
 925  				recvType = NewPointer(recvType)
 926  				isValRecv = true
 927  			}
 928  			p := &SSAParameter{
 929  				name:   recvName,
 930  				typ:    recvType,
 931  				pos:    0,
 932  				parent: fb.fn,
 933  			}
 934  			push(fb.fn.Params, p)
 935  			if recvName != "" && recvName != "_" {
 936  				recvObj := NewTCVar(fb.fn.Pkg.Pkg, recvName, recv.Typ)
 937  				p.object = recvObj
 938  				alloc := fb.emitAlloc(recv.Typ, 0)
 939  				fb.vars[recvObj] = alloc
 940  				push(fb.paramAllocas, alloc)
 941  				if isValRecv {
 942  					// p is *T; load the value T from the pointer, then store.
 943  					deref := &SSAUnOp{Op: OpMul, X: p}
 944  					deref.typ = recv.Typ
 945  					push(fb.fn.Blocks[0].Instrs, deref)
 946  					fb.emitStore(alloc, deref)
 947  				} else {
 948  					fb.emitStore(alloc, p)
 949  				}
 950  			}
 951  		}
 952  	}
 953  	if params != nil {
 954  		for i := 0; i < params.Len(); i++ {
 955  			pvar := params.At(i)
 956  			p := &SSAParameter{
 957  				name:   pvar.Name,
 958  				typ:    pvar.Typ,
 959  				pos:    fb.fn.pos,
 960  				parent: fb.fn,
 961  			}
 962  			push(fb.fn.Params, p)
 963  			if pvar.Name != "" && pvar.Name != "_" {
 964  				obj := NewTCVar(fb.fn.Pkg.Pkg, pvar.Name, pvar.Typ)
 965  				alloc := fb.emitAlloc(pvar.Typ, p.pos)
 966  				fb.vars[obj] = alloc
 967  				push(fb.paramAllocas, alloc)
 968  				fb.emitStore(alloc, p)
 969  			}
 970  		}
 971  	}
 972  
 973  	if sig.Results != nil {
 974  		for i := 0; i < sig.Results.Len(); i++ {
 975  			r := sig.Results.At(i)
 976  			if r.Name != "" && r.Name != "_" {
 977  				alloc := fb.emitAlloc(r.Typ, fb.fn.pos)
 978  				push(fb.namedResults, alloc)
 979  				push(fb.fn.Locals, alloc)
 980  				fb.vars[r] = alloc
 981  			}
 982  		}
 983  	}
 984  
 985  	if len(fb.paramAllocas) > 0 {
 986  		fb.tailBlock = fb.newBlock("tailcall")
 987  		fb.emit(&SSAJump{Comment: "enter.body"})
 988  		push(fb.currentBlock.Succs, fb.tailBlock)
 989  		push(fb.tailBlock.Preds, fb.currentBlock)
 990  		fb.currentBlock = fb.tailBlock
 991  	}
 992  
 993  	if d.Body != nil {
 994  		fb.buildBlock(d.Body)
 995  	}
 996  
 997  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
 998  		if len(fb.namedResults) > 0 {
 999  			var vals []SSAValue
1000  			for _, nr := range fb.namedResults {
1001  				elemType := nr.SSAType()
1002  				if p, ok := elemType.(*Pointer); ok {
1003  					elemType = p.Base
1004  				}
1005  				push(vals, fb.emitLoad(nr, elemType))
1006  			}
1007  			fb.emitReturn(vals, 0)
1008  		} else {
1009  			fb.emitReturn(nil, 0)
1010  		}
1011  	}
1012  	fb.fn.NamedResults = fb.namedResults
1013  }
1014  
1015  func (fb *ssaFuncBuilder) emitAlloc(typ Type, pos int32) (s *SSAAlloc) {
1016  	a := &SSAAlloc{Heap: false}
1017  	a.typ = NewPointer(typ)
1018  	a.pos = pos
1019  	a.name = fb.nextName()
1020  	fb.emit(a)
1021  	push(fb.fn.Locals, a)
1022  	return a
1023  }
1024  
1025  func (fb *ssaFuncBuilder) emitStore(addr SSAValue, val SSAValue) {
1026  	fb.emit(&SSAStore{Addr: addr, Val: val})
1027  }
1028  
1029  func (fb *ssaFuncBuilder) emitLoad(addr SSAValue, typ Type) (s SSAValue) {
1030  	u := &SSAUnOp{Op: OpMul, X: addr}
1031  	u.typ = typ
1032  	u.name = fb.nextName()
1033  	fb.emit(u)
1034  	return u
1035  }
1036  
1037  func (fb *ssaFuncBuilder) emitReturn(vals []SSAValue, pos int32) {
1038  	fb.emit(&SSAReturn{Results: vals, pos: pos})
1039  	fb.currentBlock = nil
1040  }
1041  
1042  func (fb *ssaFuncBuilder) blockTerminated(b *SSABasicBlock) (ok bool) {
1043  	if len(b.Instrs) == 0 {
1044  		return false
1045  	}
1046  	switch b.Instrs[len(b.Instrs)-1].(type) {
1047  	case *SSAReturn, *SSAJump, *SSAIf, *SSAPanic:
1048  		return true
1049  	}
1050  	return false
1051  }
1052  
1053  // Statement builders.
1054  
1055  func (fb *ssaFuncBuilder) buildBlock(b *syntax.BlockStmt) {
1056  	if b == nil {
1057  		return
1058  	}
1059  	for _, s := range b.List {
1060  		fb.buildStmt(s)
1061  	}
1062  }
1063  
1064  func (fb *ssaFuncBuilder) buildStmt(s syntax.Stmt) {
1065  	if s == nil {
1066  		return
1067  	}
1068  	if ls, ok := s.(*syntax.LabeledStmt); ok {
1069  		if ls.Label != nil {
1070  			fb.pendingLabel = ls.Label.Value
1071  			lblBlock := fb.labelBlock(ls.Label.Value)
1072  			if fb.currentBlock != nil {
1073  				fb.emit(&SSAJump{Comment: "goto.label." + ls.Label.Value})
1074  				push(fb.currentBlock.Succs, lblBlock)
1075  				push(lblBlock.Preds, fb.currentBlock)
1076  			}
1077  			fb.currentBlock = lblBlock
1078  		}
1079  		fb.buildStmt(ls.Stmt)
1080  		fb.pendingLabel = ""
1081  		return
1082  	}
1083  	if fb.currentBlock == nil {
1084  		return
1085  	}
1086  	switch ss := s.(type) {
1087  	case *syntax.EmptyStmt:
1088  		_ = ss
1089  		// nothing
1090  	case *syntax.ExprStmt:
1091  		fb.buildExpr(ss.X)
1092  	case *syntax.AssignStmt:
1093  		fb.buildAssign(ss)
1094  	case *syntax.BlockStmt:
1095  		fb.buildBlock(ss)
1096  	case *syntax.DeclStmt:
1097  		for _, d := range ss.DeclList {
1098  			fb.buildLocalDecl(d)
1099  		}
1100  	case *syntax.IfStmt:
1101  		fb.buildIf(ss)
1102  	case *syntax.ForStmt:
1103  		fb.buildFor(ss)
1104  	case *syntax.SwitchStmt:
1105  		fb.buildSwitch(ss)
1106  	case *syntax.SelectStmt:
1107  		fb.buildSelect(ss)
1108  	case *syntax.ReturnStmt:
1109  		fb.buildReturn(ss)
1110  	case *syntax.BranchStmt:
1111  		fb.buildBranch(ss)
1112  	case *syntax.SendStmt:
1113  		ch := fb.buildExpr(ss.Chan)
1114  		val := fb.buildExpr(ss.Value)
1115  		if ch != nil && val != nil {
1116  			fb.emit(&SSASend{Chan: ch, X: val})
1117  		}
1118  	case *syntax.CallStmt:
1119  		call, _ := ss.Call.(*syntax.CallExpr)
1120  		switch ss.Tok {
1121  		case token.Go:
1122  			if call != nil {
1123  				fb.buildGoStmt(call)
1124  			}
1125  		case token.Defer:
1126  			if call != nil {
1127  				fb.buildDeferStmt(call)
1128  			}
1129  		default:
1130  			fb.buildExpr(ss.Call)
1131  		}
1132  	}
1133  }
1134  
1135  func (fb *ssaFuncBuilder) buildAssign(s *syntax.AssignStmt) {
1136  	if s.Rhs == nil {
1137  		lv := fb.buildExpr(s.Lhs)
1138  		if lv == nil {
1139  			return
1140  		}
1141  		one := &SSAConst{typ: lv.SSAType(), val: &ConstInt{V:1}}
1142  		op := OpAdd
1143  		if s.Op == token.Sub {
1144  			op = OpSub
1145  		}
1146  		bin := &SSABinOp{Op: op, X: lv, Y: one}
1147  		bin.typ = lv.SSAType()
1148  		bin.name = fb.nextName()
1149  		fb.emit(bin)
1150  		fb.buildStore(s.Lhs, bin)
1151  		return
1152  	}
1153  	if s.Op == token.Def {
1154  		fb.buildShortVarDecl(s)
1155  		return
1156  	}
1157  	if s.Op != 0 {
1158  		lv := fb.buildExpr(s.Lhs)
1159  		rv := fb.buildExpr(s.Rhs)
1160  		if lv == nil || rv == nil {
1161  			return
1162  		}
1163  		op := compoundOp(s.Op)
1164  		bin := &SSABinOp{Op: op, X: lv, Y: rv}
1165  		bin.typ = lv.SSAType()
1166  		bin.name = fb.nextName()
1167  		fb.emit(bin)
1168  		fb.buildStore(s.Lhs, bin)
1169  		return
1170  	}
1171  	lhsList, lhsIsList := s.Lhs.(*syntax.ListExpr)
1172  	rhsList, rhsIsList := s.Rhs.(*syntax.ListExpr)
1173  	if lhsIsList && rhsIsList && len(lhsList.ElemList) == len(rhsList.ElemList) {
1174  		vals := []SSAValue{:len(rhsList.ElemList)}
1175  		for i, re := range rhsList.ElemList {
1176  			vals[i] = fb.buildExpr(re)
1177  		}
1178  		for i, le := range lhsList.ElemList {
1179  			if vals[i] != nil {
1180  				fb.buildStore(le, vals[i])
1181  			}
1182  		}
1183  		return
1184  	}
1185  	if lhsIsList && len(lhsList.ElemList) == 2 {
1186  		if ae, ok := s.Rhs.(*syntax.AssertExpr); ok {
1187  			x := fb.buildExpr(ae.X)
1188  			assertedType := fb.resolveType(ae.Type)
1189  			if x != nil && assertedType != nil {
1190  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1191  				ta.typ = NewTuple(
1192  					NewTCVar(nil, "val", assertedType),
1193  					NewTCVar(nil, "ok", Typ[Bool]),
1194  				)
1195  				ta.name = fb.nextName()
1196  				fb.emit(ta)
1197  				for i, le := range lhsList.ElemList {
1198  					if n, isName := le.(*syntax.Name); isName && n.Value == "_" {
1199  						continue
1200  					}
1201  					ext := &SSAExtract{Tuple: ta, Index: i}
1202  					ext.typ = ssaTupleElemType(ta.typ, i)
1203  					ext.name = fb.nextName()
1204  					fb.emit(ext)
1205  					fb.buildStore(le, ext)
1206  				}
1207  				return
1208  			}
1209  		}
1210  		if ie, ok := s.Rhs.(*syntax.IndexExpr); ok {
1211  			x := fb.buildExpr(ie.X)
1212  			idx := fb.buildExpr(ie.Index)
1213  			if x != nil && idx != nil {
1214  				if mt, ok2 := SafeUnderlying(x.SSAType()).(*TCMap); ok2 {
1215  					idx = fb.coerceToInterface(idx, mt.Key)
1216  					l := &SSALookup{X: x, Index: idx, CommaOk: true}
1217  					l.typ = NewTuple(
1218  						NewTCVar(nil, "v", mt.Elem),
1219  						NewTCVar(nil, "ok", Typ[Bool]),
1220  					)
1221  					l.name = fb.nextName()
1222  					fb.emit(l)
1223  					for i, le := range lhsList.ElemList {
1224  						if n, isName := le.(*syntax.Name); isName && n.Value == "_" {
1225  							continue
1226  						}
1227  						ext := &SSAExtract{Tuple: l, Index: i}
1228  						ext.typ = ssaTupleElemType(l.typ, i)
1229  						ext.name = fb.nextName()
1230  						fb.emit(ext)
1231  						fb.buildStore(le, ext)
1232  					}
1233  					return
1234  				}
1235  			}
1236  		}
1237  		if oe, ok := s.Rhs.(*syntax.Operation); ok && oe.Y == nil && oe.Op == token.Recv {
1238  			x := fb.buildExpr(oe.X)
1239  			if x != nil {
1240  				elemType := ssaChanElemType(x.SSAType())
1241  				u := &SSAUnOp{Op: OpArrow, X: x, CommaOk: true}
1242  				u.typ = NewTuple(
1243  					NewTCVar(nil, "v", elemType),
1244  					NewTCVar(nil, "ok", Typ[Bool]),
1245  				)
1246  				u.name = fb.nextName()
1247  				fb.emit(u)
1248  				for i, le := range lhsList.ElemList {
1249  					if n, isName := le.(*syntax.Name); isName && n.Value == "_" {
1250  						continue
1251  					}
1252  					ext := &SSAExtract{Tuple: u, Index: i}
1253  					ext.typ = ssaTupleElemType(u.typ, i)
1254  					ext.name = fb.nextName()
1255  					fb.emit(ext)
1256  					fb.buildStore(le, ext)
1257  				}
1258  				return
1259  			}
1260  		}
1261  	}
1262  	rhs := fb.buildExpr(s.Rhs)
1263  	if rhs == nil {
1264  		return
1265  	}
1266  	fb.buildStore(s.Lhs, rhs)
1267  }
1268  
1269  func (fb *ssaFuncBuilder) coerceToInterface(val SSAValue, targetType Type) (s SSAValue) {
1270  	if targetType == nil || val == nil || val.SSAType() == nil {
1271  		return val
1272  	}
1273  	if _, isIface := SafeUnderlying(targetType).(*TCInterface); isIface {
1274  		if _, alreadyIface := SafeUnderlying(val.SSAType()).(*TCInterface); !alreadyIface {
1275  			mi := &SSAMakeInterface{X: val}
1276  			mi.typ = targetType
1277  			mi.name = fb.nextName()
1278  			fb.emit(mi)
1279  			return mi
1280  		}
1281  	}
1282  	return val
1283  }
1284  
1285  func (fb *ssaFuncBuilder) buildStore(lhs syntax.Expr, val SSAValue) {
1286  	if lhs == nil {
1287  		panic("buildStore: nil lhs")
1288  	}
1289  	switch lv := lhs.(type) {
1290  	case *syntax.Name:
1291  		if lv == nil {
1292  			panic("buildStore: nil *syntax.Name after type switch")
1293  		}
1294  		if lv.Value == "_" {
1295  			return
1296  		}
1297  		obj := fb.lookupObject(lv.Value)
1298  		if obj == nil {
1299  			return
1300  		}
1301  		if alloc, ok2 := fb.vars[obj]; ok2 {
1302  			val = fb.coerceToInterface(val, ObjectType(obj))
1303  			fb.emitStore(alloc, val)
1304  		} else if fv, ok3 := fb.freeVarPtrs[lv.Value]; ok3 {
1305  			val = fb.coerceToInterface(val, ObjectType(obj))
1306  			fb.emitStore(fv, val)
1307  		} else if g2, ok4 := fb.fn.Pkg.Members[lv.Value].(*SSAGlobal); ok4 {
1308  			if p, ok5 := g2.SSAType().(*Pointer); ok5 && p.Base != nil {
1309  				val = fb.coerceToInterface(val, p.Base)
1310  			}
1311  			fb.emitStore(g2, val)
1312  		} else if v, ok6 := obj.(*TCVar); ok6 && v.Pkg != nil && v.Pkg != fb.fn.Pkg.Pkg {
1313  			// dot-imported global from another package
1314  			impPkg := fb.ensureImportedSSAPackage(v.Pkg)
1315  			g3, ok7 := impPkg.Members[lv.Value].(*SSAGlobal)
1316  			if !ok7 {
1317  				g3 = &SSAGlobal{
1318  					name: lv.Value,
1319  					typ:  NewPointer(v.Typ),
1320  					pkg:  impPkg,
1321  				}
1322  				impPkg.SetMember(lv.Value, g3)
1323  			}
1324  			if p, ok8 := g3.SSAType().(*Pointer); ok8 && p.Base != nil {
1325  				val = fb.coerceToInterface(val, p.Base)
1326  			}
1327  			fb.emitStore(g3, val)
1328  		}
1329  	case *syntax.Operation:
1330  		if lv.Y == nil && lv.Op == token.Mul {
1331  			ptr := fb.buildExpr(lv.X)
1332  			if ptr != nil {
1333  				if p, ok2 := ptr.SSAType().(*Pointer); ok2 && p.Base != nil {
1334  					val = fb.coerceToInterface(val, p.Base)
1335  				}
1336  				fb.emitStore(ptr, val)
1337  			}
1338  		}
1339  	case *syntax.SelectorExpr:
1340  		addr := fb.buildSelectorAddr(lv)
1341  		if addr == nil {
1342  			return
1343  		}
1344  		if p, ok2 := addr.SSAType().(*Pointer); ok2 && p.Base != nil {
1345  			val = fb.coerceToInterface(val, p.Base)
1346  		}
1347  		fb.emitStore(addr, val)
1348  	case *syntax.IndexExpr:
1349  		base := fb.buildExpr(lv.X)
1350  		idx := fb.buildExpr(lv.Index)
1351  		if base == nil || idx == nil {
1352  			return
1353  		}
1354  		if m, isMap := SafeUnderlying(base.SSAType()).(*TCMap); isMap {
1355  			idx = fb.coerceToInterface(idx, m.Key)
1356  			val = fb.coerceToInterface(val, m.Elem)
1357  			fb.emit(&SSAMapUpdate{Map: base, Key: idx, Value: val})
1358  			return
1359  		}
1360  		// For array LHS assignment, resolve the address of the base directly
1361  		// so SSAIndexAddr GEPs into the original, not a stack copy.
1362  		var baseAddr SSAValue
1363  		if n, ok := lv.X.(*syntax.Name); ok {
1364  			obj := fb.lookupObject(n.Value)
1365  			if obj != nil {
1366  				if alloc, ok2 := fb.vars[obj]; ok2 {
1367  					baseAddr = alloc
1368  				} else if g4, ok10 := fb.fn.Pkg.Members[n.Value].(*SSAGlobal); ok10 {
1369  					baseAddr = g4
1370  				}
1371  			}
1372  		} else if sel, ok11 := lv.X.(*syntax.SelectorExpr); ok11 {
1373  			baseAddr = fb.buildSelectorAddr(sel)
1374  		}
1375  		if baseAddr != nil {
1376  			if _, isArr := SafeUnderlying(base.SSAType()).(*Array); isArr {
1377  				ia2 := &SSAIndexAddr{X: baseAddr, Index: idx}
1378  				ia2.typ = NewPointer(ssaElemType(base.SSAType()))
1379  				ia2.name = fb.nextName()
1380  				fb.emit(ia2)
1381  				if p, ok9 := ia2.SSAType().(*Pointer); ok9 && p.Base != nil {
1382  					val = fb.coerceToInterface(val, p.Base)
1383  				}
1384  				fb.emitStore(ia2, val)
1385  				return
1386  			}
1387  		}
1388  		ia := &SSAIndexAddr{X: base, Index: idx}
1389  		ia.typ = NewPointer(ssaElemType(base.SSAType()))
1390  		ia.name = fb.nextName()
1391  		fb.emit(ia)
1392  		if p, ok2 := ia.SSAType().(*Pointer); ok2 && p.Base != nil {
1393  			val = fb.coerceToInterface(val, p.Base)
1394  		}
1395  		fb.emitStore(ia, val)
1396  	case *syntax.ListExpr:
1397  		for i, e := range lv.ElemList {
1398  			ext := &SSAExtract{Tuple: val, Index: i}
1399  			ext.typ = ssaTupleElemType(val.SSAType(), i)
1400  			ext.name = fb.nextName()
1401  			fb.emit(ext)
1402  			fb.buildStore(e, ext)
1403  		}
1404  	}
1405  }
1406  
1407  func (fb *ssaFuncBuilder) buildShortVarDecl(s *syntax.AssignStmt) {
1408  	names := ssaExprNames(s.Lhs)
1409  	if len(names) == 2 {
1410  		if ae, ok := s.Rhs.(*syntax.AssertExpr); ok {
1411  			x := fb.buildExpr(ae.X)
1412  			assertedType := fb.resolveType(ae.Type)
1413  			if assertedType != nil {
1414  				if x == nil {
1415  					x = &SSAConst{typ: NewTCInterface(nil, nil)}
1416  				}
1417  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1418  				ta.typ = NewTuple(
1419  					NewTCVar(nil, "val", assertedType),
1420  					NewTCVar(nil, "ok", Typ[Bool]),
1421  				)
1422  				ta.name = fb.nextName()
1423  				fb.emit(ta)
1424  				for i, name := range names {
1425  					if name.Value == "_" {
1426  						continue
1427  					}
1428  					ext := &SSAExtract{Tuple: ta, Index: i}
1429  					ext.typ = ssaTupleElemType(ta.typ, i)
1430  					ext.name = fb.nextName()
1431  					fb.emit(ext)
1432  					fb.removeVar(name.Value)
1433  					obj := NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1434  					alloc := fb.emitAlloc(ext.typ, 0)
1435  					fb.vars[obj] = alloc
1436  					fb.emitStore(alloc, ext)
1437  				}
1438  				return
1439  			}
1440  		}
1441  		if ie, ok := s.Rhs.(*syntax.IndexExpr); ok {
1442  			x := fb.buildExpr(ie.X)
1443  			idx := fb.buildExpr(ie.Index)
1444  			if x != nil && idx != nil {
1445  				if mt, ok2 := SafeUnderlying(x.SSAType()).(*TCMap); ok2 {
1446  					idx = fb.coerceToInterface(idx, mt.Key)
1447  					l := &SSALookup{X: x, Index: idx, CommaOk: true}
1448  					l.typ = NewTuple(
1449  						NewTCVar(nil, "v", mt.Elem),
1450  						NewTCVar(nil, "ok", Typ[Bool]),
1451  					)
1452  					l.name = fb.nextName()
1453  					fb.emit(l)
1454  					for i, name := range names {
1455  						if name.Value == "_" {
1456  							continue
1457  						}
1458  						ext := &SSAExtract{Tuple: l, Index: i}
1459  						ext.typ = ssaTupleElemType(l.typ, i)
1460  						ext.name = fb.nextName()
1461  						fb.emit(ext)
1462  						fb.removeVar(name.Value)
1463  						var obj Object
1464  						if fb.info != nil {
1465  							obj = fb.info.Defs[name]
1466  						}
1467  						if obj == nil {
1468  							obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1469  						}
1470  						alloc := fb.emitAlloc(ext.typ, 0)
1471  						fb.vars[obj] = alloc
1472  						fb.emitStore(alloc, ext)
1473  					}
1474  					return
1475  				}
1476  			}
1477  		}
1478  		if oe, ok := s.Rhs.(*syntax.Operation); ok && oe.Y == nil && oe.Op == token.Recv {
1479  			x := fb.buildExpr(oe.X)
1480  			if x != nil {
1481  				elemType := ssaChanElemType(x.SSAType())
1482  				u := &SSAUnOp{Op: OpArrow, X: x, CommaOk: true}
1483  				u.typ = NewTuple(
1484  					NewTCVar(nil, "v", elemType),
1485  					NewTCVar(nil, "ok", Typ[Bool]),
1486  				)
1487  				u.name = fb.nextName()
1488  				fb.emit(u)
1489  				for i, name := range names {
1490  					if name.Value == "_" {
1491  						continue
1492  					}
1493  					ext := &SSAExtract{Tuple: u, Index: i}
1494  					ext.typ = ssaTupleElemType(u.typ, i)
1495  					ext.name = fb.nextName()
1496  					fb.emit(ext)
1497  					fb.removeVar(name.Value)
1498  					var obj Object
1499  					if fb.info != nil {
1500  						obj = fb.info.Defs[name]
1501  					}
1502  					if obj == nil {
1503  						obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1504  					}
1505  					alloc := fb.emitAlloc(ext.typ, 0)
1506  					fb.vars[obj] = alloc
1507  					fb.emitStore(alloc, ext)
1508  				}
1509  				return
1510  			}
1511  		}
1512  	}
1513  	if rhsList, ok := s.Rhs.(*syntax.ListExpr); ok && len(rhsList.ElemList) == len(names) {
1514  		vals := []SSAValue{:len(rhsList.ElemList)}
1515  		for i, re := range rhsList.ElemList {
1516  			vals[i] = fb.buildExpr(re)
1517  		}
1518  		for i, name := range names {
1519  			if name.Value == "_" {
1520  				continue
1521  			}
1522  			var typ Type
1523  			if vals[i] != nil {
1524  				typ = vals[i].SSAType()
1525  			}
1526  			fb.removeVar(name.Value)
1527  			var obj Object
1528  			if fb.info != nil {
1529  				obj = fb.info.Defs[name]
1530  			}
1531  			if obj == nil {
1532  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1533  			}
1534  			alloc := fb.emitAlloc(typ, 0)
1535  			fb.vars[obj] = alloc
1536  			if vals[i] != nil {
1537  				fb.emitStore(alloc, vals[i])
1538  			}
1539  		}
1540  		return
1541  	}
1542  
1543  	rhs := fb.buildExpr(s.Rhs)
1544  
1545  	isTuple := false
1546  	var tup *Tuple
1547  	if rhs != nil {
1548  		tup, isTuple = rhs.SSAType().(*Tuple)
1549  	}
1550  	for i, name := range names {
1551  		if name.Value == "_" {
1552  			continue
1553  		}
1554  		var typ Type
1555  		if rhs != nil {
1556  			if isTuple && i < tup.Len() {
1557  				typ = tup.At(i).Typ
1558  			} else if i == 0 {
1559  				typ = rhs.SSAType()
1560  			}
1561  		}
1562  		if typ == nil {
1563  			rhsInfo := "nil"
1564  			if rhs != nil {
1565  				if rhs.SSAType() == nil {
1566  					rhsInfo = "ssatype=nil"
1567  				} else if tup2, ok2 := rhs.SSAType().(*Tuple); ok2 {
1568  					rhsInfo = "tuple[" | token.Itoa(tup2.Len()) | "] i=" | token.Itoa(i)
1569  					if i < tup2.Len() {
1570  						if tup2.At(i).Typ == nil {
1571  							rhsInfo = rhsInfo | " At.Type=nil"
1572  						} else {
1573  							rhsInfo = rhsInfo | " At.Type=set"
1574  						}
1575  					}
1576  				} else {
1577  					rhsInfo = "non-tuple"
1578  				}
1579  			}
1580  			typ = Typ[Int32]
1581  		}
1582  		fb.removeVar(name.Value)
1583  		var obj Object
1584  		if fb.info != nil {
1585  			obj = fb.info.Defs[name]
1586  		}
1587  		if obj == nil {
1588  			obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1589  		}
1590  		alloc := fb.emitAlloc(typ, 0)
1591  		fb.vars[obj] = alloc
1592  		var initVal SSAValue
1593  		if rhs != nil {
1594  			if isTuple {
1595  				ext := &SSAExtract{Tuple: rhs, Index: i}
1596  				ext.typ = typ
1597  				ext.name = fb.nextName()
1598  				fb.emit(ext)
1599  				initVal = ext
1600  			} else if i == 0 {
1601  				initVal = rhs
1602  			}
1603  		}
1604  		if initVal != nil {
1605  			fb.emitStore(alloc, initVal)
1606  		}
1607  	}
1608  }
1609  
1610  func (fb *ssaFuncBuilder) buildLocalDecl(d syntax.Decl) {
1611  	switch dd := d.(type) {
1612  	case *syntax.VarDecl:
1613  		var typ Type
1614  		if fb.info != nil && len(dd.NameList) > 0 {
1615  			if obj := fb.info.Defs[dd.NameList[0]]; obj != nil {
1616  				typ = ObjectType(obj)
1617  			}
1618  		}
1619  		if typ == nil && dd.Type != nil {
1620  			typ = fb.resolveType(dd.Type)
1621  		}
1622  		initVal := fb.buildExpr(dd.Values)
1623  		for _, name := range dd.NameList {
1624  			if name.Value == "_" {
1625  				continue
1626  			}
1627  			fb.removeVar(name.Value)
1628  			var obj Object
1629  			if fb.info != nil {
1630  				obj = fb.info.Defs[name]
1631  			}
1632  			if obj == nil {
1633  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1634  			}
1635  			alloc := fb.emitAlloc(ObjectType(obj), 0)
1636  			fb.vars[obj] = alloc
1637  			push(fb.fn.Locals, alloc)
1638  			if initVal != nil {
1639  				initVal = fb.coerceToInterface(initVal, ObjectType(obj))
1640  				fb.emitStore(alloc, initVal)
1641  			} else {
1642  				fb.emitStore(alloc, &SSAConst{typ: ObjectType(obj), val: nil})
1643  			}
1644  		}
1645  	case *syntax.ConstDecl:
1646  		if dd.Values != nil && len(dd.NameList) > 0 {
1647  			if fb.localConsts == nil {
1648  				fb.localConsts = map[string]*SSAConst{}
1649  			}
1650  			if list, ok := dd.Values.(*syntax.ListExpr); ok {
1651  				for i, name := range dd.NameList {
1652  					if i < len(list.ElemList) {
1653  						if v := fb.buildExpr(list.ElemList[i]); v != nil {
1654  							if c := ssaExtractConst(v); c != nil {
1655  								fb.localConsts[name.Value] = c
1656  							}
1657  						}
1658  					}
1659  				}
1660  			} else if len(dd.NameList) == 1 {
1661  				if v := fb.buildExpr(dd.Values); v != nil {
1662  					if c := ssaExtractConst(v); c != nil {
1663  						fb.localConsts[dd.NameList[0].Value] = c
1664  					}
1665  				}
1666  			}
1667  		}
1668  	case *syntax.TypeDecl:
1669  		if dd.Name != nil {
1670  			resolved := fb.resolveTypeAST(dd.Type)
1671  			if resolved != nil {
1672  				fb.localTypes[dd.Name.Value] = resolved
1673  			}
1674  		}
1675  	}
1676  }
1677  
1678  func (fb *ssaFuncBuilder) evalLocalConstExpr(e syntax.Expr) (c ConstVal) {
1679  	if e == nil {
1680  		return nil
1681  	}
1682  	switch ev := e.(type) {
1683  	case *syntax.BasicLit:
1684  		return EvalBasicLitLocal(ev)
1685  	case *syntax.Name:
1686  		if lc, ok := fb.localConsts[ev.Value]; ok && lc != nil && lc.val != nil {
1687  			return lc.val
1688  		}
1689  		return tcEvalConstExpr(ev, fb.fn.Pkg.Pkg.Scope, -1)
1690  	case *syntax.Operation:
1691  		if ev.Y == nil {
1692  			xr2 := fb.evalLocalConstExpr(ev.X)
1693  			if xr2 == nil {
1694  				return nil
1695  			}
1696  			return EvalUnaryLocal(ev.Op, xr2)
1697  		}
1698  		xr := fb.evalLocalConstExpr(ev.X)
1699  		yr := fb.evalLocalConstExpr(ev.Y)
1700  		if xr == nil || yr == nil {
1701  			return nil
1702  		}
1703  		return EvalBinaryLocal(ev.Op, xr, yr)
1704  	case *syntax.ParenExpr:
1705  		return fb.evalLocalConstExpr(ev.X)
1706  	}
1707  	return nil
1708  }
1709  
1710  func (fb *ssaFuncBuilder) buildIf(s *syntax.IfStmt) {
1711  	var savedVars map[Object]*SSAAlloc
1712  	if s.Init != nil {
1713  		savedVars = fb.saveVars()
1714  		fb.buildStmt(s.Init)
1715  	}
1716  	if fb.currentBlock == nil {
1717  		if savedVars != nil {
1718  			fb.vars = savedVars
1719  		}
1720  		return
1721  	}
1722  	cond := fb.buildExpr(s.Cond)
1723  	if cond == nil {
1724  		if savedVars != nil {
1725  			fb.vars = savedVars
1726  		}
1727  		return
1728  	}
1729  
1730  	thenBlock := fb.newBlock("if.then")
1731  	var elseBlock *SSABasicBlock
1732  	doneBlock := fb.newBlock("if.done")
1733  
1734  	if s.Else != nil {
1735  		elseBlock = fb.newBlock("if.else")
1736  	} else {
1737  		elseBlock = doneBlock
1738  	}
1739  
1740  	fb.emit(&SSAIf{Cond: cond})
1741  	push(fb.currentBlock.Succs, thenBlock, elseBlock)
1742  	push(thenBlock.Preds, fb.currentBlock)
1743  	push(elseBlock.Preds, fb.currentBlock)
1744  
1745  	oldThen := fb.enterScope()
1746  	thenBlock.ScopeID = fb.scopeID
1747  	fb.currentBlock = thenBlock
1748  	fb.buildBlock(s.Then)
1749  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1750  		fb.emit(&SSAJump{Comment: "if.done"})
1751  		push(fb.currentBlock.Succs, doneBlock)
1752  		push(doneBlock.Preds, fb.currentBlock)
1753  	}
1754  	fb.exitScope(oldThen)
1755  
1756  	if s.Else != nil {
1757  		oldElse := fb.enterScope()
1758  		elseBlock.ScopeID = fb.scopeID
1759  		fb.currentBlock = elseBlock
1760  		fb.buildStmt(s.Else)
1761  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1762  			fb.emit(&SSAJump{Comment: "if.done"})
1763  			push(fb.currentBlock.Succs, doneBlock)
1764  			push(doneBlock.Preds, fb.currentBlock)
1765  		}
1766  		fb.exitScope(oldElse)
1767  	}
1768  
1769  	fb.currentBlock = doneBlock
1770  	if savedVars != nil {
1771  		fb.vars = savedVars
1772  	}
1773  }
1774  
1775  func (fb *ssaFuncBuilder) buildFor(s *syntax.ForStmt) {
1776  	var savedVars map[Object]*SSAAlloc
1777  	if s.Init != nil {
1778  		if rc, ok := s.Init.(*syntax.RangeClause); ok {
1779  			fb.buildRangeLoop(s, rc)
1780  			return
1781  		}
1782  		savedVars = fb.saveVars()
1783  		fb.buildStmt(s.Init)
1784  	}
1785  
1786  	condBlock := fb.newBlock("for.cond")
1787  	bodyBlock := fb.newBlock("for.body")
1788  	postBlock := fb.newBlock("for.post")
1789  	doneBlock := fb.newBlock("for.done")
1790  
1791  	fb.emit(&SSAJump{Comment: "for.cond"})
1792  	push(fb.currentBlock.Succs, condBlock)
1793  	push(condBlock.Preds, fb.currentBlock)
1794  
1795  	push(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: postBlock, done: doneBlock})
1796  	fb.pendingLabel = ""
1797  
1798  	fb.currentBlock = condBlock
1799  	if s.Cond != nil {
1800  		cond := fb.buildExpr(s.Cond)
1801  		if cond != nil {
1802  			fb.emit(&SSAIf{Cond: cond})
1803  			push(fb.currentBlock.Succs, bodyBlock, doneBlock)
1804  			push(bodyBlock.Preds, condBlock)
1805  			push(doneBlock.Preds, condBlock)
1806  		}
1807  	} else {
1808  		fb.emit(&SSAJump{Comment: "for.body"})
1809  		push(fb.currentBlock.Succs, bodyBlock)
1810  		push(bodyBlock.Preds, condBlock)
1811  	}
1812  
1813  	forScope := fb.enterScope()
1814  	bodyBlock.ScopeID = fb.scopeID
1815  	fb.currentBlock = bodyBlock
1816  	fb.buildBlock(s.Body)
1817  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1818  		fb.emit(&SSAJump{Comment: "for.post"})
1819  		push(fb.currentBlock.Succs, postBlock)
1820  		push(postBlock.Preds, fb.currentBlock)
1821  	}
1822  
1823  	postBlock.ScopeID = fb.scopeID
1824  	fb.currentBlock = postBlock
1825  	if s.Post != nil {
1826  		fb.buildStmt(s.Post)
1827  	}
1828  	if fb.currentBlock != nil {
1829  		fb.emit(&SSAJump{Comment: "for.cond"})
1830  		push(fb.currentBlock.Succs, condBlock)
1831  		push(condBlock.Preds, fb.currentBlock)
1832  	}
1833  	fb.exitScope(forScope)
1834  
1835  	fb.loops = fb.loops[:len(fb.loops)-1]
1836  	fb.currentBlock = doneBlock
1837  	if savedVars != nil {
1838  		fb.vars = savedVars
1839  	}
1840  }
1841  
1842  func (fb *ssaFuncBuilder) buildRangeLoop(s *syntax.ForStmt, rc *syntax.RangeClause) {
1843  	savedVars := fb.saveVars()
1844  	iterExpr := fb.buildExpr(rc.X)
1845  	if iterExpr == nil {
1846  		return
1847  	}
1848  
1849  	r := &SSARange{X: iterExpr}
1850  	r.typ = Typ[Invalid]
1851  	r.name = fb.nextName()
1852  	fb.emit(r)
1853  
1854  	bodyBlock := fb.newBlock("range.body")
1855  	doneBlock := fb.newBlock("range.done")
1856  
1857  	condBlock := fb.newBlock("range.cond")
1858  
1859  	push(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: condBlock, done: doneBlock})
1860  	fb.pendingLabel = ""
1861  	fb.emit(&SSAJump{Comment: "range.cond"})
1862  	push(fb.currentBlock.Succs, condBlock)
1863  	push(condBlock.Preds, fb.currentBlock)
1864  
1865  	fb.currentBlock = condBlock
1866  	iterSSAType := iterExpr.SSAType()
1867  	if iterSSAType == nil {
1868  		switch x := rc.X.(type) {
1869  		case *syntax.SelectorExpr:
1870  			if x != nil {
1871  				tv := x.GetTypeInfo()
1872  				if tv.Type != nil {
1873  					if t, ok := tv.Type.(Type); ok { iterSSAType = t }
1874  				}
1875  			}
1876  		case *syntax.Name:
1877  			if x != nil {
1878  				tv := x.GetTypeInfo()
1879  				if tv.Type != nil {
1880  					if t, ok := tv.Type.(Type); ok { iterSSAType = t }
1881  				}
1882  			}
1883  		}
1884  		if iterSSAType == nil {
1885  			mxutil.WriteStr(2, "WARN: unresolved range type in " | fb.fn.Pkg.Pkg.Path | "." | fb.fn.name | "\n")
1886  			return
1887  		}
1888  	}
1889  	nxt := &SSANext{Iter: r, IsString: ssaIsStringType(iterSSAType)}
1890  	keyTyp := asType(Typ[Int32])
1891  	valTyp := asType(Typ[Invalid])
1892  	iterT := iterSSAType
1893  	iterU := SafeUnderlying(iterT)
1894  	if sl, ok := iterU.(*Slice); ok {
1895  		valTyp = sl.Elem
1896  	} else if sl2, ok12 := iterT.(*Slice); ok12 {
1897  		valTyp = sl2.Elem
1898  	} else if mt2, ok13 := iterU.(*TCMap); ok13 {
1899  		keyTyp = mt2.Key
1900  		valTyp = mt2.Elem
1901  	} else if mt3, ok14 := iterT.(*TCMap); ok14 {
1902  		keyTyp = mt3.Key
1903  		valTyp = mt3.Elem
1904  	} else if ar2, ok15 := iterU.(*Array); ok15 {
1905  		valTyp = ar2.Elem
1906  	} else if ar3, ok16 := iterT.(*Array); ok16 {
1907  		valTyp = ar3.Elem
1908  	} else if p, ok17 := iterU.(*Pointer); ok17 && p.Base != nil {
1909  		if ar4, ok18 := SafeUnderlying(p.Base).(*Array); ok18 {
1910  			valTyp = ar4.Elem
1911  		}
1912  	}
1913  	if valTyp == asType(Typ[Invalid]) && ssaIsStringType(iterSSAType) {
1914  		valTyp = asType(Typ[Uint8])
1915  	}
1916  	nxt.typ = NewTuple(
1917  		NewTCVar(nil, "ok", Typ[Bool]),
1918  		NewTCVar(nil, "k", keyTyp),
1919  		NewTCVar(nil, "v", valTyp),
1920  	)
1921  	nxt.name = fb.nextName()
1922  	fb.emit(nxt)
1923  
1924  	okExt := &SSAExtract{Tuple: nxt, Index: 0}
1925  	okExt.typ = Typ[Bool]
1926  	okExt.name = fb.nextName()
1927  	fb.emit(okExt)
1928  
1929  	fb.emit(&SSAIf{Cond: okExt})
1930  	push(fb.currentBlock.Succs, bodyBlock, doneBlock)
1931  	push(bodyBlock.Preds, condBlock)
1932  	push(doneBlock.Preds, condBlock)
1933  
1934  	rangeScope := fb.enterScope()
1935  	bodyBlock.ScopeID = fb.scopeID
1936  	fb.currentBlock = bodyBlock
1937  	if rc.Lhs != nil && rc.Def {
1938  		names := ssaExprNames(rc.Lhs)
1939  		for i, name := range names {
1940  			if name.Value == "_" {
1941  				continue
1942  			}
1943  			ext := &SSAExtract{Tuple: nxt, Index: i + 1}
1944  			ext.typ = ssaTupleElemType(nxt.typ, i+1)
1945  			ext.name = fb.nextName()
1946  			fb.emit(ext)
1947  			var obj Object
1948  			if fb.info != nil {
1949  				obj = fb.info.Defs[name]
1950  			}
1951  			if obj == nil {
1952  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1953  			}
1954  			fb.removeVar(name.Value)
1955  			alloc := fb.emitAlloc(ext.typ, 0)
1956  			fb.vars[obj] = alloc
1957  			fb.emitStore(alloc, ext)
1958  		}
1959  	} else if rc.Lhs != nil && !rc.Def {
1960  		names := ssaExprNames(rc.Lhs)
1961  		for i, name := range names {
1962  			if name.Value == "_" {
1963  				continue
1964  			}
1965  			ext := &SSAExtract{Tuple: nxt, Index: i + 1}
1966  			ext.typ = ssaTupleElemType(nxt.typ, i+1)
1967  			ext.name = fb.nextName()
1968  			fb.emit(ext)
1969  			fb.buildStore(name, ext)
1970  		}
1971  	}
1972  	fb.buildBlock(s.Body)
1973  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1974  		fb.emit(&SSAJump{Comment: "range.cond"})
1975  		push(fb.currentBlock.Succs, condBlock)
1976  		push(condBlock.Preds, fb.currentBlock)
1977  	}
1978  	fb.exitScope(rangeScope)
1979  
1980  	fb.loops = fb.loops[:len(fb.loops)-1]
1981  	fb.currentBlock = doneBlock
1982  	fb.vars = savedVars
1983  }
1984  
1985  func (fb *ssaFuncBuilder) buildSwitch(s *syntax.SwitchStmt) {
1986  	var savedVars map[Object]*SSAAlloc
1987  	if s.Init != nil {
1988  		savedVars = fb.saveVars()
1989  		fb.buildStmt(s.Init)
1990  	}
1991  	if fb.currentBlock == nil {
1992  		if savedVars != nil {
1993  			fb.vars = savedVars
1994  		}
1995  		return
1996  	}
1997  
1998  	doneBlock := fb.newBlock("switch.done")
1999  	savedLoops := fb.loops
2000  	push(fb.loops, ssaLoopState{label: fb.pendingLabel, done: doneBlock})
2001  	fb.pendingLabel = ""
2002  
2003  	if s.Tag != nil {
2004  		if tsg, ok := s.Tag.(*syntax.TypeSwitchGuard); ok {
2005  			fb.buildTypeSwitch(s, tsg, doneBlock)
2006  			fb.loops = savedLoops
2007  			fb.currentBlock = doneBlock
2008  			if savedVars != nil {
2009  				fb.vars = savedVars
2010  			}
2011  			return
2012  		}
2013  	}
2014  
2015  	var tag SSAValue
2016  	if s.Tag != nil {
2017  		tag = fb.buildExpr(s.Tag)
2018  	}
2019  
2020  	for _, clause := range s.Body {
2021  		caseBlock := fb.newBlock("switch.case")
2022  		nextBlock := fb.newBlock("switch.next")
2023  
2024  		if clause.Cases != nil && tag != nil {
2025  			var cond SSAValue
2026  			caseExprs := []syntax.Expr{clause.Cases}
2027  			if list, ok := clause.Cases.(*syntax.ListExpr); ok {
2028  				caseExprs = list.ElemList
2029  			}
2030  			for _, ce := range caseExprs {
2031  				caseVal := fb.buildExpr(ce)
2032  				// Fold constant string comparisons at SSA build time.
2033  				if tc, ok1 := tag.(*SSAConst); ok1 {
2034  					if cc, ok2 := caseVal.(*SSAConst); ok2 {
2035  						eq := ssaConstEqual(tc, cc)
2036  						boolConst := &SSAConst{typ: Typ[Bool], val: &ConstBool{V: eq}}
2037  						if cond == nil {
2038  							cond = boolConst
2039  						} else {
2040  							// OR with previous: true || x = true, false || x = x
2041  							if pc, ok3 := cond.(*SSAConst); ok3 {
2042  								if pb, ok4 := pc.val.(*ConstBool); ok4 {
2043  									if pb.V {
2044  										cond = pc // already true
2045  									} else {
2046  										cond = boolConst
2047  									}
2048  								} else {
2049  									cond = boolConst
2050  								}
2051  							} else {
2052  								orOp := &SSABinOp{Op: OpLor, X: cond, Y: boolConst}
2053  								orOp.typ = Typ[Bool]
2054  								orOp.name = fb.nextName()
2055  								fb.emit(orOp)
2056  								cond = orOp
2057  							}
2058  						}
2059  						continue
2060  					}
2061  				}
2062  				cmp := &SSABinOp{Op: OpEql, X: tag, Y: caseVal}
2063  				cmp.typ = Typ[Bool]
2064  				cmp.name = fb.nextName()
2065  				fb.emit(cmp)
2066  				if cond == nil {
2067  					cond = cmp
2068  				} else {
2069  					orOp := &SSABinOp{Op: OpLor, X: cond, Y: cmp}
2070  					orOp.typ = Typ[Bool]
2071  					orOp.name = fb.nextName()
2072  					fb.emit(orOp)
2073  					cond = orOp
2074  				}
2075  			}
2076  			// If cond folded to a constant, emit unconditional branch.
2077  			if cc, ok := cond.(*SSAConst); ok {
2078  				if cb, ok2 := cc.val.(*ConstBool); ok2 {
2079  					if cb.V {
2080  						fb.emit(&SSAJump{Comment: "switch.const.true"})
2081  						push(fb.currentBlock.Succs, caseBlock)
2082  						push(caseBlock.Preds, fb.currentBlock)
2083  					} else {
2084  						fb.emit(&SSAJump{Comment: "switch.const.false"})
2085  						push(fb.currentBlock.Succs, nextBlock)
2086  						push(nextBlock.Preds, fb.currentBlock)
2087  					}
2088  				} else {
2089  					fb.emit(&SSAIf{Cond: cond})
2090  					push(fb.currentBlock.Succs, caseBlock, nextBlock)
2091  					push(caseBlock.Preds, fb.currentBlock)
2092  					push(nextBlock.Preds, fb.currentBlock)
2093  				}
2094  			} else {
2095  				fb.emit(&SSAIf{Cond: cond})
2096  				push(fb.currentBlock.Succs, caseBlock, nextBlock)
2097  				push(caseBlock.Preds, fb.currentBlock)
2098  				push(nextBlock.Preds, fb.currentBlock)
2099  			}
2100  		} else if clause.Cases != nil && tag == nil {
2101  			// Tagless switch: comma-separated cases are OR'd.
2102  			caseExprs := []syntax.Expr{clause.Cases}
2103  			if list, ok := clause.Cases.(*syntax.ListExpr); ok {
2104  				caseExprs = list.ElemList
2105  			}
2106  			var cond SSAValue
2107  			for _, ce := range caseExprs {
2108  				cv := fb.buildExpr(ce)
2109  				if cond == nil {
2110  					cond = cv
2111  				} else {
2112  					orOp := &SSABinOp{Op: OpLor, X: cond, Y: cv}
2113  					orOp.typ = Typ[Bool]
2114  					orOp.name = fb.nextName()
2115  					fb.emit(orOp)
2116  					cond = orOp
2117  				}
2118  			}
2119  			fb.emit(&SSAIf{Cond: cond})
2120  			push(fb.currentBlock.Succs, caseBlock, nextBlock)
2121  			push(caseBlock.Preds, fb.currentBlock)
2122  			push(nextBlock.Preds, fb.currentBlock)
2123  		} else {
2124  			fb.emit(&SSAJump{Comment: "switch.case"})
2125  			push(fb.currentBlock.Succs, caseBlock)
2126  			push(caseBlock.Preds, fb.currentBlock)
2127  		}
2128  
2129  		caseScope := fb.enterScope()
2130  		caseBlock.ScopeID = fb.scopeID
2131  		fb.currentBlock = caseBlock
2132  		caseSaved := fb.saveVars()
2133  		for _, stmt := range clause.Body {
2134  			fb.buildStmt(stmt)
2135  			if fb.currentBlock == nil {
2136  				break
2137  			}
2138  		}
2139  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
2140  			fb.emit(&SSAJump{Comment: "switch.done"})
2141  			push(fb.currentBlock.Succs, doneBlock)
2142  			push(doneBlock.Preds, fb.currentBlock)
2143  		}
2144  		fb.exitScope(caseScope)
2145  		fb.vars = caseSaved
2146  		fb.currentBlock = nextBlock
2147  	}
2148  
2149  	if fb.currentBlock != nil {
2150  		fb.emit(&SSAJump{Comment: "switch.done"})
2151  		push(fb.currentBlock.Succs, doneBlock)
2152  		push(doneBlock.Preds, fb.currentBlock)
2153  	}
2154  
2155  	fb.loops = savedLoops
2156  	fb.currentBlock = doneBlock
2157  	if savedVars != nil {
2158  		fb.vars = savedVars
2159  	}
2160  }
2161  
2162  func (fb *ssaFuncBuilder) buildTypeSwitch(s *syntax.SwitchStmt, tsg *syntax.TypeSwitchGuard, doneBlock *SSABasicBlock) {
2163  	x := fb.buildExpr(tsg.X)
2164  	var savedObj Object
2165  	var savedAlloc *SSAAlloc
2166  	if tsg.Lhs != nil {
2167  		for obj, alloc := range fb.vars {
2168  			if ObjectName(obj) == tsg.Lhs.Value {
2169  				savedObj = obj
2170  				savedAlloc = alloc
2171  				break
2172  			}
2173  		}
2174  	}
2175  	for _, clause := range s.Body {
2176  		caseBlock := fb.newBlock("typeswitch.case")
2177  		nextBlock := fb.newBlock("typeswitch.next")
2178  
2179  		if clause.Cases != nil {
2180  			caseExprs := []syntax.Expr{clause.Cases}
2181  			if list, ok := clause.Cases.(*syntax.ListExpr); ok {
2182  				caseExprs = list.ElemList
2183  			}
2184  
2185  			var cond SSAValue
2186  			var firstTA *SSATypeAssert
2187  			var firstType Type
2188  			for _, ce := range caseExprs {
2189  				if n, isName := ce.(*syntax.Name); isName && n.Value == "nil" {
2190  					nilType := x.SSAType()
2191  					if nilType == nil {
2192  						nilType = NewTCInterface(nil, nil)
2193  					}
2194  					nilCheck := &SSABinOp{Op: OpEql, X: x, Y: &SSAConst{typ: nilType, val: nil}}
2195  					nilCheck.typ = Typ[Bool]
2196  					nilCheck.name = fb.nextName()
2197  					fb.emit(nilCheck)
2198  					if cond == nil {
2199  						cond = nilCheck
2200  					} else {
2201  						orOp := &SSABinOp{Op: OpLor, X: cond, Y: nilCheck}
2202  						orOp.typ = Typ[Bool]
2203  						orOp.name = fb.nextName()
2204  						fb.emit(orOp)
2205  						cond = orOp
2206  					}
2207  					continue
2208  				}
2209  				var assertedType Type
2210  				if fb.info != nil {
2211  					tv := fb.info.Types[ce]
2212  					assertedType = tv.Type
2213  				}
2214  				if assertedType == nil {
2215  					assertedType = fb.resolveType(ce)
2216  				}
2217  				if assertedType == nil {
2218  					assertedType = Typ[Invalid]
2219  				}
2220  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
2221  				ta.typ = NewTuple(
2222  					NewTCVar(nil, "val", assertedType),
2223  					NewTCVar(nil, "ok", Typ[Bool]),
2224  				)
2225  				ta.name = fb.nextName()
2226  				fb.emit(ta)
2227  				okExt := &SSAExtract{Tuple: ta, Index: 1}
2228  				okExt.typ = Typ[Bool]
2229  				okExt.name = fb.nextName()
2230  				fb.emit(okExt)
2231  				if firstTA == nil {
2232  					firstTA = ta
2233  					firstType = assertedType
2234  				}
2235  				if cond == nil {
2236  					cond = okExt
2237  				} else {
2238  					orOp := &SSABinOp{Op: OpLor, X: cond, Y: okExt}
2239  					orOp.typ = Typ[Bool]
2240  					orOp.name = fb.nextName()
2241  					fb.emit(orOp)
2242  					cond = orOp
2243  				}
2244  			}
2245  			fb.emit(&SSAIf{Cond: cond})
2246  			push(fb.currentBlock.Succs, caseBlock, nextBlock)
2247  			push(caseBlock.Preds, fb.currentBlock)
2248  			push(nextBlock.Preds, fb.currentBlock)
2249  
2250  			fb.currentBlock = caseBlock
2251  			if tsg.Lhs != nil {
2252  				var guardVal SSAValue
2253  				var guardType Type
2254  				if firstTA != nil {
2255  					ext := &SSAExtract{Tuple: firstTA, Index: 0}
2256  					ext.typ = firstType
2257  					ext.name = fb.nextName()
2258  					fb.emit(ext)
2259  					guardVal = ext
2260  					guardType = firstType
2261  				} else {
2262  					guardType = x.SSAType()
2263  					if guardType == nil {
2264  						guardType = NewTCInterface(nil, nil)
2265  					}
2266  					guardVal = &SSAConst{typ: guardType, val: nil}
2267  				}
2268  				for old := range fb.vars {
2269  					if ObjectName(old) == tsg.Lhs.Value {
2270  						delete(fb.vars, old)
2271  						break
2272  					}
2273  				}
2274  				obj := NewTCVar(fb.fn.Pkg.Pkg, tsg.Lhs.Value, guardType)
2275  				alloc := fb.emitAlloc(guardType, 0)
2276  				fb.vars[obj] = alloc
2277  				fb.emitStore(alloc, guardVal)
2278  			}
2279  		} else {
2280  			fb.emit(&SSAJump{Comment: "typeswitch.case"})
2281  			push(fb.currentBlock.Succs, caseBlock)
2282  			push(caseBlock.Preds, fb.currentBlock)
2283  			fb.currentBlock = caseBlock
2284  			if tsg.Lhs != nil {
2285  				guardType := x.SSAType()
2286  				if guardType == nil {
2287  					guardType = NewTCInterface(nil, nil)
2288  				}
2289  				for old := range fb.vars {
2290  					if ObjectName(old) == tsg.Lhs.Value {
2291  						delete(fb.vars, old)
2292  						break
2293  					}
2294  				}
2295  				obj := NewTCVar(fb.fn.Pkg.Pkg, tsg.Lhs.Value, guardType)
2296  				alloc := fb.emitAlloc(guardType, 0)
2297  				fb.vars[obj] = alloc
2298  				fb.emitStore(alloc, x)
2299  			}
2300  		}
2301  
2302  		tsScope := fb.enterScope()
2303  		caseBlock.ScopeID = fb.scopeID
2304  		caseSaved := fb.saveVars()
2305  		for _, stmt := range clause.Body {
2306  			fb.buildStmt(stmt)
2307  			if fb.currentBlock == nil {
2308  				break
2309  			}
2310  		}
2311  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
2312  			fb.emit(&SSAJump{Comment: "switch.done"})
2313  			push(fb.currentBlock.Succs, doneBlock)
2314  			push(doneBlock.Preds, fb.currentBlock)
2315  		}
2316  		fb.exitScope(tsScope)
2317  		fb.vars = caseSaved
2318  		fb.currentBlock = nextBlock
2319  	}
2320  	if savedObj != nil && savedAlloc != nil {
2321  		for old := range fb.vars {
2322  			if ObjectName(old) == tsg.Lhs.Value {
2323  				delete(fb.vars, old)
2324  				break
2325  			}
2326  		}
2327  		fb.vars[savedObj] = savedAlloc
2328  	}
2329  	if fb.currentBlock != nil {
2330  		fb.emit(&SSAJump{Comment: "switch.done"})
2331  		push(fb.currentBlock.Succs, doneBlock)
2332  		push(doneBlock.Preds, fb.currentBlock)
2333  	}
2334  }
2335  
2336  func (fb *ssaFuncBuilder) buildSelect(s *syntax.SelectStmt) {
2337  	doneBlock := fb.newBlock("select.done")
2338  
2339  	var states []*SSASelectState
2340  	caseBlocks := [](*SSABasicBlock){:0:len(s.Body)}
2341  	for i, clause := range s.Body {
2342  		cb := fb.newBlock("select.case")
2343  		push(caseBlocks, cb)
2344  		state := &SSASelectState{}
2345  		if clause.Comm != nil {
2346  			switch comm := clause.Comm.(type) {
2347  			case *syntax.SendStmt:
2348  				state.Dir = SelectDirSend
2349  				state.Chan = fb.buildExpr(comm.Chan)
2350  				state.Send = fb.buildExpr(comm.Value)
2351  			case *syntax.AssignStmt:
2352  				var chanExpr syntax.Expr
2353  				if op, ok2 := comm.Rhs.(*syntax.Operation); ok2 && op.Y == nil && op.Op == token.Recv {
2354  					chanExpr = op.X
2355  				}
2356  				if chanExpr != nil {
2357  					state.Dir = SelectDirRecv
2358  					state.Chan = fb.buildExpr(chanExpr)
2359  				}
2360  			case *syntax.ExprStmt:
2361  				if op, ok2 := comm.X.(*syntax.Operation); ok2 && op.Y == nil && op.Op == token.Recv {
2362  					state.Dir = SelectDirRecv
2363  					state.Chan = fb.buildExpr(op.X)
2364  				}
2365  			}
2366  		}
2367  		push(states, state)
2368  		_ = i
2369  	}
2370  
2371  	// Build tuple type with recv element types.
2372  	tupleVars := []*TCVar{
2373  		NewTCVar(nil, "index", Typ[Int32]),
2374  		NewTCVar(nil, "recvOk", Typ[Bool]),
2375  	}
2376  	recvFieldIdx := int32(2) // first recv value in tuple
2377  	for _, st := range states {
2378  		if st.Dir == SelectDirRecv && st.Chan != nil {
2379  			elemType := ssaChanElemType(st.Chan.SSAType())
2380  			push(tupleVars, NewTCVar(nil, "recv", elemType))
2381  		}
2382  	}
2383  	hasDefault := false
2384  	for _, clause := range s.Body {
2385  		if clause.Comm == nil {
2386  			hasDefault = true
2387  			break
2388  		}
2389  	}
2390  	sel := &SSASelect{States: states, Blocking: !hasDefault}
2391  	sel.typ = &Tuple{Vars: tupleVars}
2392  	sel.name = fb.nextName()
2393  	fb.emit(sel)
2394  
2395  	// Extract index from select result.
2396  	idxExt := &SSAExtract{Tuple: sel, Index: 0}
2397  	idxExt.typ = Typ[Int32]
2398  	idxExt.name = fb.nextName()
2399  	fb.emit(idxExt)
2400  
2401  	// Build if/else chain: if index == 0 -> case0, elif index == 1 -> case1, ...
2402  	entryBlock := fb.currentBlock
2403  	for i := int32(0); i < int32(len(s.Body)); i++ {
2404  		if i == int32(len(s.Body))-1 {
2405  			// Last case: unconditional jump.
2406  			fb.emit(&SSAJump{Comment: "select.last"})
2407  			push(entryBlock.Succs, caseBlocks[i])
2408  			push(caseBlocks[i].Preds, entryBlock)
2409  			break
2410  		}
2411  		nextCheck := fb.newBlock("select.check")
2412  		cmpVal := &SSAConst{typ: Typ[Int32], val: &ConstInt{V:int64(i)}}
2413  		cmp := &SSABinOp{Op: OpEql, X: idxExt, Y: cmpVal}
2414  		cmp.typ = Typ[Bool]
2415  		cmp.name = fb.nextName()
2416  		fb.emit(cmp)
2417  		fb.emit(&SSAIf{Cond: cmp})
2418  		push(entryBlock.Succs, caseBlocks[i])
2419  		push(caseBlocks[i].Preds, entryBlock)
2420  		push(entryBlock.Succs, nextCheck)
2421  		push(nextCheck.Preds, entryBlock)
2422  		fb.currentBlock = nextCheck
2423  		entryBlock = nextCheck
2424  	}
2425  
2426  	// Build case bodies.
2427  	recvIdx := recvFieldIdx
2428  	for i, clause := range s.Body {
2429  		selScope := fb.enterScope()
2430  		caseBlocks[i].ScopeID = fb.scopeID
2431  		fb.currentBlock = caseBlocks[i]
2432  
2433  		// For recv cases, extract the received value from the select tuple
2434  		// and bind it to the variable (don't re-do chanRecv).
2435  		if clause.Comm != nil && states[i].Dir == SelectDirRecv {
2436  			switch comm := clause.Comm.(type) {
2437  			case *syntax.AssignStmt:
2438  				// v := <-ch or v = <-ch
2439  				ext := &SSAExtract{Tuple: sel, Index: recvIdx}
2440  				ext.typ = ssaChanElemType(states[i].Chan.SSAType())
2441  				ext.name = fb.nextName()
2442  				fb.emit(ext)
2443  				if comm.Op == token.Def {
2444  					names := ssaExprNames(comm.Lhs)
2445  					for _, name := range names {
2446  						if name.Value == "_" {
2447  							continue
2448  						}
2449  						fb.removeVar(name.Value)
2450  						obj := NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
2451  						alloc := fb.emitAlloc(ext.typ, 0)
2452  						fb.vars[obj] = alloc
2453  						fb.emitStore(alloc, ext)
2454  					}
2455  				} else {
2456  					fb.buildStore(comm.Lhs, ext)
2457  				}
2458  			}
2459  			recvIdx++
2460  		}
2461  		// For send cases, the send was already done by chanSelect. Skip comm.
2462  
2463  		for _, stmt := range clause.Body {
2464  			fb.buildStmt(stmt)
2465  			if fb.currentBlock == nil {
2466  				break
2467  			}
2468  		}
2469  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
2470  			fb.emit(&SSAJump{Comment: "select.done"})
2471  			push(fb.currentBlock.Succs, doneBlock)
2472  			push(doneBlock.Preds, fb.currentBlock)
2473  		}
2474  		fb.exitScope(selScope)
2475  	}
2476  
2477  	fb.currentBlock = doneBlock
2478  }
2479  
2480  func (fb *ssaFuncBuilder) isSelfTailCall(e syntax.Expr) (ce *syntax.CallExpr, found bool) {
2481  	call, ok := e.(*syntax.CallExpr)
2482  	if !ok || fb.tailBlock == nil || fb.deferred > 0 {
2483  		return nil, false
2484  	}
2485  	name, ok := call.Fun.(*syntax.Name)
2486  	if !ok {
2487  		return nil, false
2488  	}
2489  	obj := fb.lookupObject(name.Value)
2490  	if obj == nil {
2491  		return nil, false
2492  	}
2493  	tc, ok := obj.(*TCFunc)
2494  	if !ok || tc == nil {
2495  		return nil, false
2496  	}
2497  	fn, _ := fb.fn.Pkg.Members[name.Value].(*SSAFunction)
2498  	if fn != fb.fn {
2499  		return nil, false
2500  	}
2501  	return call, true
2502  }
2503  
2504  func (fb *ssaFuncBuilder) buildReturn(s *syntax.ReturnStmt) {
2505  	if s.Results != nil {
2506  		if call, ok := fb.isSelfTailCall(s.Results); ok {
2507  			args := fb.buildArgs(call.ArgList)
2508  			if len(args) == len(fb.paramAllocas) {
2509  				for i, arg := range args {
2510  					fb.emitStore(fb.paramAllocas[i], arg)
2511  				}
2512  				fb.emit(&SSAJump{Comment: "tailcall"})
2513  				push(fb.currentBlock.Succs, fb.tailBlock)
2514  				push(fb.tailBlock.Preds, fb.currentBlock)
2515  				fb.currentBlock = nil
2516  				return
2517  			}
2518  		}
2519  	}
2520  	var vals []SSAValue
2521  	if s.Results != nil {
2522  		if list, ok := s.Results.(*syntax.ListExpr); ok {
2523  			for i, el := range list.ElemList {
2524  				v := fb.buildExpr(el)
2525  				if v != nil {
2526  					push(vals, v)
2527  				} else {
2528  					var zeroType Type
2529  					if fb.fn.Signature != nil && fb.fn.Signature.Results != nil && int32(i) < int32(fb.fn.Signature.Results.Len()) {
2530  						zeroType = fb.fn.Signature.Results.At(int32(i)).Typ
2531  					}
2532  					push(vals, &SSAConst{typ: zeroType, val: nil})
2533  				}
2534  			}
2535  		} else {
2536  			v := fb.buildExpr(s.Results)
2537  			if v != nil {
2538  				if v.SSAType() == nil {
2539  					push(vals, v)
2540  				} else if tup, ok2 := v.SSAType().(*Tuple); ok2 && tup.Len() > 1 {
2541  					for i := 0; i < tup.Len(); i++ {
2542  						ext := &SSAExtract{Tuple: v, Index: i}
2543  						ext.typ = tup.At(i).Typ
2544  						ext.name = fb.nextName()
2545  						fb.emit(ext)
2546  						push(vals, ext)
2547  					}
2548  				} else {
2549  					push(vals, v)
2550  				}
2551  			}
2552  		}
2553  	} else if len(fb.namedResults) > 0 {
2554  		for _, nr := range fb.namedResults {
2555  			elemType := nr.SSAType()
2556  			if p, ok := elemType.(*Pointer); ok {
2557  				elemType = p.Base
2558  			}
2559  			push(vals, fb.emitLoad(nr, elemType))
2560  		}
2561  	}
2562  	if fb.fn.Signature != nil && fb.fn.Signature.Results != nil {
2563  		for i, v := range vals {
2564  			if i < fb.fn.Signature.Results.Len() {
2565  				retType := fb.fn.Signature.Results.At(i).Typ
2566  				if n, ok := retType.(*Named); ok && n != nil {
2567  					u := n.Underlying()
2568  					if u != nil && u != Type(n) {
2569  						if _, isIface := u.(*TCInterface); isIface {
2570  							if _, alreadyIface := SafeUnderlying(v.SSAType()).(*TCInterface); !alreadyIface {
2571  								mi := &SSAMakeInterface{X: v}
2572  								mi.typ = retType
2573  								mi.name = fb.nextName()
2574  								fb.emit(mi)
2575  								vals[i] = mi
2576  								continue
2577  							}
2578  						}
2579  					}
2580  				}
2581  				vals[i] = fb.coerceToInterface(v, retType)
2582  			}
2583  		}
2584  	}
2585  	fb.emitReturn(vals, 0)
2586  }
2587  
2588  func (fb *ssaFuncBuilder) buildBranch(s *syntax.BranchStmt) {
2589  	if fb.currentBlock == nil {
2590  		return
2591  	}
2592  	switch s.Tok {
2593  	case token.Break:
2594  		if len(fb.loops) > 0 {
2595  			var doneBlock *SSABasicBlock
2596  			if s.Label != nil {
2597  				for i := len(fb.loops) - 1; i >= 0; i-- {
2598  					if fb.loops[i].label == s.Label.Value {
2599  						doneBlock = fb.loops[i].done
2600  						break
2601  					}
2602  				}
2603  			}
2604  			if doneBlock == nil {
2605  				doneBlock = fb.loops[len(fb.loops)-1].done
2606  			}
2607  			if doneBlock != nil {
2608  				fb.emit(&SSAJump{Comment: "break"})
2609  				push(fb.currentBlock.Succs, doneBlock)
2610  				push(doneBlock.Preds, fb.currentBlock)
2611  				fb.currentBlock = nil
2612  			}
2613  		}
2614  	case token.Continue:
2615  		for i := len(fb.loops) - 1; i >= 0; i-- {
2616  			postBlock := fb.loops[i].post
2617  			if postBlock == nil {
2618  				postBlock = fb.loops[i].body
2619  			}
2620  			if postBlock == nil {
2621  				continue
2622  			}
2623  			fb.emit(&SSAJump{Comment: "continue"})
2624  			push(fb.currentBlock.Succs, postBlock)
2625  			push(postBlock.Preds, fb.currentBlock)
2626  			fb.currentBlock = nil
2627  			break
2628  		}
2629  	case token.Goto:
2630  		if s.Label != nil {
2631  			target := fb.labelBlock(s.Label.Value)
2632  			if target != nil {
2633  				fb.emit(&SSAJump{Comment: "goto"})
2634  				push(fb.currentBlock.Succs, target)
2635  				push(target.Preds, fb.currentBlock)
2636  				fb.currentBlock = nil
2637  			}
2638  		}
2639  	case token.Return:
2640  		fb.emitReturn(nil, 0)
2641  	}
2642  }
2643  
2644  func (fb *ssaFuncBuilder) buildGoStmt(call *syntax.CallExpr) {
2645  	fn := fb.buildExpr(call.Fun)
2646  	if fn == nil {
2647  		return
2648  	}
2649  	args := fb.buildArgs(call.ArgList)
2650  	g := &SSAGo{Call: SSACallCommon{Value: fn, Args: args}}
2651  	fb.emit(g)
2652  }
2653  
2654  func (fb *ssaFuncBuilder) buildDeferStmt(call *syntax.CallExpr) {
2655  	fn := fb.buildExpr(call.Fun)
2656  	if fn == nil {
2657  		return
2658  	}
2659  	args := fb.buildArgs(call.ArgList)
2660  	d := &SSADefer{Call: SSACallCommon{Value: fn, Args: args}}
2661  	fb.emit(d)
2662  	fb.deferred++
2663  }
2664  
2665  // Expression builders.
2666  
2667  func (fb *ssaFuncBuilder) buildExpr(e syntax.Expr) (s SSAValue) {
2668  	if e == nil || fb.currentBlock == nil {
2669  		return nil
2670  	}
2671  	switch ev := e.(type) {
2672  	case *syntax.Name:
2673  		return fb.buildIdent(ev)
2674  	case *syntax.BasicLit:
2675  		return fb.buildLit(ev)
2676  	case *syntax.Operation:
2677  		return fb.buildOperation(ev)
2678  	case *syntax.CallExpr:
2679  		return fb.buildCall(ev)
2680  	case *syntax.SelectorExpr:
2681  		return fb.buildSelector(ev)
2682  	case *syntax.IndexExpr:
2683  		return fb.buildIndex(ev)
2684  	case *syntax.SliceExpr:
2685  		return fb.buildSlice(ev)
2686  	case *syntax.AssertExpr:
2687  		return fb.buildAssert(ev)
2688  	case *syntax.CompositeLit:
2689  		return fb.buildCompositeLit(ev)
2690  	case *syntax.FuncLit:
2691  		return fb.buildFuncLit(ev)
2692  	case *syntax.ParenExpr:
2693  		return fb.buildExpr(ev.X)
2694  	case *syntax.ListExpr:
2695  		var last SSAValue
2696  		for _, el := range ev.ElemList {
2697  			last = fb.buildExpr(el)
2698  		}
2699  		return last
2700  	case *syntax.KeyValueExpr:
2701  		return fb.buildExpr(ev.Value)
2702  	}
2703  	return nil
2704  }
2705  
2706  func (fb *ssaFuncBuilder) buildIdent(e *syntax.Name) (s SSAValue) {
2707  	if e.Value == "_" || e.Value == "nil" {
2708  		return &SSAConst{typ: nil, val: nil}
2709  	}
2710  	if fb.localConsts != nil {
2711  		if c, ok := fb.localConsts[e.Value]; ok {
2712  			return c
2713  		}
2714  	}
2715  	obj := fb.lookupObject(e.Value)
2716  	if obj == nil && fb.info != nil {
2717  		obj = fb.info.Uses[e]
2718  	}
2719  	if obj == nil && fb.parent != nil {
2720  		for p := fb.parent; p != nil; p = p.parent {
2721  			for pobj := range p.vars {
2722  				if ObjectName(pobj) == e.Value {
2723  					fv := fb.getOrCreateFreeVar(e.Value, ObjectType(pobj))
2724  					return fb.emitLoad(fv, ObjectType(pobj))
2725  				}
2726  			}
2727  			if p.freeVarPtrs != nil {
2728  				if pfv, ok := p.freeVarPtrs[e.Value]; ok {
2729  					fv := fb.getOrCreateFreeVar(e.Value, pfv.typ)
2730  					return fb.emitLoad(fv, pfv.typ)
2731  				}
2732  			}
2733  		}
2734  	}
2735  	if obj == nil {
2736  		if fb.fn.Pkg != nil {
2737  			if fn, ok := fb.fn.Pkg.Members[e.Value].(*SSAFunction); ok {
2738  				return fn
2739  			}
2740  			if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
2741  				return fb.emitLoad(g, g.typ)
2742  			}
2743  			if nc, ok := fb.fn.Pkg.Members[e.Value].(*SSANamedConst); ok {
2744  				return nc.Value
2745  			}
2746  		}
2747  		return fb.builtinValue(e.Value)
2748  	}
2749  	switch ob := obj.(type) {
2750  	case *TCVar:
2751  		if alloc, ok := fb.vars[ob]; ok {
2752  			return fb.emitLoad(alloc, ob.Typ)
2753  		}
2754  		if fv, ok := fb.freeVarPtrs[e.Value]; ok {
2755  			return fb.emitLoad(fv, ob.Typ)
2756  		}
2757  		for p := fb.parent; p != nil; p = p.parent {
2758  			found := false
2759  			if _, ok := p.vars[ob]; ok {
2760  				found = true
2761  			}
2762  			if !found {
2763  				for pobj := range p.vars {
2764  					if ObjectName(pobj) == e.Value {
2765  						found = true
2766  						break
2767  					}
2768  				}
2769  			}
2770  			if !found && p.freeVarPtrs != nil {
2771  				if _, ok := p.freeVarPtrs[e.Value]; ok {
2772  					found = true
2773  				}
2774  			}
2775  			if found {
2776  				fv := fb.getOrCreateFreeVar(e.Value, ob.Typ)
2777  				return fb.emitLoad(fv, ob.Typ)
2778  			}
2779  		}
2780  		if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
2781  			return fb.emitLoad(g, ob.Typ)
2782  		}
2783  		// dot-imported variable from another package
2784  		if ob.Pkg != nil && ob.Pkg != fb.fn.Pkg.Pkg {
2785  			impPkg := fb.ensureImportedSSAPackage(ob.Pkg)
2786  			g, ok := impPkg.Members[e.Value].(*SSAGlobal)
2787  			if !ok {
2788  				g = &SSAGlobal{
2789  					name: e.Value,
2790  					typ:  NewPointer(ob.Typ),
2791  					pkg:  impPkg,
2792  				}
2793  				impPkg.SetMember(e.Value, g)
2794  			}
2795  			return fb.emitLoad(g, ob.Typ)
2796  		}
2797  		return &SSAConst{typ: ob.Typ, val: nil}
2798  	case *TCConst:
2799  		return &SSAConst{typ: ob.Typ, val: localizeConstVal(ob.Val, ob.Typ)}
2800  	case *TCFunc:
2801  		fn, _ := fb.fn.Pkg.Members[e.Value].(*SSAFunction)
2802  		if fn != nil {
2803  			return fn
2804  		}
2805  		// dot-imported function from another package
2806  		if ob.Pkg != nil && ob.Pkg != fb.fn.Pkg.Pkg {
2807  			impPkg := fb.ensureImportedSSAPackage(ob.Pkg)
2808  			fn = impPkg.Func(e.Value)
2809  			if fn == nil {
2810  				sig, _ := ob.Typ.(*Signature)
2811  				fn = &SSAFunction{
2812  					name:      e.Value,
2813  					object:    ob,
2814  					Signature: sig,
2815  					Pkg:       impPkg,
2816  					Prog:      fb.fn.Prog,
2817  				}
2818  				impPkg.SetMember(e.Value, fn)
2819  			}
2820  			return fn
2821  		}
2822  		return &SSAConst{typ: ob.Typ, val: nil}
2823  	case *TypeName:
2824  		return nil
2825  	case *Builtin:
2826  		return &SSABuiltin{id: ob.Id, name: ob.Name}
2827  	}
2828  	return nil
2829  }
2830  
2831  func (fb *ssaFuncBuilder) builtinValue(name string) (s SSAValue) {
2832  	id, ok := ssaBuiltinID(name)
2833  	if !ok {
2834  		return nil
2835  	}
2836  	return &SSABuiltin{id: id, name: name}
2837  }
2838  
2839  func (fb *ssaFuncBuilder) buildLit(e *syntax.BasicLit) (s SSAValue) {
2840  	cv := EvalBasicLitLocal(e)
2841  	if cv == nil {
2842  		return nil
2843  	}
2844  	switch e.Kind {
2845  	case token.IntLit:
2846  		return &SSAConst{typ: Typ[UntypedInt], val: cv}
2847  	case token.FloatLit:
2848  		return &SSAConst{typ: Typ[UntypedFloat], val: cv}
2849  	case token.StringLit:
2850  		return &SSAConst{typ: Typ[UntypedString], val: cv}
2851  	case token.RuneLit:
2852  		return &SSAConst{typ: Typ[UntypedRune], val: cv}
2853  	}
2854  	return nil
2855  }
2856  
2857  func (fb *ssaFuncBuilder) buildOperation(e *syntax.Operation) (s SSAValue) {
2858  	if e.Y == nil {
2859  		if e.Op == token.Add {
2860  			return fb.buildExpr(e.X)
2861  		}
2862  		op2 := syntaxOpToSSAOp(e.Op, true)
2863  		if op2 == OpAnd {
2864  			if name, ok := e.X.(*syntax.Name); ok {
2865  				obj := fb.lookupObject(name.Value)
2866  				if obj != nil {
2867  					if alloc, ok2 := fb.vars[obj]; ok2 {
2868  						return alloc
2869  					}
2870  					if g, ok2 := fb.fn.Pkg.Members[name.Value].(*SSAGlobal); ok2 {
2871  						return g
2872  					}
2873  				}
2874  			}
2875  			if ie, ok := e.X.(*syntax.IndexExpr); ok {
2876  				idx := fb.buildExpr(ie.Index)
2877  				if idx == nil {
2878  					return nil
2879  				}
2880  				var base SSAValue
2881  				if sel, ok2 := ie.X.(*syntax.SelectorExpr); ok2 {
2882  					base = fb.buildSelectorAddr(sel)
2883  				}
2884  				if base == nil {
2885  					base = fb.buildExpr(ie.X)
2886  				}
2887  				if base == nil {
2888  					return nil
2889  				}
2890  				// &s.field[i] where field is a slice: base is a pointer to
2891  				// the slice header; load the header so IndexAddr indexes the
2892  				// slice's data pointer, not the header itself.
2893  				if pt, okp := SafeUnderlying(base.SSAType()).(*Pointer); okp && pt.Base != nil {
2894  					pte := pt.Base
2895  					pteu := SafeUnderlying(pte)
2896  					isSl := false
2897  					if _, ok2 := pteu.(*Slice); ok2 {
2898  						isSl = true
2899  					} else if bb, okb := pteu.(*Basic); okb && bb.Info&IsString != 0 {
2900  						isSl = true
2901  					}
2902  					if isSl {
2903  						base = fb.emitLoad(base, pte)
2904  					}
2905  				}
2906  				ia := &SSAIndexAddr{X: base, Index: idx}
2907  				ia.typ = NewPointer(ssaElemType(base.SSAType()))
2908  				ia.name = fb.nextName()
2909  				fb.emit(ia)
2910  				return ia
2911  			}
2912  			if sel, ok := e.X.(*syntax.SelectorExpr); ok {
2913  				addr := fb.buildSelectorAddr(sel)
2914  				if addr != nil {
2915  					return addr
2916  				}
2917  			}
2918  			xv2 := fb.buildExpr(e.X)
2919  			if xv2 == nil {
2920  				return nil
2921  			}
2922  			a := &SSAAlloc{Heap: true}
2923  			a.typ = NewPointer(xv2.SSAType())
2924  			a.name = fb.nextName()
2925  			fb.emit(a)
2926  			fb.emitStore(a, xv2)
2927  			return a
2928  		}
2929  		xv3 := fb.buildExpr(e.X)
2930  		if xv3 == nil {
2931  			return nil
2932  		}
2933  		if op2 == OpArrow {
2934  			u2 := &SSAUnOp{Op: OpArrow, X: xv3}
2935  			u2.typ = ssaChanElemType(xv3.SSAType())
2936  			u2.name = fb.nextName()
2937  			fb.emit(u2)
2938  			return u2
2939  		}
2940  		u := &SSAUnOp{Op: op2, X: xv3}
2941  		if op2 == OpMul {
2942  			if p, ok := xv3.SSAType().(*Pointer); ok {
2943  				u.typ = p.Base
2944  			} else {
2945  				u.typ = xv3.SSAType()
2946  			}
2947  		} else {
2948  			u.typ = xv3.SSAType()
2949  		}
2950  		u.name = fb.nextName()
2951  		fb.emit(u)
2952  		return u
2953  	}
2954  	op := syntaxOpToSSAOp(e.Op, false)
2955  	if op == OpLand || op == OpLor {
2956  		xv4 := fb.buildExpr(e.X)
2957  		if xv4 == nil {
2958  			return nil
2959  		}
2960  		rhsBlock := fb.newBlock("sc.rhs")
2961  		mergeBlock := fb.newBlock("sc.merge")
2962  		entryBlock := fb.currentBlock
2963  		fb.emit(&SSAIf{Cond: xv4})
2964  		if op == OpLand {
2965  			push(fb.currentBlock.Succs, rhsBlock, mergeBlock)
2966  		} else {
2967  			push(fb.currentBlock.Succs, mergeBlock, rhsBlock)
2968  		}
2969  		push(rhsBlock.Preds, entryBlock)
2970  		push(mergeBlock.Preds, entryBlock)
2971  		fb.currentBlock = rhsBlock
2972  		yv := fb.buildExpr(e.Y)
2973  		if yv == nil {
2974  			yv = &SSAConst{typ: Typ[Bool], val: &ConstBool{V:false}}
2975  		}
2976  		fb.emit(&SSAJump{Comment: "sc.merge"})
2977  		push(fb.currentBlock.Succs, mergeBlock)
2978  		push(mergeBlock.Preds, fb.currentBlock)
2979  		fb.currentBlock = mergeBlock
2980  		var shortVal SSAValue
2981  		if op == OpLand {
2982  			shortVal = &SSAConst{typ: Typ[Bool], val: &ConstBool{V:false}}
2983  		} else {
2984  			shortVal = &SSAConst{typ: Typ[Bool], val: &ConstBool{V:true}}
2985  		}
2986  		phi := &SSAPhi{Edges: []SSAValue{shortVal, yv}, Comment: "sc"}
2987  		phi.typ = Typ[Bool]
2988  		phi.name = fb.nextName()
2989  		fb.emit(phi)
2990  		return phi
2991  	}
2992  	x := fb.buildExpr(e.X)
2993  	y := fb.buildExpr(e.Y)
2994  	if x == nil || y == nil {
2995  		return nil
2996  	}
2997  	if (op == OpOr || op == OpAdd) && x.SSAType() != nil && y.SSAType() != nil {
2998  		if IsRuneKind(x.SSAType()) && IsStringKind(y.SSAType()) || IsStringKind(x.SSAType()) && IsRuneKind(y.SSAType()) {
2999  			mxutil.WriteStr(2, "compile error: cannot concatenate rune with string - convert to UTF-8 first\n")
3000  			push(cctx.compileErrors, "cannot concatenate rune with string")
3001  		}
3002  	}
3003  	if xc, ok := x.(*SSAConst); ok {
3004  		if yc, ok2 := y.(*SSAConst); ok2 {
3005  			if xc.val != nil && yc.val != nil {
3006  				folded := EvalBinaryLocal(e.Op, xc.val, yc.val)
3007  				if folded != nil {
3008  					ct := xc.typ
3009  					if ct == nil {
3010  						ct = yc.typ
3011  					}
3012  					if _, isBool := folded.(*ConstBool); isBool {
3013  						ct = Typ[Bool]
3014  					}
3015  					return &SSAConst{typ: ct, val: folded}
3016  				}
3017  			}
3018  		}
3019  	}
3020  	b := &SSABinOp{Op: op, X: x, Y: y}
3021  	b.name = fb.nextName()
3022  	switch op {
3023  	case OpEql, OpNeq, OpLss, OpLeq, OpGtr, OpGeq:
3024  		b.typ = Typ[Bool]
3025  	default:
3026  		xT := x.SSAType()
3027  		yT := y.SSAType()
3028  		xUntyped := false
3029  		if xB, ok := SafeUnderlying(xT).(*Basic); ok && xB.Info&IsUntyped != 0 {
3030  			xUntyped = true
3031  		}
3032  		if xT != nil && !xUntyped {
3033  			b.typ = xT
3034  		} else if yT != nil {
3035  			b.typ = yT
3036  		} else {
3037  			b.typ = xT
3038  		}
3039  	}
3040  	fb.emit(b)
3041  	return b
3042  }
3043  
3044  func (fb *ssaFuncBuilder) buildCall(e *syntax.CallExpr) (s SSAValue) {
3045  	if ie, ok := e.Fun.(*syntax.IndexExpr); ok {
3046  		if result, handled := fb.tryGenericCallFromIndex(ie, e.ArgList, e.HasDots); handled {
3047  			return result
3048  		}
3049  	}
3050  	if name, ok := e.Fun.(*syntax.Name); ok {
3051  		obj := fb.lookupObject(name.Value)
3052  		if tn, ok2 := obj.(*TypeName); ok2 {
3053  			if _, isTP := tn.Typ.(*TypeParam); !isTP {
3054  				args2 := fb.buildArgs(e.ArgList)
3055  				if len(args2) == 1 && args2[0] != nil {
3056  					conv := &SSAConvert{X: args2[0]}
3057  					conv.typ = tn.Typ
3058  					conv.name = fb.nextName()
3059  					fb.emit(conv)
3060  					return conv
3061  				}
3062  				return nil
3063  			}
3064  		}
3065  		if result, handled := fb.tryGenericLocalCall(name.Value, e.ArgList, e.HasDots); handled {
3066  			return result
3067  		}
3068  	}
3069  	if convType := fb.resolveTypeAST(e.Fun); convType != nil {
3070  		args3 := fb.buildArgs(e.ArgList)
3071  		if len(args3) == 1 && args3[0] != nil {
3072  			conv := &SSAConvert{X: args3[0]}
3073  			conv.typ = convType
3074  			conv.name = fb.nextName()
3075  			fb.emit(conv)
3076  			return conv
3077  		}
3078  		return nil
3079  	}
3080  	if sel, ok := e.Fun.(*syntax.SelectorExpr); ok {
3081  		if name, ok2 := sel.X.(*syntax.Name); ok2 {
3082  			obj := fb.lookupObject(name.Value)
3083  			if pn, ok3 := obj.(*PkgName); ok3 {
3084  				return fb.buildPkgCall(pn, sel.Sel.Value, e.ArgList, e.HasDots)
3085  			}
3086  		}
3087  		recv := fb.buildExpr(sel.X)
3088  		if recv != nil && recv.SSAType() != nil {
3089  			if fn2, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv); fn2 != nil {
3090  				fixedRecv = fb.derefValueRecv(fn2, fixedRecv)
3091  				args4 := fb.buildArgs(e.ArgList)
3092  				if fn2.Signature != nil {
3093  					if fn2.Signature.Variadic && !e.HasDots {
3094  						args4 = fb.wrapVariadicArgs(args4, fn2.Signature)
3095  					}
3096  					args4 = fb.coerceArgsToInterface(args4, fn2.Signature)
3097  				}
3098  				allArgs := []SSAValue{:0:len(args4) + 1}
3099  				push(allArgs, fixedRecv)
3100  				for _, ma := range args4 {
3101  					push(allArgs, ma)
3102  				}
3103  				var retType2 Type
3104  				if fn2.Signature != nil {
3105  					if fn2.Signature.Results != nil && fn2.Signature.Results.Len() == 1 {
3106  						retType2 = fn2.Signature.Results.At(0).Typ
3107  					} else if fn2.Signature.Results != nil && fn2.Signature.Results.Len() > 1 {
3108  						retType2 = fn2.Signature.Results
3109  					}
3110  				}
3111  				call2 := &SSACall{Call: SSACallCommon{Value: fn2, Args: allArgs}}
3112  				call2.typ = retType2
3113  				call2.name = fb.nextName()
3114  				fb.emit(call2)
3115  				if retType2 == nil {
3116  					return nil
3117  				}
3118  				return call2
3119  			}
3120  			if inv := fb.buildIfaceMethodCall(sel, recv, e.ArgList); inv != nil {
3121  				return inv
3122  			}
3123  		}
3124  	}
3125  	fn := fb.buildExpr(e.Fun)
3126  	args := fb.buildArgs(e.ArgList)
3127  
3128  	if fn == nil {
3129  		return nil
3130  	}
3131  	if bi, ok := fn.(*SSABuiltin); ok {
3132  		return fb.buildBuiltinCall(e, bi, args)
3133  	}
3134  
3135  	var retType Type
3136  	if fn.SSAType() != nil {
3137  		if sig, ok := SafeUnderlying(fn.SSAType()).(*Signature); ok {
3138  			if sig.Results != nil && sig.Results.Len() == 1 {
3139  				retType = sig.Results.At(0).Typ
3140  			} else if sig.Results != nil && sig.Results.Len() > 1 {
3141  				retType = sig.Results
3142  			}
3143  		}
3144  	} else if ssaFn, ok := fn.(*SSAFunction); ok && ssaFn.Signature != nil {
3145  		sig := ssaFn.Signature
3146  		if sig.Results != nil && sig.Results.Len() == 1 {
3147  			retType = sig.Results.At(0).Typ
3148  		} else if sig.Results != nil && sig.Results.Len() > 1 {
3149  			retType = sig.Results
3150  		}
3151  	}
3152  
3153  	if fn.SSAType() != nil {
3154  		if sig, ok := SafeUnderlying(fn.SSAType()).(*Signature); ok {
3155  			if sig.Variadic && !e.HasDots {
3156  				args = fb.wrapVariadicArgs(args, sig)
3157  			}
3158  			args = fb.coerceArgsToInterface(args, sig)
3159  		}
3160  	}
3161  
3162  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
3163  	call.typ = retType
3164  	call.name = fb.nextName()
3165  	fb.emit(call)
3166  
3167  	if retType == nil {
3168  		return nil
3169  	}
3170  	return call
3171  }
3172  
3173  func (fb *ssaFuncBuilder) coerceArgsToInterface(args []SSAValue, sig *Signature) (ss []SSAValue) {
3174  	if sig.Params == nil {
3175  		return args
3176  	}
3177  	for i := 0; i < len(args) && i < sig.Params.Len(); i++ {
3178  		paramType := sig.Params.At(i).Typ
3179  		if paramType == nil || args[i] == nil || args[i].SSAType() == nil {
3180  			continue
3181  		}
3182  		_, isIface := SafeUnderlying(paramType).(*TCInterface)
3183  		if !isIface {
3184  			continue
3185  		}
3186  		_, argIsIface := SafeUnderlying(args[i].SSAType()).(*TCInterface)
3187  		if argIsIface {
3188  			continue
3189  		}
3190  		mi := &SSAMakeInterface{X: args[i], IType: paramType}
3191  		mi.typ = paramType
3192  		mi.name = fb.nextName()
3193  		fb.emit(mi)
3194  		args[i] = mi
3195  	}
3196  	return args
3197  }
3198  
3199  func (fb *ssaFuncBuilder) wrapVariadicArgs(args []SSAValue, sig *Signature) (ss []SSAValue) {
3200  	if sig.Params == nil {
3201  		return args
3202  	}
3203  	nFixed := sig.Params.Len() - 1
3204  	if nFixed < 0 {
3205  		nFixed = 0
3206  	}
3207  	if nFixed > len(args) {
3208  		nFixed = len(args)
3209  	}
3210  	nVariadic := len(args) - nFixed
3211  	if nVariadic <= 0 {
3212  		nilSlice := NewSSAConst(&ConstNil{}, sig.Params.At(sig.Params.Len()-1).Typ)
3213  		result2 := []SSAValue{:nFixed:nFixed}
3214  		copy(result2, args[:nFixed])
3215  		push(result2, nilSlice)
3216  		return result2
3217  	}
3218  	sliceType := sig.Params.At(sig.Params.Len() - 1).Typ
3219  	var elemType Type
3220  	if sl, ok := SafeUnderlying(sliceType).(*Slice); ok {
3221  		elemType = sl.Elem
3222  	}
3223  	// HasDots lost because closures can't write to captured named returns.
3224  	// Detect spread: if exactly 1 variadic arg whose type matches the
3225  	// variadic param's slice type, pass it through. This covers both
3226  	// concrete T and interface{} variadics (e.g. fmt.Print -> fmt.Fprint).
3227  	if nVariadic == 1 && elemType != nil {
3228  		argT := args[nFixed].SSAType()
3229  		if argT != nil && Identical(argT, sliceType) {
3230  			return args
3231  		}
3232  	}
3233  	lenVal := NewSSAConst(&ConstInt{V:int64(nVariadic)}, Typ[Int32])
3234  	ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal}
3235  	ms.typ = sliceType
3236  	ms.name = fb.nextName()
3237  	fb.emit(ms)
3238  	for i := 0; i < nVariadic; i++ {
3239  		idx := NewSSAConst(&ConstInt{V:int64(i)}, Typ[Int32])
3240  		ia := &SSAIndexAddr{X: ms, Index: idx}
3241  		ia.typ = NewPointer(elemType)
3242  		ia.name = fb.nextName()
3243  		fb.emit(ia)
3244  		v := args[nFixed+i]
3245  		if elemType != nil {
3246  			v = fb.coerceToInterface(v, elemType)
3247  		}
3248  		fb.emitStore(ia, v)
3249  	}
3250  	result := []SSAValue{:nFixed:nFixed}
3251  	copy(result, args[:nFixed])
3252  	push(result, ms)
3253  	return result
3254  }
3255  
3256  func (fb *ssaFuncBuilder) buildArgs(argList []syntax.Expr) (ss []SSAValue) {
3257  	args := []SSAValue{:0:len(argList)}
3258  	for _, a := range argList {
3259  		v := fb.buildExpr(a)
3260  		if v != nil {
3261  			push(args, v)
3262  		}
3263  	}
3264  	if len(args) == 1 && args[0] != nil {
3265  		if t, ok := args[0].SSAType().(*Tuple); ok && t.Len() > 1 {
3266  			expanded := []SSAValue{:0:t.Len()}
3267  			for i := int32(0); i < int32(t.Len()); i++ {
3268  				ext := &SSAExtract{Tuple: args[0], Index: int32(i)}
3269  				ext.typ = t.At(int32(i)).Typ
3270  				ext.name = fb.nextName()
3271  				fb.emit(ext)
3272  				push(expanded, ext)
3273  			}
3274  			return expanded
3275  		}
3276  	}
3277  	return args
3278  }
3279  
3280  func (fb *ssaFuncBuilder) buildBuiltinCall(e *syntax.CallExpr, b *SSABuiltin, args []SSAValue) (s SSAValue) {
3281  	switch b.id {
3282  	case BuiltinLen, BuiltinCap:
3283  		if b.id == BuiltinLen && len(args) == 1 {
3284  			if c, ok := args[0].(*SSAConst); ok {
3285  				if cs, ok2 := c.val.(*ConstStr); ok2 {
3286  					return &SSAConst{typ: Typ[Int32], val: &ConstInt{V:int64(len(cs.S))}}
3287  				}
3288  			}
3289  		}
3290  		call2 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3291  		call2.typ = Typ[Int32]
3292  		call2.name = fb.nextName()
3293  		fb.emit(call2)
3294  		return call2
3295  	case BuiltinAppend:
3296  		if len(args) > 1 {
3297  			if sl, ok := SafeUnderlying(args[0].SSAType()).(*Slice); ok {
3298  				if _, isIface := SafeUnderlying(sl.Elem).(*TCInterface); isIface {
3299  					for i := 1; i < len(args); i++ {
3300  						if e.HasDots && i == 1 {
3301  							continue
3302  						}
3303  						if args[i] == nil || args[i].SSAType() == nil {
3304  							continue
3305  						}
3306  						if _, argIface := SafeUnderlying(args[i].SSAType()).(*TCInterface); argIface {
3307  							continue
3308  						}
3309  						mi := &SSAMakeInterface{X: args[i], IType: sl.Elem}
3310  						mi.typ = sl.Elem
3311  						mi.name = fb.nextName()
3312  						fb.emit(mi)
3313  						args[i] = mi
3314  					}
3315  				}
3316  			}
3317  		}
3318  		call3 := &SSACall{Call: SSACallCommon{Value: b, Args: args, HasDots: e.HasDots}}
3319  		if len(args) > 0 {
3320  			call3.typ = args[0].SSAType()
3321  		}
3322  		call3.name = fb.nextName()
3323  		fb.emit(call3)
3324  		return call3
3325  	case BuiltinMake:
3326  		if len(e.ArgList) == 0 {
3327  			return nil
3328  		}
3329  		typ := fb.resolveType(e.ArgList[0])
3330  		return fb.emitMake(typ, args)
3331  	case BuiltinNew:
3332  		if len(e.ArgList) == 0 {
3333  			return nil
3334  		}
3335  		typ := fb.resolveType(e.ArgList[0])
3336  		a := &SSAAlloc{Heap: true}
3337  		a.typ = NewPointer(typ)
3338  		a.name = fb.nextName()
3339  		fb.emit(a)
3340  		return a
3341  	case BuiltinPanic:
3342  		if len(args) > 0 {
3343  			fb.emit(&SSAPanic{X: args[0]})
3344  			fb.currentBlock = nil
3345  		}
3346  		return nil
3347  	case BuiltinClose, BuiltinDelete, BuiltinClear, BuiltinPrint, BuiltinPrintln:
3348  		call4 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3349  		call4.name = fb.nextName()
3350  		fb.emit(call4)
3351  		return nil
3352  	case BuiltinCopy:
3353  		call5 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3354  		call5.typ = Typ[Int32]
3355  		call5.name = fb.nextName()
3356  		fb.emit(call5)
3357  		return call5
3358  	case BuiltinRecover:
3359  		call6 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3360  		call6.typ = NewTCInterface(nil, nil)
3361  		call6.name = fb.nextName()
3362  		fb.emit(call6)
3363  		return call6
3364  	case BuiltinSpawn:
3365  		call7 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3366  		call7.typ = NewTCChan(TCRecvOnly, Typ[TCString])
3367  		call7.name = fb.nextName()
3368  		fb.emit(call7)
3369  		return call7
3370  	case BuiltinMin, BuiltinMax:
3371  		call8 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3372  		if len(args) > 0 && args[0] != nil {
3373  			call8.typ = args[0].SSAType()
3374  		} else {
3375  			call8.typ = Typ[Int32]
3376  		}
3377  		call8.name = fb.nextName()
3378  		fb.emit(call8)
3379  		return call8
3380  	}
3381  	call9 := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
3382  	call9.name = fb.nextName()
3383  	fb.emit(call9)
3384  	return call9
3385  }
3386  
3387  func (fb *ssaFuncBuilder) emitMake(typ Type, sizeArgs []SSAValue) (s SSAValue) {
3388  	if typ == nil {
3389  		return nil
3390  	}
3391  	switch u := SafeUnderlying(typ).(type) {
3392  	case *Basic:
3393  		if u.Kind == TCString {
3394  			ms := &SSAMakeSlice{}
3395  			ms.typ = typ
3396  			ms.name = fb.nextName()
3397  			if len(sizeArgs) > 0 {
3398  				ms.Len = sizeArgs[0]
3399  			}
3400  			if len(sizeArgs) > 1 {
3401  				ms.Cap = sizeArgs[1]
3402  			}
3403  			fb.emit(ms)
3404  			return ms
3405  		}
3406  	case *Slice:
3407  		ms := &SSAMakeSlice{}
3408  		ms.typ = typ
3409  		ms.name = fb.nextName()
3410  		if len(sizeArgs) > 0 {
3411  			ms.Len = sizeArgs[0]
3412  		}
3413  		if len(sizeArgs) > 1 {
3414  			ms.Cap = sizeArgs[1]
3415  		}
3416  		fb.emit(ms)
3417  		return ms
3418  	case *TCMap:
3419  		mm := &SSAMakeMap{}
3420  		mm.typ = typ
3421  		mm.name = fb.nextName()
3422  		if len(sizeArgs) > 0 {
3423  			mm.Reserve = sizeArgs[0]
3424  		}
3425  		fb.emit(mm)
3426  		return mm
3427  	case *TCChan:
3428  		mc := &SSAMakeChan{}
3429  		mc.typ = typ
3430  		mc.name = fb.nextName()
3431  		if len(sizeArgs) > 0 {
3432  			mc.Size = sizeArgs[0]
3433  		}
3434  		fb.emit(mc)
3435  		return mc
3436  	}
3437  	return nil
3438  }
3439  
3440  func (fb *ssaFuncBuilder) buildSelector(e *syntax.SelectorExpr) (s SSAValue) {
3441  	if name, ok := e.X.(*syntax.Name); ok {
3442  		obj := fb.lookupObject(name.Value)
3443  		if obj == nil && fb.info != nil {
3444  			obj = fb.info.Uses[name]
3445  		}
3446  		if pn, ok2 := obj.(*PkgName); ok2 {
3447  			return fb.buildPkgMember(pn, e.Sel.Value)
3448  		}
3449  		// Fallback: resolve imported const directly from the type
3450  		// checker's selection info when PkgName lookup fails.
3451  		if obj == nil && fb.info != nil && fb.info.Selections != nil {
3452  			if sel, ok3 := fb.info.Selections[e]; ok3 {
3453  				if sel.Obj != nil {
3454  					if tc, ok4 := sel.Obj.(*TCConst); ok4 {
3455  						return &SSAConst{typ: tc.Typ, val: localizeConstVal(tc.Val, tc.Typ)}
3456  					}
3457  				}
3458  			}
3459  		}
3460  	}
3461  	fa := fb.buildSelectorAddr(e)
3462  	if fa != nil {
3463  		elemType := fa.SSAType()
3464  		if p, ok := SafeUnderlying(elemType).(*Pointer); ok {
3465  			elemType = p.Base
3466  		}
3467  		return fb.emitLoad(fa, elemType)
3468  	}
3469  	recv := fb.buildExpr(e.X)
3470  	if recv == nil {
3471  		return nil
3472  	}
3473  	return fb.buildMethodValue(e, recv)
3474  }
3475  
3476  func (fb *ssaFuncBuilder) buildMethodValue(sel *syntax.SelectorExpr, recv SSAValue) (s SSAValue) {
3477  	fn, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv)
3478  	if fn == nil || fn.Signature == nil {
3479  		return nil
3480  	}
3481  	methodSig := fn.Signature
3482  	var wrapperParams *Tuple
3483  	if methodSig.Params != nil && methodSig.Params.Len() > 0 {
3484  		vars := []*TCVar{:0:methodSig.Params.Len()}
3485  		for i := 0; i < methodSig.Params.Len(); i++ {
3486  			push(vars, methodSig.Params.At(i))
3487  		}
3488  		wrapperParams = NewTuple(vars...)
3489  	}
3490  	wrapperSig := NewSignature(nil, wrapperParams, methodSig.Results, methodSig.Variadic)
3491  	name := fb.fn.name | "__mval" | ssaItoa(len(fb.fn.AnonFuncs)+1)
3492  	wrapper := &SSAFunction{
3493  		name:      name,
3494  		Signature: wrapperSig,
3495  		Pkg:       fb.fn.Pkg,
3496  		Prog:      fb.fn.Prog,
3497  		parent:    fb.fn,
3498  	}
3499  	push(fb.fn.AnonFuncs, wrapper)
3500  	recvType := fixedRecv.SSAType()
3501  	fv := &SSAFreeVar{name: "recv", typ: recvType, parent: wrapper}
3502  	push(wrapper.FreeVars, fv)
3503  	if wrapperParams != nil {
3504  		for i := 0; i < wrapperParams.Len(); i++ {
3505  			v := wrapperParams.At(i)
3506  			p := &SSAParameter{name: v.Name, typ: v.Typ, parent: wrapper}
3507  			push(wrapper.Params, p)
3508  		}
3509  	}
3510  	entry := NewSSABasicBlock(wrapper, "entry")
3511  	args := []SSAValue{:0:1 + len(wrapper.Params)}
3512  	push(args, fv)
3513  	for _, p := range wrapper.Params {
3514  		push(args, p)
3515  	}
3516  	var retType Type
3517  	if methodSig.Results != nil && methodSig.Results.Len() == 1 {
3518  		retType = methodSig.Results.At(0).Typ
3519  	} else if methodSig.Results != nil && methodSig.Results.Len() > 1 {
3520  		retType = methodSig.Results
3521  	}
3522  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
3523  	call.typ = retType
3524  	call.name = "t1"
3525  	call.setBlock(entry)
3526  	push(entry.Instrs, call)
3527  	ret := &SSAReturn{}
3528  	if retType != nil {
3529  		ret.Results = []SSAValue{call}
3530  	}
3531  	ret.setBlock(entry)
3532  	push(entry.Instrs, ret)
3533  	mc := &SSAMakeClosure{Fn: wrapper, Bindings: []SSAValue{fixedRecv}}
3534  	mc.typ = wrapperSig
3535  	mc.name = fb.nextName()
3536  	fb.emit(mc)
3537  	return mc
3538  }
3539  
3540  func (fb *ssaFuncBuilder) ensureImportedSSAPackage(imported *TCPackage) (s *SSAPackage) {
3541  	impPkg := fb.fn.Prog.ImportedPackage(imported.Path)
3542  	if impPkg == nil {
3543  		impPkg = &SSAPackage{
3544  			Prog:    fb.fn.Prog,
3545  			Pkg:     imported,
3546  			Members: map[string]SSAMember{},
3547  		}
3548  		fb.fn.Prog.imported[imported.Path] = impPkg
3549  		fb.fn.Prog.packages[imported] = impPkg
3550  	}
3551  	return impPkg
3552  }
3553  
3554  func (fb *ssaFuncBuilder) buildPkgMember(pn *PkgName, memberName string) (s SSAValue) {
3555  	imported := pn.Imported
3556  	if imported == nil {
3557  		return nil
3558  	}
3559  	obj := imported.Scope.Lookup(memberName)
3560  	if obj == nil {
3561  		return nil
3562  	}
3563  	// runtime.GOOS/GOARCH and internal/goarch.GOARCH are target-dependent
3564  	// consts. Return as SSAConst so switch folding and string compare work.
3565  	if imported.Path == "runtime" || imported.Path == "internal/goarch" {
3566  		if memberName == "GOOS" {
3567  			return &SSAConst{typ: Typ[TCString], val: &ConstStr{S:compileTargetOS()}}
3568  		}
3569  		if memberName == "GOARCH" {
3570  			return &SSAConst{typ: Typ[TCString], val: &ConstStr{S:compileTargetArch()}}
3571  		}
3572  	}
3573  	switch ob := obj.(type) {
3574  	case *TCConst:
3575  		return &SSAConst{typ: ob.Typ, val: localizeConstVal(ob.Val, ob.Typ)}
3576  	case *TCVar:
3577  		impPkg := fb.ensureImportedSSAPackage(imported)
3578  		g, ok := impPkg.Members[memberName].(*SSAGlobal)
3579  		if !ok {
3580  			g = &SSAGlobal{
3581  				name: memberName,
3582  				typ:  NewPointer(ob.Typ),
3583  				pkg:  impPkg,
3584  			}
3585  			impPkg.SetMember(memberName, g)
3586  		}
3587  		return fb.emitLoad(g, ob.Typ)
3588  	case *TCFunc:
3589  		impPkg := fb.ensureImportedSSAPackage(imported)
3590  		fn := impPkg.Func(memberName)
3591  		if fn == nil {
3592  			// Materialize the imported function for use as a value; the
3593  			// direct-call path does the same lazily, but a func referenced
3594  			// as an argument never goes through it.
3595  			sig, _ := ob.Typ.(*Signature)
3596  			fn = &SSAFunction{
3597  				name:      memberName,
3598  				object:    ob,
3599  				Signature: sig,
3600  				Pkg:       impPkg,
3601  				Prog:      fb.fn.Prog,
3602  			}
3603  			if isNoContextExtern(imported.Path, memberName) {
3604  				fn.isExternC = true
3605  			}
3606  			impPkg.SetMember(memberName, fn)
3607  		}
3608  		return fn
3609  	}
3610  	return nil
3611  }
3612  
3613  func (fb *ssaFuncBuilder) buildSelectorAddr(e *syntax.SelectorExpr) (s SSAValue) {
3614  	var addr SSAValue
3615  	var structType Type
3616  	if inner, ok := e.X.(*syntax.SelectorExpr); ok {
3617  		addr = fb.buildSelectorAddr(inner)
3618  		if addr == nil {
3619  			return nil
3620  		}
3621  		structType = addr.SSAType()
3622  		if p2, ok19 := SafeUnderlying(structType).(*Pointer); ok19 {
3623  			structType = p2.Base
3624  		}
3625  		if p3, ok20 := SafeUnderlying(structType).(*Pointer); ok20 {
3626  			ld := &SSAUnOp{Op: OpMul, X: addr}
3627  			ld.typ = structType
3628  			ld.name = fb.nextName()
3629  			fb.emit(ld)
3630  			addr = ld
3631  			structType = p3.Base
3632  		}
3633  	} else if ie2, ok21 := e.X.(*syntax.IndexExpr); ok21 {
3634  		x := fb.buildExpr(ie2.X)
3635  		idx := fb.buildExpr(ie2.Index)
3636  		if x == nil || idx == nil {
3637  			return nil
3638  		}
3639  		ia := &SSAIndexAddr{X: x, Index: idx}
3640  		elemT := ssaElemType(x.SSAType())
3641  		ia.typ = NewPointer(elemT)
3642  		ia.name = fb.nextName()
3643  		fb.emit(ia)
3644  		addr = ia
3645  		structType = elemT
3646  		if _, isPtr := SafeUnderlying(elemT).(*Pointer); isPtr {
3647  			ld := fb.emitLoad(ia, elemT)
3648  			addr = ld
3649  			structType = elemT
3650  		}
3651  	} else {
3652  		x := fb.buildExpr(e.X)
3653  		if x == nil || x.SSAType() == nil {
3654  			if name2, ok22 := e.X.(*syntax.Name); ok22 {
3655  				obj := fb.lookupObject(name2.Value)
3656  				if pn2, ok23 := obj.(*PkgName); ok23 {
3657  					return fb.buildPkgMemberAddr(pn2, e.Sel.Value)
3658  				}
3659  			}
3660  			return nil
3661  		}
3662  		baseType := x.SSAType()
3663  		addr = x
3664  		if _, ok24 := SafeUnderlying(baseType).(*Pointer); !ok24 {
3665  			found := false
3666  			if name3, ok25 := e.X.(*syntax.Name); ok25 {
3667  				obj := fb.lookupObject(name3.Value)
3668  				if obj != nil {
3669  					if alloc, ok2 := fb.vars[obj]; ok2 {
3670  						addr = alloc
3671  						baseType = NewPointer(baseType)
3672  						found = true
3673  					} else if fb.freeVarPtrs != nil {
3674  						if fv2, ok26 := fb.freeVarPtrs[name3.Value]; ok26 {
3675  							addr = fv2
3676  							baseType = NewPointer(baseType)
3677  							found = true
3678  						}
3679  					}
3680  				}
3681  			}
3682  			if !found {
3683  				alloc := &SSAAlloc{Comment: "fieldaddr.tmp"}
3684  				alloc.typ = NewPointer(baseType)
3685  				alloc.name = fb.nextName()
3686  				fb.emit(alloc)
3687  				fb.emitStore(alloc, x)
3688  				addr = alloc
3689  				baseType = NewPointer(baseType)
3690  			}
3691  		}
3692  		structType = baseType
3693  		if p4, ok27 := SafeUnderlying(structType).(*Pointer); ok27 {
3694  			structType = p4.Base
3695  		}
3696  	}
3697  	fieldIdx := fb.fieldIndex(structType, e.Sel.Value)
3698  	if fieldIdx < 0 {
3699  		_ = structType
3700  	}
3701  	if fieldIdx >= 0 {
3702  		fa := &SSAFieldAddr{X: addr, Field: fieldIdx}
3703  		fa.typ = NewPointer(fb.fieldType(structType, fieldIdx))
3704  		fa.name = fb.nextName()
3705  		fb.emit(fa)
3706  		return fa
3707  	}
3708  	path := fb.findEmbeddedFieldPath(structType, e.Sel.Value)
3709  	if len(path) >= 2 {
3710  		cur := addr
3711  		curType := structType
3712  		for pi, idx := range path {
3713  			fa := &SSAFieldAddr{X: cur, Field: idx}
3714  			fa.typ = NewPointer(fb.fieldType(curType, idx))
3715  			fa.name = fb.nextName()
3716  			fb.emit(fa)
3717  			curType = fb.fieldType(curType, idx)
3718  			if pi < len(path)-1 {
3719  				if p, ok := SafeUnderlying(curType).(*Pointer); ok {
3720  					ld := &SSAUnOp{Op: OpMul, X: fa}
3721  					ld.typ = curType
3722  					ld.name = fb.nextName()
3723  					fb.emit(ld)
3724  					cur = ld
3725  					curType = p.Base
3726  					continue
3727  				}
3728  			}
3729  			cur = fa
3730  		}
3731  		return cur
3732  	}
3733  	return nil
3734  }
3735  
3736  func (fb *ssaFuncBuilder) buildIndex(e *syntax.IndexExpr) (s SSAValue) {
3737  	x := fb.buildExpr(e.X)
3738  	idx := fb.buildExpr(e.Index)
3739  	if x == nil || idx == nil {
3740  		return nil
3741  	}
3742  	if x.SSAType() == nil {
3743  		return nil
3744  	}
3745  	switch t := SafeUnderlying(x.SSAType()).(type) {
3746  	case *TCMap:
3747  		idx = fb.coerceToInterface(idx, t.Key)
3748  		l := &SSALookup{X: x, Index: idx}
3749  		l.typ = t.Elem
3750  		l.name = fb.nextName()
3751  		fb.emit(l)
3752  		return l
3753  	case *Pointer:
3754  		if arr, ok2 := SafeUnderlying(t.Base).(*Array); ok2 {
3755  			ia2 := &SSAIndexAddr{X: x, Index: idx}
3756  			ia2.typ = NewPointer(t.Base)
3757  			ia2.name = fb.nextName()
3758  			fb.emit(ia2)
3759  			return fb.emitLoad(ia2, arr.Elem)
3760  		}
3761  		et := ssaElemType(x.SSAType())
3762  		ia := &SSAIndexAddr{X: x, Index: idx}
3763  		ia.typ = NewPointer(et)
3764  		ia.name = fb.nextName()
3765  		fb.emit(ia)
3766  		return fb.emitLoad(ia, et)
3767  	default:
3768  		et := ssaElemType(x.SSAType())
3769  		ia := &SSAIndexAddr{X: x, Index: idx}
3770  		ia.typ = NewPointer(et)
3771  		ia.name = fb.nextName()
3772  		fb.emit(ia)
3773  		return fb.emitLoad(ia, et)
3774  	}
3775  }
3776  
3777  func (fb *ssaFuncBuilder) buildSlice(e *syntax.SliceExpr) (s SSAValue) {
3778  	// Slicing an addressable array must alias its storage: arr[:] passed to
3779  	// a writer mutates arr. Building the array VALUE would slice a copy.
3780  	x := fb.buildArrayAddr(e.X)
3781  	if x == nil {
3782  		x = fb.buildExpr(e.X)
3783  	}
3784  	if x == nil {
3785  		return nil
3786  	}
3787  	sl := &SSASlice{X: x}
3788  	if len(e.Index) > 0 && e.Index[0] != nil {
3789  		sl.Low = fb.buildExpr(e.Index[0])
3790  	}
3791  	if len(e.Index) > 1 && e.Index[1] != nil {
3792  		sl.High = fb.buildExpr(e.Index[1])
3793  	}
3794  	if len(e.Index) > 2 && e.Index[2] != nil {
3795  		sl.Max = fb.buildExpr(e.Index[2])
3796  	}
3797  	sl.typ = ssaSliceOf(x.SSAType())
3798  	sl.name = fb.nextName()
3799  	fb.emit(sl)
3800  	return sl
3801  }
3802  
3803  // buildArrayAddr returns the address of an addressable array-typed
3804  // expression, or nil if the expression is not an addressable array.
3805  func (fb *ssaFuncBuilder) buildArrayAddr(x syntax.Expr) (s SSAValue) {
3806  	switch ex := x.(type) {
3807  	case *syntax.ParenExpr:
3808  		return fb.buildArrayAddr(ex.X)
3809  	case *syntax.Operation:
3810  		if ex.Y == nil && ex.Op == token.Mul {
3811  			// (*p)[low:high] - p already points at the array
3812  			p := fb.buildExpr(ex.X)
3813  			if p != nil {
3814  				if pt, ok := SafeUnderlying(p.SSAType()).(*Pointer); ok && pt.Base != nil {
3815  					if _, isArr := SafeUnderlying(pt.Base).(*Array); isArr {
3816  						return p
3817  					}
3818  				}
3819  			}
3820  		}
3821  	case *syntax.Name:
3822  		obj := fb.lookupObject(ex.Value)
3823  		if obj == nil || ObjectType(obj) == nil {
3824  			return nil
3825  		}
3826  		if _, isArr := SafeUnderlying(ObjectType(obj)).(*Array); !isArr {
3827  			return nil
3828  		}
3829  		if alloc, ok := fb.vars[obj]; ok {
3830  			return alloc
3831  		}
3832  		if fv, ok := fb.freeVarPtrs[ex.Value]; ok {
3833  			return fv
3834  		}
3835  		if fb.fn.Pkg != nil {
3836  			if g, ok := fb.fn.Pkg.Members[ex.Value].(*SSAGlobal); ok {
3837  				return g
3838  			}
3839  		}
3840  	case *syntax.SelectorExpr:
3841  		// Skip package selectors: pkg.Name is not a field access.
3842  		if name, ok := ex.X.(*syntax.Name); ok {
3843  			if _, isPkg := fb.lookupObject(name.Value).(*PkgName); isPkg {
3844  				return nil
3845  			}
3846  		}
3847  		addr := fb.buildSelectorAddr(ex)
3848  		if addr == nil {
3849  			return nil
3850  		}
3851  		if pt, ok := SafeUnderlying(addr.SSAType()).(*Pointer); ok && pt.Base != nil {
3852  			if _, isArr := SafeUnderlying(pt.Base).(*Array); isArr {
3853  				return addr
3854  			}
3855  		}
3856  		// Not an array field: the stray field-addr GEP is dead code.
3857  		return nil
3858  	case *syntax.IndexExpr:
3859  		var base SSAValue
3860  		if sel, ok2 := ex.X.(*syntax.SelectorExpr); ok2 {
3861  			base = fb.buildSelectorAddr(sel)
3862  		}
3863  		if base == nil {
3864  			base = fb.buildArrayAddr(ex.X)
3865  		}
3866  		if base == nil {
3867  			base = fb.buildExpr(ex.X)
3868  		}
3869  		if base == nil {
3870  			return nil
3871  		}
3872  		bt := base.SSAType()
3873  		if pt, ok := SafeUnderlying(bt).(*Pointer); ok && pt.Base != nil {
3874  			bt = pt.Base
3875  		}
3876  		elem := ssaElemType(bt)
3877  		if elem == nil {
3878  			return nil
3879  		}
3880  		if _, isArr := SafeUnderlying(elem).(*Array); !isArr {
3881  			return nil
3882  		}
3883  		idx := fb.buildExpr(ex.Index)
3884  		if idx == nil {
3885  			return nil
3886  		}
3887  		ia := &SSAIndexAddr{X: base, Index: idx}
3888  		ia.typ = NewPointer(elem)
3889  		ia.name = fb.nextName()
3890  		fb.emit(ia)
3891  		return ia
3892  	}
3893  	return nil
3894  }
3895  
3896  func (fb *ssaFuncBuilder) buildAssert(e *syntax.AssertExpr) (s SSAValue) {
3897  	x := fb.buildExpr(e.X)
3898  	assertedType := fb.resolveType(e.Type)
3899  	if x == nil {
3900  		return nil
3901  	}
3902  	ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: false}
3903  	ta.typ = assertedType
3904  	ta.name = fb.nextName()
3905  	fb.emit(ta)
3906  	return ta
3907  }
3908  
3909  func (fb *ssaFuncBuilder) buildCompositeLit(e *syntax.CompositeLit) (s SSAValue) {
3910  	var typ Type
3911  	if e.Type != nil {
3912  		typ = fb.resolveType(e.Type)
3913  	}
3914  	if typ == nil {
3915  		return nil
3916  	}
3917  
3918  	if sl, ok := SafeUnderlying(typ).(*Slice); ok {
3919  		return fb.buildSliceLit(e, typ, sl)
3920  	}
3921  
3922  	if mt, isMap := SafeUnderlying(typ).(*TCMap); isMap {
3923  		mm := &SSAMakeMap{}
3924  		mm.typ = typ
3925  		mm.name = fb.nextName()
3926  		fb.emit(mm)
3927  		for _, el := range e.ElemList {
3928  			if kv, ok := el.(*syntax.KeyValueExpr); ok {
3929  				k := fb.buildExpr(kv.Key)
3930  				v := fb.buildExpr(kv.Value)
3931  				if k != nil && v != nil {
3932  					k = fb.coerceToInterface(k, mt.Key)
3933  					v = fb.coerceToInterface(v, mt.Elem)
3934  					fb.emit(&SSAMapUpdate{Map: mm, Key: k, Value: v})
3935  				}
3936  			}
3937  		}
3938  		return mm
3939  	}
3940  
3941  	if ar, isArr := SafeUnderlying(typ).(*Array); isArr {
3942  		return fb.buildArrayLit(e, typ, ar)
3943  	}
3944  
3945  	alloc := fb.emitAlloc(typ, 0)
3946  	posIdx := 0
3947  	for _, el := range e.ElemList {
3948  		if kv, ok := el.(*syntax.KeyValueExpr); ok {
3949  			if _, ok2 := SafeUnderlying(typ).(*TCStruct); ok2 {
3950  				idx := fb.fieldIndex(typ, kv.Key.(*syntax.Name).Value)
3951  				if idx >= 0 {
3952  					fa := &SSAFieldAddr{X: alloc, Field: idx}
3953  					ft := fb.fieldType(typ, idx)
3954  					fa.typ = NewPointer(ft)
3955  					fa.name = fb.nextName()
3956  					fb.emit(fa)
3957  					v := fb.buildExpr(kv.Value)
3958  					if v != nil {
3959  						v = fb.coerceToInterface(v, ft)
3960  						fb.emitStore(fa, v)
3961  					}
3962  				}
3963  			}
3964  		} else {
3965  			v := fb.buildExpr(el)
3966  			if v != nil {
3967  				if _, ok2 := SafeUnderlying(typ).(*TCStruct); ok2 {
3968  					ft := fb.fieldType(typ, posIdx)
3969  					fa := &SSAFieldAddr{X: alloc, Field: posIdx}
3970  					fa.typ = NewPointer(ft)
3971  					fa.name = fb.nextName()
3972  					fb.emit(fa)
3973  					v = fb.coerceToInterface(v, ft)
3974  					fb.emitStore(fa, v)
3975  				}
3976  			}
3977  			posIdx++
3978  		}
3979  	}
3980  	return fb.emitLoad(alloc, typ)
3981  }
3982  
3983  func (fb *ssaFuncBuilder) buildArrayLit(e *syntax.CompositeLit, typ Type, ar *Array) (s SSAValue) {
3984  	if ar.Len < 0 {
3985  		ar = NewArray(ar.Elem, int64(len(e.ElemList)))
3986  		typ = ar
3987  	}
3988  	alloc := fb.emitAlloc(typ, 0)
3989  	elemTyp := ar.Elem
3990  	for i, el := range e.ElemList {
3991  		var expr syntax.Expr
3992  		if kv, ok := el.(*syntax.KeyValueExpr); ok {
3993  			expr = kv.Value
3994  		} else {
3995  			expr = el
3996  		}
3997  		var v SSAValue
3998  		if cl, ok := expr.(*syntax.CompositeLit); ok && cl.Type == nil {
3999  			v = fb.buildCompositeLitWithType(cl, elemTyp)
4000  		} else {
4001  			v = fb.buildExpr(expr)
4002  		}
4003  		if v == nil {
4004  			continue
4005  		}
4006  		idx := &SSAConst{typ: Typ[Int32], val: &ConstInt{V:int64(i)}}
4007  		ia := &SSAIndexAddr{X: alloc, Index: idx}
4008  		ia.typ = NewPointer(elemTyp)
4009  		ia.name = fb.nextName()
4010  		fb.emit(ia)
4011  		v = fb.coerceToInterface(v, elemTyp)
4012  		fb.emitStore(ia, v)
4013  	}
4014  	return fb.emitLoad(alloc, typ)
4015  }
4016  
4017  func (fb *ssaFuncBuilder) buildCompositeLitWithType(e *syntax.CompositeLit, typ Type) (s SSAValue) {
4018  	if sl, ok := SafeUnderlying(typ).(*Slice); ok {
4019  		return fb.buildSliceLit(e, typ, sl)
4020  	}
4021  	if ar, isArr := SafeUnderlying(typ).(*Array); isArr {
4022  		return fb.buildArrayLit(e, typ, ar)
4023  	}
4024  	alloc := fb.emitAlloc(typ, 0)
4025  	posIdx := 0
4026  	for _, el := range e.ElemList {
4027  		if kv, ok := el.(*syntax.KeyValueExpr); ok {
4028  			if _, ok2 := SafeUnderlying(typ).(*TCStruct); ok2 {
4029  				idx := fb.fieldIndex(typ, kv.Key.(*syntax.Name).Value)
4030  				if idx >= 0 {
4031  					ft := fb.fieldType(typ, idx)
4032  					fa := &SSAFieldAddr{X: alloc, Field: idx}
4033  					fa.typ = NewPointer(ft)
4034  					fa.name = fb.nextName()
4035  					fb.emit(fa)
4036  					v := fb.buildExpr(kv.Value)
4037  					if v != nil {
4038  						v = fb.coerceToInterface(v, ft)
4039  						fb.emitStore(fa, v)
4040  					}
4041  				}
4042  			}
4043  		} else {
4044  			v := fb.buildExpr(el)
4045  			if v != nil {
4046  				if _, ok2 := SafeUnderlying(typ).(*TCStruct); ok2 {
4047  					ft := fb.fieldType(typ, posIdx)
4048  					fa := &SSAFieldAddr{X: alloc, Field: posIdx}
4049  					fa.typ = NewPointer(ft)
4050  					fa.name = fb.nextName()
4051  					fb.emit(fa)
4052  					v = fb.coerceToInterface(v, ft)
4053  					fb.emitStore(fa, v)
4054  				}
4055  			}
4056  			posIdx++
4057  		}
4058  	}
4059  	return fb.emitLoad(alloc, typ)
4060  }
4061  
4062  func (fb *ssaFuncBuilder) buildSliceLit(e *syntax.CompositeLit, typ Type, sl *Slice) (s SSAValue) {
4063  	n := len(e.ElemList)
4064  	nVal := &SSAConst{typ: Typ[Int32], val: &ConstInt{V:int64(n)}}
4065  	ms := &SSAMakeSlice{}
4066  	ms.typ = typ
4067  	ms.name = fb.nextName()
4068  	ms.Len = nVal
4069  	ms.Cap = nVal
4070  	fb.emit(ms)
4071  
4072  	elemTyp := sl.Elem
4073  	for i, el := range e.ElemList {
4074  		var expr syntax.Expr
4075  		if kv, ok := el.(*syntax.KeyValueExpr); ok {
4076  			expr = kv.Value
4077  		} else {
4078  			expr = el
4079  		}
4080  		var v SSAValue
4081  		if cl, ok := expr.(*syntax.CompositeLit); ok && cl.Type == nil {
4082  			v = fb.buildCompositeLitWithType(cl, elemTyp)
4083  		} else {
4084  			v = fb.buildExpr(expr)
4085  		}
4086  		if v == nil {
4087  			continue
4088  		}
4089  		idx := &SSAConst{typ: Typ[Int32], val: &ConstInt{V:int64(i)}}
4090  		ia := &SSAIndexAddr{X: ms, Index: idx}
4091  		ia.typ = NewPointer(elemTyp)
4092  		ia.name = fb.nextName()
4093  		fb.emit(ia)
4094  		v = fb.coerceToInterface(v, elemTyp)
4095  		fb.emitStore(ia, v)
4096  	}
4097  	return ms
4098  }
4099  
4100  func (fb *ssaFuncBuilder) buildFuncLit(e *syntax.FuncLit) (s SSAValue) {
4101  	var sig *Signature
4102  	if fb.info != nil {
4103  		if tv, ok := fb.info.Types[e]; ok {
4104  			sig, _ = tv.Type.(*Signature)
4105  		}
4106  	}
4107  	if sig == nil && e.Type != nil {
4108  		sig = tcResolveFuncInline(e.Type, fb.fn.Pkg.Pkg.Scope)
4109  	}
4110  	name := fb.fn.name | "__anon" | ssaItoa(len(fb.fn.AnonFuncs)+1)
4111  	anon := &SSAFunction{
4112  		name:      name,
4113  		Signature: sig,
4114  		pos:       0,
4115  		Pkg:       fb.fn.Pkg,
4116  		Prog:      fb.fn.Prog,
4117  		parent:    fb.fn,
4118  	}
4119  	push(fb.fn.AnonFuncs, anon)
4120  
4121  	ab := newSSAFuncBuilder(anon, fb.info)
4122  	ab.parent = fb
4123  	// Closures inside monomorphized bodies need the same generic context as
4124  	// their parent, or calls to source-package functions silently vanish.
4125  	ab.typeSubst = fb.typeSubst
4126  	ab.srcScope = fb.srcScope
4127  	ab.fileScope = fb.fileScope
4128  	d := &syntax.FuncDecl{
4129  		Name: &syntax.Name{Value: name},
4130  		Type: e.Type,
4131  		Body: e.Body,
4132  	}
4133  	ab.buildBody(d)
4134  
4135  	if len(anon.FreeVars) == 0 {
4136  		mc0 := &SSAMakeClosure{Fn: anon}
4137  		mc0.typ = sig
4138  		mc0.name = fb.nextName()
4139  		fb.emit(mc0)
4140  		return mc0
4141  	}
4142  	bindings := []SSAValue{:0:len(anon.FreeVars)}
4143  	for _, fv := range anon.FreeVars {
4144  		obj := fb.lookupObject(fv.name)
4145  		if obj != nil {
4146  			if alloc, ok := fb.vars[obj]; ok {
4147  				alloc.Heap = true
4148  				push(bindings, alloc)
4149  			} else if pfv2, ok28 := fb.freeVarPtrs[fv.name]; ok28 {
4150  				push(bindings, pfv2)
4151  			} else {
4152  				push(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
4153  			}
4154  		} else if pfv, ok := fb.freeVarPtrs[fv.name]; ok {
4155  			push(bindings, pfv)
4156  		} else {
4157  			push(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
4158  		}
4159  	}
4160  	mc := &SSAMakeClosure{Fn: anon, Bindings: bindings}
4161  	mc.typ = sig
4162  	mc.name = fb.nextName()
4163  	fb.emit(mc)
4164  	return mc
4165  }
4166  
4167  func (fb *ssaFuncBuilder) saveVars() (m map[Object]*SSAAlloc) {
4168  	saved := map[Object]*SSAAlloc{}
4169  	for k, v := range fb.vars {
4170  		saved[k] = v
4171  	}
4172  	return saved
4173  }
4174  
4175  func (fb *ssaFuncBuilder) removeVar(name string) {
4176  	// Delete ALL matching Objects. A map iteration would be nondeterministic
4177  	// if multiple Objects share the same name (scope shadowing), so collect
4178  	// matches first, then delete.
4179  	var matches []Object
4180  	for o := range fb.vars {
4181  		if ObjectName(o) == name {
4182  			push(matches, o)
4183  		}
4184  	}
4185  	for _, o := range matches {
4186  		delete(fb.vars, o)
4187  	}
4188  }
4189  
4190  
4191  func (fb *ssaFuncBuilder) buildPkgMemberAddr(pn *PkgName, memberName string) (s SSAValue) {
4192  	imported := pn.Imported
4193  	if imported == nil {
4194  		return nil
4195  	}
4196  	obj := imported.Scope.Lookup(memberName)
4197  	if obj == nil {
4198  		return nil
4199  	}
4200  	switch ob := obj.(type) {
4201  	case *TCConst:
4202  		return nil
4203  	case *TCVar:
4204  		impPkg := fb.ensureImportedSSAPackage(imported)
4205  		g, ok := impPkg.Members[memberName].(*SSAGlobal)
4206  		if !ok {
4207  			g = &SSAGlobal{
4208  				name: memberName,
4209  				typ:  NewPointer(ob.Typ),
4210  				pkg:  impPkg,
4211  			}
4212  			impPkg.SetMember(memberName, g)
4213  		}
4214  		return g
4215  	}
4216  	return nil
4217  }
4218  
4219  func (fb *ssaFuncBuilder) buildPkgCall(pn *PkgName, funcName string, argList []syntax.Expr, hasDots bool) (s SSAValue) {
4220  	imported := pn.Imported
4221  	if imported == nil {
4222  		return nil
4223  	}
4224  	if imported.Path == "unsafe" && (funcName == "Slice" || funcName == "String") {
4225  		// string and []byte are the same type: unsafe.String(ptr, len) is
4226  		// unsafe.Slice with a byte element, which already yields string.
4227  		return fb.buildUnsafeSlice(argList)
4228  	}
4229  	if imported.Path == "unsafe" && (funcName == "SliceData" || funcName == "StringData") {
4230  		arg := fb.buildExpr(argList[0])
4231  		extract := &SSAExtract{Tuple: arg, Index: 0}
4232  		extract.typ = Typ[UnsafePointer]
4233  		extract.name = fb.nextName()
4234  		extract.setBlock(fb.currentBlock)
4235  		push(fb.currentBlock.Instrs, extract)
4236  		return extract
4237  	}
4238  	if imported.Path == "unsafe" && funcName == "Add" {
4239  		if len(argList) != 2 {
4240  			return nil
4241  		}
4242  		ptr := fb.buildExpr(argList[0])
4243  		offset := fb.buildExpr(argList[1])
4244  		idx := &SSAIndexAddr{X: ptr, Index: offset}
4245  		idx.typ = NewPointer(Typ[Uint8])
4246  		idx.name = fb.nextName()
4247  		idx.setBlock(fb.currentBlock)
4248  		push(fb.currentBlock.Instrs, idx)
4249  		return idx
4250  	}
4251  	if imported.Path == "unsafe" && funcName == "Sizeof" {
4252  		sz := int64(8)
4253  		if len(argList) == 1 {
4254  			arg := fb.buildExpr(argList[0])
4255  			if arg != nil && arg.SSAType() != nil {
4256  				sz = ssaSizeofType(arg.SSAType())
4257  			}
4258  		}
4259  		return NewSSAConst(&ConstInt{V:sz}, Typ[Int64])
4260  	}
4261  	if imported.Path == "unsafe" && funcName == "Alignof" {
4262  		return NewSSAConst(&ConstInt{V:8}, Typ[Int64])
4263  	}
4264  	if imported.Path == "unsafe" && funcName == "Offsetof" {
4265  		return NewSSAConst(&ConstInt{V:0}, Typ[Int64])
4266  	}
4267  	if result, handled := fb.tryGenericPkgCall(pn, funcName, argList, hasDots); handled {
4268  		return result
4269  	}
4270  	obj := imported.Scope.Lookup(funcName)
4271  	if obj == nil {
4272  		// Fail loud: a dropped call compiles the caller to garbage
4273  		// (zeroinitializer returns) and crashes far from the cause.
4274  		push(cctx.compileErrors,
4275  			"undefined: "|imported.Path|"."|funcName|" (called from "|fb.fn.name|")")
4276  		return nil
4277  	}
4278  	fn, ok := obj.(*TCFunc)
4279  	if !ok {
4280  		return nil
4281  	}
4282  	impPkg := fb.ensureImportedSSAPackage(imported)
4283  	ssaFn := impPkg.Func(funcName)
4284  	if ssaFn == nil {
4285  		ssaFn = &SSAFunction{
4286  			name:      funcName,
4287  			object:    fn,
4288  			Signature: fn.Typ.(*Signature),
4289  			Pkg:       impPkg,
4290  			Prog:      fb.fn.Prog,
4291  		}
4292  		if isNoContextExtern(imported.Path, funcName) {
4293  			ssaFn.isExternC = true
4294  		}
4295  		impPkg.SetMember(funcName, ssaFn)
4296  	}
4297  	args := fb.buildArgs(argList)
4298  	var retType Type
4299  	if ssaFn.Signature != nil {
4300  		if ssaFn.Signature.Variadic && !hasDots {
4301  			args = fb.wrapVariadicArgs(args, ssaFn.Signature)
4302  		}
4303  		args = fb.coerceArgsToInterface(args, ssaFn.Signature)
4304  		if ssaFn.Signature.Results != nil && ssaFn.Signature.Results.Len() == 1 {
4305  			retType = ssaFn.Signature.Results.At(0).Typ
4306  		} else if ssaFn.Signature.Results != nil && ssaFn.Signature.Results.Len() > 1 {
4307  			retType = ssaFn.Signature.Results
4308  		}
4309  	}
4310  	call := &SSACall{Call: SSACallCommon{Value: ssaFn, Args: args}}
4311  	call.typ = retType
4312  	call.name = fb.nextName()
4313  	fb.emit(call)
4314  	if retType == nil {
4315  		return nil
4316  	}
4317  	return call
4318  }
4319  
4320  func (fb *ssaFuncBuilder) buildUnsafeSlice(argList []syntax.Expr) (s SSAValue) {
4321  	if len(argList) < 2 {
4322  		return nil
4323  	}
4324  	ptrVal := fb.buildExpr(argList[0])
4325  	lenVal := fb.buildExpr(argList[1])
4326  	if ptrVal == nil || lenVal == nil {
4327  		return nil
4328  	}
4329  	var elemType Type
4330  	if pt, ok := SafeUnderlying(ptrVal.SSAType()).(*Pointer); ok {
4331  		elemType = pt.Base
4332  	}
4333  	if elemType == nil {
4334  		elemType = Typ[Uint8]
4335  	}
4336  	ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal, Data: ptrVal}
4337  	if b, ok := elemType.(*Basic); ok && b.Kind == Uint8 {
4338  		ms.typ = Typ[TCString]
4339  	} else {
4340  		ms.typ = NewSlice(elemType)
4341  	}
4342  	ms.name = fb.nextName()
4343  	fb.emit(ms)
4344  	return ms
4345  }
4346  
4347  // Helpers.
4348  
4349  func (fb *ssaFuncBuilder) lookupObject(name string) (o Object) {
4350  	for obj := range fb.vars {
4351  		if ObjectName(obj) == name {
4352  			return obj
4353  		}
4354  	}
4355  	if fb.parent != nil {
4356  		for obj := range fb.parent.vars {
4357  			if ObjectName(obj) == name {
4358  				return obj
4359  			}
4360  		}
4361  	}
4362  	if fb.srcScope != nil {
4363  		if _, obj := fb.srcScope.LookupParent(name); obj != nil {
4364  			return obj
4365  		}
4366  	}
4367  	if fb.fileScope != nil {
4368  		if _, obj := fb.fileScope.LookupParent(name); obj != nil {
4369  			return obj
4370  		}
4371  	}
4372  	if fb.fn.Pkg != nil {
4373  		if _, obj := fb.fn.Pkg.Pkg.Scope.LookupParent(name); obj != nil {
4374  			return obj
4375  		}
4376  	}
4377  	if fb.info != nil {
4378  		return nil
4379  	}
4380  	return nil
4381  }
4382  
4383  func (fb *ssaFuncBuilder) getOrCreateFreeVar(name string, typ Type) (s SSAValue) {
4384  	for _, fv2 := range fb.fn.FreeVars {
4385  		if fv2.name == name {
4386  			return fv2
4387  		}
4388  	}
4389  	fv := &SSAFreeVar{
4390  		name:   name,
4391  		typ:    typ,
4392  		parent: fb.fn,
4393  	}
4394  	push(fb.fn.FreeVars, fv)
4395  	if fb.freeVarPtrs == nil {
4396  		fb.freeVarPtrs = map[string]*SSAFreeVar{}
4397  	}
4398  	fb.freeVarPtrs[name] = fv
4399  	return fv
4400  }
4401  
4402  func (fb *ssaFuncBuilder) lookupVar(name string) (t *TCVar) {
4403  	obj := fb.lookupObject(name)
4404  	v, _ := obj.(*TCVar)
4405  	return v
4406  }
4407  
4408  // derefValueRecv loads the receiver through the pointer when a value-receiver
4409  // method is called on a pointer: the definition takes the receiver by value
4410  // (an LLVM aggregate), so passing the raw pointer reinterprets pointer bits
4411  // as field data.
4412  func (fb *ssaFuncBuilder) derefValueRecv(fn *SSAFunction, recv SSAValue) (s SSAValue) {
4413  	if fn == nil || recv == nil || fn.Signature == nil || fn.Signature.Recv == nil {
4414  		return recv
4415  	}
4416  	// All receivers are ptr in Moxie. If the Signature says value receiver
4417  	// and the caller has a pointer, pass it through (already ptr).
4418  	// If the caller has a value, take its address.
4419  	if _, recvIsPtr := SafeUnderlying(fn.Signature.Recv.Typ).(*Pointer); recvIsPtr {
4420  		return recv
4421  	}
4422  	// Source-level value receiver - function now expects ptr.
4423  	// If recv is already a pointer, pass through.
4424  	if _, ok := SafeUnderlying(recv.SSAType()).(*Pointer); ok {
4425  		return recv
4426  	}
4427  	// recv is a value - take its address by storing to an alloca.
4428  	alloc := fb.emitAlloc(recv.SSAType(), 0)
4429  	fb.emitStore(alloc, recv)
4430  	return alloc
4431  }
4432  
4433  func (fb *ssaFuncBuilder) resolveMethodCallWithRecv(sel *syntax.SelectorExpr, recv SSAValue) (rfn *SSAFunction, rrecv SSAValue) {
4434  	typ := recv.SSAType()
4435  	if typ == nil {
4436  		return nil, nil
4437  	}
4438  	isPtr := false
4439  	if p5, ok35 := SafeUnderlying(typ).(*Pointer); ok35 {
4440  		typ = p5.Base
4441  		isPtr = true
4442  	}
4443  	if _, ok36 := SafeUnderlying(typ).(*TCInterface); ok36 {
4444  		if named2, ok37 := typ.(*Named); !ok37 || named2.NumMethods() == 0 {
4445  			return nil, nil
4446  		}
4447  	}
4448  	// Handle Basic types (builtin stringers in runtime package)
4449  	if basic, ok38 := typ.(*Basic); ok38 {
4450  		typeName2 := "(*" | basic.Name | ")"
4451  		mangledName2 := typeName2 | "." | sel.Sel.Value
4452  		extSym := "runtime." | mangledName2
4453  		for i := int32(0); i < basic.NumMethods(); i++ {
4454  			m := basic.Method(i)
4455  			if m.Name == sel.Sel.Value {
4456  				fn3 := fb.fn.Pkg.ExternalFunc(mangledName2, m.Signature())
4457  				fn3.externalSymbol = extSym
4458  				return fn3, recv
4459  			}
4460  		}
4461  		resolved := UntypedToTyped(basic)
4462  		if resolved == nil {
4463  			return nil, nil
4464  		}
4465  		switch rt := resolved.(type) {
4466  		case *Basic:
4467  			typeName2 = "(*" | rt.Name | ")"
4468  			mangledName2 = typeName2 | "." | sel.Sel.Value
4469  			extSym = "runtime." | mangledName2
4470  			for i := int32(0); i < rt.NumMethods(); i++ {
4471  				m := rt.Method(i)
4472  				if m.Name == sel.Sel.Value {
4473  					fn4 := fb.fn.Pkg.ExternalFunc(mangledName2, m.Signature())
4474  					fn4.externalSymbol = extSym
4475  					return fn4, recv
4476  				}
4477  			}
4478  			return nil, nil
4479  		case *Named:
4480  			typ = rt
4481  		default:
4482  			return nil, nil
4483  		}
4484  	}
4485  	named, ok := typ.(*Named)
4486  	if !ok {
4487  		return nil, nil
4488  	}
4489  	typeName := ""
4490  	if named.Obj != nil {
4491  		typeName = named.Obj.Name
4492  	}
4493  	if typeName == "" {
4494  		return nil, nil
4495  	}
4496  	resolveNamed := named
4497  	if resolveNamed.NumMethods() == 0 {
4498  		// The Named type from typeSubst may be a bare copy without methods.
4499  		// Look up the canonical type in cctx.universe.Registry which has methods
4500  		// attached from mxh loading.
4501  		if resolveNamed.Obj != nil && resolveNamed.Obj.Pkg != nil {
4502  			pkgPath := resolveNamed.Obj.Pkg.Path
4503  			nm := resolveNamed.Obj.Name
4504  			if cctx.universe.Registry != nil {
4505  				if pkg := cctx.universe.Registry[pkgPath]; pkg != nil && pkg.Scope != nil {
4506  					if obj := pkg.Scope.Lookup(nm); obj != nil {
4507  						if regNamed, ok39 := ObjectType(obj).(*Named); ok39 && regNamed.NumMethods() > 0 {
4508  							resolveNamed = regNamed
4509  							typeName = nm
4510  						}
4511  					}
4512  				}
4513  			}
4514  		}
4515  		if resolveNamed.NumMethods() == 0 {
4516  			cur := Type(resolveNamed)
4517  			for depth := 0; depth < 10; depth++ {
4518  				n2, ok40 := cur.(*Named)
4519  				if !ok40 || n2 == nil { break }
4520  				if n2.NumMethods() > 0 {
4521  					resolveNamed = n2
4522  					if n2.Obj != nil && n2.Obj.Name != "" {
4523  						typeName = n2.Obj.Name
4524  					}
4525  					break
4526  				}
4527  				raw := n2.Under
4528  				if raw == nil || raw == cur { break }
4529  				cur = raw
4530  			}
4531  		}
4532  	}
4533  	namedPkgPath := ""
4534  	if resolveNamed.Obj != nil && resolveNamed.Obj.Pkg != nil {
4535  		namedPkgPath = resolveNamed.Obj.Pkg.Path
4536  	}
4537  	// All methods use (*Type).Method naming regardless of receiver type.
4538  	recvName := "(*" | typeName | ")"
4539  	samePackage := namedPkgPath != "" && namedPkgPath == fb.fn.Pkg.Pkg.Path
4540  	mangledName := recvName | "." | sel.Sel.Value
4541  	if !samePackage && namedPkgPath != "" {
4542  		mangledName = namedPkgPath | "." | recvName | "." | sel.Sel.Value
4543  	}
4544  	var fn *SSAFunction
4545  	if samePackage {
4546  		fn, _ = fb.fn.Pkg.Members[mangledName].(*SSAFunction)
4547  	}
4548  	if fn == nil {
4549  		for i := 0; i < resolveNamed.NumMethods(); i++ {
4550  			m := resolveNamed.Method(i)
4551  			if m.Name == sel.Sel.Value {
4552  				if !samePackage && namedPkgPath != "" {
4553  					// Imported method: register in the imported package so the
4554  					// emitter uses the moxie convention (value receivers passed
4555  					// by value, trailing ctx param). The externalSymbol path is
4556  					// C-export ABI and drops the ctx argument.
4557  					impPkg := fb.ensureImportedSSAPackage(resolveNamed.Obj.Pkg)
4558  					fn = impPkg.ExternalFunc(recvName|"."|sel.Sel.Value, m.Signature())
4559  				} else {
4560  					fn = fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
4561  					if resolveNamed.Obj != nil && resolveNamed.Obj.Pkg == nil {
4562  						fn.externalSymbol = "runtime." | mangledName
4563  					}
4564  				}
4565  				break
4566  			}
4567  		}
4568  	}
4569  	if fn != nil {
4570  		if fn.Signature != nil && fn.Signature.Recv != nil {
4571  			recvParam := fn.Signature.Recv
4572  			_, recvIsPtr := SafeUnderlying(recvParam.Typ).(*Pointer)
4573  			if recvIsPtr && !isPtr {
4574  				if nameExpr, ok41 := sel.X.(*syntax.Name); ok41 {
4575  					obj := fb.lookupObject(nameExpr.Value)
4576  					if obj != nil {
4577  						if alloc, ok3 := fb.vars[obj]; ok3 {
4578  							recv = alloc
4579  						}
4580  					}
4581  				} else if innerSel, ok42 := sel.X.(*syntax.SelectorExpr); ok42 {
4582  					addr := fb.buildSelectorAddr(innerSel)
4583  					if addr != nil {
4584  						recv = addr
4585  					}
4586  				}
4587  			}
4588  		}
4589  		return fn, recv
4590  	}
4591  	st, ok2 := SafeUnderlying(named).(*TCStruct)
4592  	if !ok2 {
4593  		return nil, nil
4594  	}
4595  	if !isPtr {
4596  		fixed := false
4597  		if innerSel, ok3 := sel.X.(*syntax.SelectorExpr); ok3 {
4598  			addr := fb.buildSelectorAddr(innerSel)
4599  			if addr != nil {
4600  				recv = addr
4601  				fixed = true
4602  			}
4603  		}
4604  		if !fixed {
4605  			if nameExpr, ok3 := sel.X.(*syntax.Name); ok3 {
4606  				obj := fb.lookupObject(nameExpr.Value)
4607  				if obj != nil {
4608  					if a, ok4 := fb.vars[obj]; ok4 {
4609  						recv = a
4610  						fixed = true
4611  					}
4612  				}
4613  			}
4614  		}
4615  		if !fixed {
4616  			alloc := &SSAAlloc{}
4617  			alloc.typ = NewPointer(recv.SSAType())
4618  			alloc.name = fb.nextName()
4619  			fb.emit(alloc)
4620  			storeOp := &SSAStore{Addr: alloc, Val: recv}
4621  			fb.emit(storeOp)
4622  			recv = alloc
4623  		}
4624  	}
4625  	for i := 0; i < st.NumFields(); i++ {
4626  		f := st.Field(i)
4627  		if !f.Anonymous {
4628  			continue
4629  		}
4630  		embedType := f.Typ
4631  		embedNamed, ok3 := embedType.(*Named)
4632  		if !ok3 {
4633  			if p, ok4 := embedType.(*Pointer); ok4 {
4634  				embedNamed, ok3 = p.Base.(*Named)
4635  			}
4636  		}
4637  		if !ok3 || embedNamed.Obj == nil {
4638  			continue
4639  		}
4640  		embedName := "(*" | embedNamed.Obj.Name | ")"
4641  		embedSamePkg := embedNamed.Obj.Pkg != nil && embedNamed.Obj.Pkg.Path == fb.fn.Pkg.Pkg.Path
4642  		embedMangledName := embedName | "." | sel.Sel.Value
4643  		if !embedSamePkg && embedNamed.Obj.Pkg != nil {
4644  			embedMangledName = embedNamed.Obj.Pkg.Path | "." | embedName | "." | sel.Sel.Value
4645  		}
4646  		var embedFn *SSAFunction
4647  		if embedSamePkg {
4648  			embedFn, _ = fb.fn.Pkg.Members[embedMangledName].(*SSAFunction)
4649  		}
4650  		if embedFn == nil {
4651  			for mi := int32(0); mi < int32(embedNamed.NumMethods()); mi++ {
4652  				m := embedNamed.Method(int32(mi))
4653  				if m.Name == sel.Sel.Value {
4654  					if !embedSamePkg && embedNamed.Obj.Pkg != nil {
4655  						impPkg := fb.ensureImportedSSAPackage(embedNamed.Obj.Pkg)
4656  						embedFn = impPkg.ExternalFunc(embedName|"."|sel.Sel.Value, m.Signature())
4657  					} else {
4658  						embedFn = fb.fn.Pkg.ExternalFunc(embedMangledName, m.Signature())
4659  					}
4660  					break
4661  				}
4662  			}
4663  		}
4664  		if embedFn != nil {
4665  			fieldAddr := &SSAFieldAddr{
4666  				X:     recv,
4667  				Field: i,
4668  			}
4669  			fieldAddr.typ = NewPointer(embedType)
4670  			fieldAddr.name = fb.nextName()
4671  			fb.emit(fieldAddr)
4672  			var embedRecv SSAValue = fieldAddr
4673  			if _, isEmbedPtr := SafeUnderlying(embedType).(*Pointer); isEmbedPtr {
4674  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
4675  				ld.typ = embedType
4676  				ld.name = fb.nextName()
4677  				fb.emit(ld)
4678  				embedRecv = ld
4679  			}
4680  			return embedFn, embedRecv
4681  		}
4682  		embedSt, ok5 := SafeUnderlying(embedNamed).(*TCStruct)
4683  		if !ok5 {
4684  			continue
4685  		}
4686  		for j := 0; j < embedSt.NumFields(); j++ {
4687  			f2 := embedSt.Field(j)
4688  			if !f2.Anonymous {
4689  				continue
4690  			}
4691  			embed2Type := f2.Typ
4692  			embed2Named, ok6 := embed2Type.(*Named)
4693  			if !ok6 {
4694  				if p2, ok7 := embed2Type.(*Pointer); ok7 {
4695  					embed2Named, ok6 = p2.Base.(*Named)
4696  				}
4697  			}
4698  			if !ok6 || embed2Named.Obj == nil {
4699  				continue
4700  			}
4701  			embed2Name := "(*" | embed2Named.Obj.Name | ")"
4702  			embed2SamePkg := embed2Named.Obj.Pkg != nil && embed2Named.Obj.Pkg.Path == fb.fn.Pkg.Pkg.Path
4703  			embed2Mangled := embed2Name | "." | sel.Sel.Value
4704  			if !embed2SamePkg && embed2Named.Obj.Pkg != nil {
4705  				embed2Mangled = embed2Named.Obj.Pkg.Path | "." | embed2Name | "." | sel.Sel.Value
4706  			}
4707  			var embed2Fn *SSAFunction
4708  			if embed2SamePkg {
4709  				embed2Fn, _ = fb.fn.Pkg.Members[embed2Mangled].(*SSAFunction)
4710  			}
4711  			if embed2Fn == nil {
4712  				for mi := int32(0); mi < int32(embed2Named.NumMethods()); mi++ {
4713  					m := embed2Named.Method(int32(mi))
4714  					if m.Name == sel.Sel.Value {
4715  						if !embed2SamePkg && embed2Named.Obj.Pkg != nil {
4716  							impPkg := fb.ensureImportedSSAPackage(embed2Named.Obj.Pkg)
4717  							embed2Fn = impPkg.ExternalFunc(embed2Name|"."|sel.Sel.Value, m.Signature())
4718  						} else {
4719  							embed2Fn = fb.fn.Pkg.ExternalFunc(embed2Mangled, m.Signature())
4720  						}
4721  						break
4722  					}
4723  				}
4724  			}
4725  			if embed2Fn == nil {
4726  				continue
4727  			}
4728  			fieldAddr1 := &SSAFieldAddr{X: recv, Field: i}
4729  			fieldAddr1.typ = NewPointer(embedType)
4730  			fieldAddr1.name = fb.nextName()
4731  			fb.emit(fieldAddr1)
4732  			var cur1 SSAValue = fieldAddr1
4733  			curEmbedType := embedType
4734  			if p5, ok8 := SafeUnderlying(embedType).(*Pointer); ok8 {
4735  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr1}
4736  				ld.typ = embedType
4737  				ld.name = fb.nextName()
4738  				fb.emit(ld)
4739  				cur1 = ld
4740  				curEmbedType = p5.Base
4741  			}
4742  			_ = curEmbedType
4743  			fieldAddr2 := &SSAFieldAddr{X: cur1, Field: j}
4744  			fieldAddr2.typ = NewPointer(embed2Type)
4745  			fieldAddr2.name = fb.nextName()
4746  			fb.emit(fieldAddr2)
4747  			var embedRecv2 SSAValue = fieldAddr2
4748  			if _, isEmbedPtr2 := SafeUnderlying(embed2Type).(*Pointer); isEmbedPtr2 {
4749  				ld2 := &SSAUnOp{Op: OpMul, X: fieldAddr2}
4750  				ld2.typ = embed2Type
4751  				ld2.name = fb.nextName()
4752  				fb.emit(ld2)
4753  				embedRecv2 = ld2
4754  			}
4755  			return embed2Fn, embedRecv2
4756  		}
4757  	}
4758  	return nil, nil
4759  }
4760  
4761  func (fb *ssaFuncBuilder) buildIfaceMethodCall(sel *syntax.SelectorExpr, recv SSAValue, argExprs []syntax.Expr) (s SSAValue) {
4762  	typ := recv.SSAType()
4763  	if p6, ok43 := SafeUnderlying(typ).(*Pointer); ok43 {
4764  		typ = p6.Base
4765  	}
4766  	iface, ok := SafeUnderlying(typ).(*TCInterface)
4767  	if !ok {
4768  		return nil
4769  	}
4770  	var methodSig *Signature
4771  	for i := 0; i < iface.NumMethods(); i++ {
4772  		m := iface.Method(i)
4773  		if m == nil {
4774  			continue
4775  		}
4776  		if m.Name == sel.Sel.Value {
4777  			methodSig = m.Sig
4778  			break
4779  		}
4780  	}
4781  	var retType Type
4782  	if methodSig != nil && methodSig.Results != nil {
4783  		if methodSig.Results.Len() == 1 {
4784  			retType = methodSig.Results.At(0).Typ
4785  		} else if methodSig.Results.Len() > 1 {
4786  			retType = methodSig.Results
4787  		}
4788  	}
4789  	args := fb.buildArgs(argExprs)
4790  	inv := &SSAInvoke{
4791  		X:          recv,
4792  		MethodName: sel.Sel.Value,
4793  		IfaceType:  iface,
4794  		Args:       args,
4795  	}
4796  	inv.typ = retType
4797  	inv.name = fb.nextName()
4798  	fb.emit(inv)
4799  	if retType == nil {
4800  		return nil
4801  	}
4802  	return inv
4803  }
4804  
4805  func (fb *ssaFuncBuilder) resolveType(e syntax.Expr) (t Type) {
4806  	if fb.info != nil {
4807  		if tv, ok := fb.info.Types[e]; ok && tv.Type != nil {
4808  			return tv.Type
4809  		}
4810  	}
4811  	t = fb.resolveTypeAST(e)
4812  	return t
4813  }
4814  
4815  func (fb *ssaFuncBuilder) resolveTypeAST(e syntax.Expr) (t Type) {
4816  	if e == nil {
4817  		return nil
4818  	}
4819  	switch ev := e.(type) {
4820  	case *syntax.Name:
4821  		if fb.typeSubst != nil {
4822  			if t2, ok44 := fb.typeSubst[ev.Value]; ok44 {
4823  				return t2
4824  			}
4825  		}
4826  		if t3, ok45 := fb.localTypes[ev.Value]; ok45 {
4827  			return t3
4828  		}
4829  		obj := fb.lookupObject(ev.Value)
4830  		if tn, ok := obj.(*TypeName); ok {
4831  			if tp, ok2 := tn.Typ.(*TypeParam); ok2 && fb.typeSubst != nil {
4832  				if t4, ok46 := fb.typeSubst[tp.String()]; ok46 {
4833  					return t4
4834  				}
4835  			}
4836  			return tn.Typ
4837  		}
4838  	case *syntax.Operation:
4839  		if ev.Y == nil && ev.Op == token.Mul {
4840  			base := fb.resolveTypeAST(ev.X)
4841  			if base != nil {
4842  				return NewPointer(base)
4843  			}
4844  		}
4845  	case *syntax.SliceType:
4846  		elem := fb.resolveTypeAST(ev.Elem)
4847  		if elem != nil {
4848  			if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
4849  				return Typ[TCString]
4850  			}
4851  			return NewSlice(elem)
4852  		}
4853  	case *syntax.ArrayType:
4854  		elem := fb.resolveTypeAST(ev.Elem)
4855  		if elem != nil {
4856  			n := int64(-1)
4857  			if lit, ok := ev.Len.(*syntax.BasicLit); ok {
4858  				n = ssaParseInt64(lit.Value)
4859  			} else if ev.Len != nil {
4860  				cv := tcEvalConstExpr(ev.Len, fb.fn.Pkg.Pkg.Scope, -1)
4861  				if cv == nil && fb.localConsts != nil {
4862  					cv = fb.evalLocalConstExpr(ev.Len)
4863  				}
4864  				if ci2, ok47 := cv.(*ConstInt); ok47 {
4865  					n = ci2.V
4866  				}
4867  			}
4868  			return NewArray(elem, n)
4869  		}
4870  	case *syntax.MapType:
4871  		key := fb.resolveTypeAST(ev.Key)
4872  		val := fb.resolveTypeAST(ev.Value)
4873  		if key != nil && val != nil {
4874  			return NewTCMap(key, val)
4875  		}
4876  	case *syntax.StructType:
4877  		return fb.resolveStructTypeAST(ev)
4878  	case *syntax.ChanType:
4879  		elem := fb.resolveTypeAST(ev.Elem)
4880  		if elem != nil {
4881  			dir := TCSendRecv
4882  			if ev.Dir == syntax.SendOnly {
4883  				dir = TCSendOnly
4884  			} else if ev.Dir == syntax.RecvOnly {
4885  				dir = TCRecvOnly
4886  			}
4887  			return NewTCChan(dir, elem)
4888  		}
4889  	case *syntax.InterfaceType:
4890  		return fb.resolveInterfaceTypeAST(ev)
4891  	case *syntax.FuncType:
4892  		return fb.resolveFuncTypeAST(ev)
4893  	case *syntax.SelectorExpr:
4894  		if x, ok := ev.X.(*syntax.Name); ok {
4895  			obj := fb.lookupObject(x.Value)
4896  			if pn, ok2 := obj.(*PkgName); ok2 && pn.Imported != nil {
4897  				sel := pn.Imported.Scope.Lookup(ev.Sel.Value)
4898  				if tn, ok3 := sel.(*TypeName); ok3 {
4899  					return tn.Typ
4900  				}
4901  			}
4902  		}
4903  	case *syntax.ParenExpr:
4904  		return fb.resolveTypeAST(ev.X)
4905  	}
4906  	return nil
4907  }
4908  
4909  func (fb *ssaFuncBuilder) resolveInterfaceTypeAST(e *syntax.InterfaceType) (t *TCInterface) {
4910  	var methods []*IfaceMethod
4911  	for _, f := range e.MethodList {
4912  		if f.Name == nil {
4913  			continue
4914  		}
4915  		ft, ok := f.Type.(*syntax.FuncType)
4916  		if !ok {
4917  			continue
4918  		}
4919  		sig := fb.resolveFuncTypeAST(ft)
4920  		if sig != nil {
4921  			push(methods, NewTCIfaceMethod(f.Name.Value, sig))
4922  		}
4923  	}
4924  	iface := NewTCInterface(methods, nil)
4925  	iface.Complete()
4926  	return iface
4927  }
4928  
4929  func (fb *ssaFuncBuilder) resolveStructTypeAST(e *syntax.StructType) (t *TCStruct) {
4930  	var fields []*TCVar
4931  	var tags []string
4932  	for i, f := range e.FieldList {
4933  		typ := fb.resolveTypeAST(f.Type)
4934  		if typ == nil {
4935  			return nil
4936  		}
4937  		name := ""
4938  		if f.Name != nil {
4939  			name = f.Name.Value
4940  		}
4941  		push(fields, NewTCField(fb.fn.Pkg.Pkg, name, typ, f.Name == nil))
4942  		tag := ""
4943  		if i < len(e.TagList) && e.TagList[i] != nil {
4944  			tag = e.TagList[i].Value
4945  		}
4946  		push(tags, tag)
4947  	}
4948  	return NewTCStruct(fields, tags)
4949  }
4950  
4951  func (fb *ssaFuncBuilder) resolveFuncTypeAST(ft *syntax.FuncType) (s *Signature) {
4952  	if ft == nil {
4953  		return nil
4954  	}
4955  	var params []*TCVar
4956  	for _, p := range ft.ParamList {
4957  		typ := fb.resolveTypeAST(p.Type)
4958  		pname := ""
4959  		if p.Name != nil {
4960  			pname = p.Name.Value
4961  		}
4962  		push(params, NewTCVar(nil, pname, typ))
4963  	}
4964  	var results []*TCVar
4965  	for _, r := range ft.ResultList {
4966  		typ := fb.resolveTypeAST(r.Type)
4967  		rname := ""
4968  		if r.Name != nil {
4969  			rname = r.Name.Value
4970  		}
4971  		push(results, NewTCVar(nil, rname, typ))
4972  	}
4973  	var pTuple, rTuple *Tuple
4974  	if len(params) > 0 {
4975  		pTuple = NewTuple(params...)
4976  	}
4977  	if len(results) > 0 {
4978  		rTuple = NewTuple(results...)
4979  	}
4980  	return NewSignature(nil, pTuple, rTuple, false)
4981  }
4982  
4983  func (fb *ssaFuncBuilder) fieldIndex(t Type, name string) (n int32) {
4984  	if t == nil {
4985  		return -1
4986  	}
4987  	if pt, ok := SafeUnderlying(t).(*Pointer); ok {
4988  		t = pt.Base
4989  	}
4990  	if st, ok := SafeUnderlying(t).(*TCStruct); ok {
4991  		for i := 0; i < st.NumFields(); i++ {
4992  			if st.Field(i).Name == name {
4993  				return i
4994  			}
4995  		}
4996  	}
4997  	return -1
4998  }
4999  
5000  func (fb *ssaFuncBuilder) findEmbeddedField(t Type, name string) (embedIdx int32, innerIdx int32) {
5001  	path := fb.findEmbeddedFieldPath(t, name)
5002  	if len(path) < 2 {
5003  		return -1, -1
5004  	}
5005  	return path[0], path[1]
5006  }
5007  
5008  func (fb *ssaFuncBuilder) findEmbeddedFieldPath(t Type, name string) (ss []int32) {
5009  	if t == nil {
5010  		return nil
5011  	}
5012  	if pt2, ok48 := SafeUnderlying(t).(*Pointer); ok48 {
5013  		t = pt2.Base
5014  	}
5015  	st, ok := SafeUnderlying(t).(*TCStruct)
5016  	if !ok {
5017  		return nil
5018  	}
5019  	for i := 0; i < st.NumFields(); i++ {
5020  		f := st.Field(i)
5021  		if !f.Anonymous {
5022  			continue
5023  		}
5024  		embedType := f.Typ
5025  		if pt3, ok49 := SafeUnderlying(embedType).(*Pointer); ok49 {
5026  			embedType = pt3.Base
5027  		}
5028  		inner := fb.fieldIndex(embedType, name)
5029  		if inner >= 0 {
5030  			return []int32{i, inner}
5031  		}
5032  		sub := fb.findEmbeddedFieldPath(embedType, name)
5033  		if len(sub) > 0 {
5034  			return []int32{i} | sub
5035  		}
5036  	}
5037  	return nil
5038  }
5039  
5040  func (fb *ssaFuncBuilder) fieldType(t Type, idx int32) (tv Type) {
5041  	if t == nil {
5042  		return nil
5043  	}
5044  	if pt, ok := SafeUnderlying(t).(*Pointer); ok {
5045  		t = pt.Base
5046  	}
5047  	if st, ok := SafeUnderlying(t).(*TCStruct); ok {
5048  		if idx >= 0 && idx < st.NumFields() {
5049  			return fb.substTypeParams(st.Field(idx).Typ)
5050  		}
5051  	}
5052  	return nil
5053  }
5054  
5055  // substTypeParams substitutes type parameters in t using fb.typeSubst.
5056  // Generic struct types are erased to their base Named inside monomorphized
5057  // bodies, so a field like newPoint func() P still carries the TypeParam; the
5058  // concrete binding lives in fb.typeSubst.
5059  func (fb *ssaFuncBuilder) substTypeParams(t Type) (tv Type) {
5060  	if t == nil || fb.typeSubst == nil {
5061  		return t
5062  	}
5063  	switch tt := t.(type) {
5064  	case *TypeParam:
5065  		if r, ok := fb.typeSubst[tt.String()]; ok {
5066  			return r
5067  		}
5068  	case *Pointer:
5069  		e := fb.substTypeParams(tt.Base)
5070  		if e != tt.Base {
5071  			return NewPointer(e)
5072  		}
5073  	case *Slice:
5074  		e := fb.substTypeParams(tt.Elem)
5075  		if e != tt.Elem {
5076  			return NewSlice(e)
5077  		}
5078  	case *Signature:
5079  		changed := false
5080  		var params []*TCVar
5081  		if tt.Params != nil {
5082  			for i := 0; i < tt.Params.Len(); i++ {
5083  				p := tt.Params.At(i)
5084  				nt := fb.substTypeParams(p.Typ)
5085  				if nt != p.Typ {
5086  					changed = true
5087  					push(params, NewTCVar(nil, p.Name, nt))
5088  				} else {
5089  					push(params, p)
5090  				}
5091  			}
5092  		}
5093  		var results []*TCVar
5094  		if tt.Results != nil {
5095  			for i := 0; i < tt.Results.Len(); i++ {
5096  				r := tt.Results.At(i)
5097  				nt := fb.substTypeParams(r.Typ)
5098  				if nt != r.Typ {
5099  					changed = true
5100  					push(results, NewTCVar(nil, r.Name, nt))
5101  				} else {
5102  					push(results, r)
5103  				}
5104  			}
5105  		}
5106  		if changed {
5107  			var pT *Tuple
5108  			if len(params) > 0 {
5109  				pT = NewTuple(params...)
5110  			}
5111  			var rT *Tuple
5112  			if len(results) > 0 {
5113  				rT = NewTuple(results...)
5114  			}
5115  			return NewSignature(nil, pT, rT, tt.Variadic)
5116  		}
5117  	}
5118  	return t
5119  }
5120  
5121  func ssaExtractConst(v SSAValue) (s *SSAConst) {
5122  	if c, ok := v.(*SSAConst); ok {
5123  		return c
5124  	}
5125  	if conv, ok := v.(*SSAConvert); ok {
5126  		if c, ok2 := conv.X.(*SSAConst); ok2 {
5127  			return &SSAConst{typ: conv.SSAType(), val: c.val}
5128  		}
5129  	}
5130  	return nil
5131  }
5132  
5133  func ssaExprNames(e syntax.Expr) (ns []*syntax.Name) {
5134  	if e == nil {
5135  		return nil
5136  	}
5137  	if n, ok := e.(*syntax.Name); ok {
5138  		return []*syntax.Name{n}
5139  	}
5140  	if l, ok := e.(*syntax.ListExpr); ok {
5141  		var names []*syntax.Name
5142  		for _, el := range l.ElemList {
5143  			if n2, ok50 := el.(*syntax.Name); ok50 {
5144  				push(names, n2)
5145  			}
5146  		}
5147  		return names
5148  	}
5149  	return nil
5150  }
5151  
5152  // ssaSizeofType computes byte size for a type, used by unsafe.Sizeof.
5153  func ssaSizeofType(t Type) (sz int64) {
5154  	if t == nil {
5155  		return 8
5156  	}
5157  	u := SafeUnderlying(t)
5158  	if u == nil {
5159  		return 8
5160  	}
5161  	switch v := u.(type) {
5162  	case *Basic:
5163  		switch v.Kind {
5164  		case Bool, Int8, Uint8:
5165  			return 1
5166  		case Int16, Uint16:
5167  			return 2
5168  		case Int32, Uint32, Float32:
5169  			return 4
5170  		case Int64, Uint64, Float64, UnsafePointer:
5171  			return 8
5172  		case TCString, UntypedString:
5173  			return 24
5174  		}
5175  		return 8
5176  	case *Pointer:
5177  		return 8
5178  	case *Slice:
5179  		return 24
5180  	case *Signature:
5181  		return 16
5182  	case *TCInterface:
5183  		return 16
5184  	case *TCMap, *TCChan:
5185  		return 8
5186  	case *Array:
5187  		return ssaSizeofType(v.Elem) * v.Len
5188  	case *TCStruct:
5189  		total := int64(0)
5190  		for i := 0; i < v.NumFields(); i++ {
5191  			fsz := ssaSizeofType(v.Field(i).Typ)
5192  			if fsz >= 8 && total%8 != 0 {
5193  				total = (total + 7) & ^int64(7)
5194  			}
5195  			total = total + fsz
5196  		}
5197  		if total%8 != 0 {
5198  			total = (total + 7) & ^int64(7)
5199  		}
5200  		return total
5201  	}
5202  	return 8
5203  }
5204  
5205  func localizeConstVal(val ConstVal, typ Type) (c ConstVal) {
5206  	if val == nil {
5207  		return nil
5208  	}
5209  	return val
5210  }
5211  
5212  func mangleGenericName(baseName string, typeArgs []Type) (s string) {
5213  	s = baseName | "__"
5214  	for i, t := range typeArgs {
5215  		if i > 0 {
5216  			s = s | "_"
5217  		}
5218  		if t == nil {
5219  			s = s | "nil"
5220  		} else {
5221  			ts := t.String()
5222  			for j := 0; j < len(ts); j++ {
5223  				c := ts[j]
5224  				if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') {
5225  					s = s | string([]byte{c})
5226  				} else if c == '.' {
5227  					s = s | "."
5228  				} else {
5229  					s = s | "_"
5230  				}
5231  			}
5232  		}
5233  	}
5234  	return s
5235  }
5236  
5237  func resolveTypeExprWithSubst(e syntax.Expr, typeSubst map[string]Type, pkgScope *Scope) (t Type) {
5238  	if e == nil {
5239  		return nil
5240  	}
5241  	switch ev := e.(type) {
5242  	case *syntax.Name:
5243  		if t5, ok51 := typeSubst[ev.Value]; ok51 {
5244  			return t5
5245  		}
5246  		_, obj := Universe.LookupParent(ev.Value)
5247  		if obj != nil {
5248  			if tn, ok := obj.(*TypeName); ok {
5249  				return tn.Typ
5250  			}
5251  		}
5252  		if pkgScope != nil {
5253  			tobj := pkgScope.Lookup(ev.Value)
5254  			if tobj != nil {
5255  				if tn, ok := tobj.(*TypeName); ok {
5256  					return tn.Typ
5257  				}
5258  			}
5259  		}
5260  		if cctx.universe.Registry != nil {
5261  			for _, pkg := range cctx.universe.Registry {
5262  				if pkg == nil || pkg.Scope == nil {
5263  					continue
5264  				}
5265  				tobj := pkg.Scope.Lookup(ev.Value)
5266  				if tobj != nil {
5267  					if tn, ok := tobj.(*TypeName); ok {
5268  						return tn.Typ
5269  					}
5270  				}
5271  			}
5272  		}
5273  		return nil
5274  	case *syntax.DotsType:
5275  		elem := resolveTypeExprWithSubst(ev.Elem, typeSubst, pkgScope)
5276  		if elem != nil {
5277  			if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
5278  				return Typ[TCString]
5279  			}
5280  			return NewSlice(elem)
5281  		}
5282  	case *syntax.SliceType:
5283  		elem := resolveTypeExprWithSubst(ev.Elem, typeSubst, pkgScope)
5284  		if elem != nil {
5285  			if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
5286  				return Typ[TCString]
5287  			}
5288  			return NewSlice(elem)
5289  		}
5290  	case *syntax.ArrayType:
5291  		elem := resolveTypeExprWithSubst(ev.Elem, typeSubst, pkgScope)
5292  		if elem != nil {
5293  			n := int64(-1)
5294  			if lit, ok := ev.Len.(*syntax.BasicLit); ok {
5295  				n = ssaParseInt64(lit.Value)
5296  			} else if ev.Len != nil && pkgScope != nil {
5297  				cv := tcEvalConstExpr(ev.Len, pkgScope, -1)
5298  				if ci3, ok52 := cv.(*ConstInt); ok52 {
5299  					n = ci3.V
5300  				}
5301  			}
5302  			return NewArray(elem, n)
5303  		}
5304  	case *syntax.Operation:
5305  		if ev.Y == nil && ev.Op == token.Mul {
5306  			base := resolveTypeExprWithSubst(ev.X, typeSubst, pkgScope)
5307  			if base != nil {
5308  				return NewPointer(base)
5309  			}
5310  		}
5311  	case *syntax.MapType:
5312  		key := resolveTypeExprWithSubst(ev.Key, typeSubst, pkgScope)
5313  		val := resolveTypeExprWithSubst(ev.Value, typeSubst, pkgScope)
5314  		if key != nil && val != nil {
5315  			return NewTCMap(key, val)
5316  		}
5317  	case *syntax.ChanType:
5318  		elem := resolveTypeExprWithSubst(ev.Elem, typeSubst, pkgScope)
5319  		if elem != nil {
5320  			dir := TCSendRecv
5321  			if ev.Dir == syntax.SendOnly {
5322  				dir = TCSendOnly
5323  			} else if ev.Dir == syntax.RecvOnly {
5324  				dir = TCRecvOnly
5325  			}
5326  			return NewTCChan(dir, elem)
5327  		}
5328  	case *syntax.InterfaceType:
5329  		return resolveInterfaceFromAST(ev)
5330  	case *syntax.FuncType:
5331  		return resolveSignatureWithSubst(ev, typeSubst, pkgScope)
5332  	case *syntax.IndexExpr:
5333  		// Generic instantiation Curve[P]: erase to the base named type.
5334  		// Fields typed by the type param are substituted at use sites via
5335  		// fb.typeSubst.
5336  		return resolveTypeExprWithSubst(ev.X, typeSubst, pkgScope)
5337  	case *syntax.SelectorExpr:
5338  		if pkgName, ok := ev.X.(*syntax.Name); ok {
5339  			if imp := cctx.universe.LookupByName(pkgName.Value); imp != nil {
5340  				typeObj := imp.Scope.Lookup(ev.Sel.Value)
5341  				if typeObj != nil {
5342  					if tn, ok2 := typeObj.(*TypeName); ok2 {
5343  						return tn.Typ
5344  					}
5345  				}
5346  			}
5347  		}
5348  	}
5349  	return nil
5350  }
5351  
5352  func resolveSignatureWithSubst(ft *syntax.FuncType, typeSubst map[string]Type, pkgScope *Scope) (s *Signature) {
5353  	if ft == nil {
5354  		return nil
5355  	}
5356  	var params []*TCVar
5357  	variadic := false
5358  	for _, p := range ft.ParamList {
5359  		typ := resolveTypeExprWithSubst(p.Type, typeSubst, pkgScope)
5360  		name := ""
5361  		if p.Name != nil {
5362  			name = p.Name.Value
5363  		}
5364  		push(params, NewTCVar(nil, name, typ))
5365  	}
5366  	if len(ft.ParamList) > 0 {
5367  		last := ft.ParamList[len(ft.ParamList)-1]
5368  		if _, ok := last.Type.(*syntax.DotsType); ok {
5369  			variadic = true
5370  		}
5371  	}
5372  	var results []*TCVar
5373  	for _, r := range ft.ResultList {
5374  		typ := resolveTypeExprWithSubst(r.Type, typeSubst, pkgScope)
5375  		name := ""
5376  		if r.Name != nil {
5377  			name = r.Name.Value
5378  		}
5379  		if typ == nil && r.Name != nil {
5380  			if _, ok := r.Type.(*syntax.Name); ok {
5381  			}
5382  		}
5383  		push(results, NewTCVar(nil, name, typ))
5384  	}
5385  	var paramTuple *Tuple
5386  	if len(params) > 0 {
5387  		paramTuple = NewTuple(params...)
5388  	}
5389  	var resultTuple *Tuple
5390  	if len(results) > 0 {
5391  		resultTuple = NewTuple(results...)
5392  	}
5393  	return NewSignature(nil, paramTuple, resultTuple, variadic)
5394  }
5395  
5396  func matchTypeParam(paramType syntax.Expr, argType Type, tparams []*syntax.Field, typeMap map[string]Type) {
5397  	if paramType == nil || argType == nil {
5398  		return
5399  	}
5400  	switch pt := paramType.(type) {
5401  	case *syntax.Name:
5402  		for _, tp := range tparams {
5403  			if tp.Name != nil && tp.Name.Value == pt.Value {
5404  				typeMap[pt.Value] = argType
5405  				return
5406  			}
5407  		}
5408  	case *syntax.DotsType:
5409  		matchTypeParam(pt.Elem, argType, tparams, typeMap)
5410  	case *syntax.Operation:
5411  		// pointer param AST: *T is Operation{Op: Mul, Y: nil}
5412  		if pt.Y == nil && pt.Op == token.Mul {
5413  			if p, ok := SafeUnderlying(argType).(*Pointer); ok {
5414  				matchTypeParam(pt.X, p.Base, tparams, typeMap)
5415  			}
5416  		}
5417  	case *syntax.SliceType:
5418  		u := SafeUnderlying(argType)
5419  		// In Moxie, string and []byte are the same type. Treat string as
5420  		// []byte when matching against a slice type parameter.
5421  		if b, ok := u.(*Basic); ok && b.Kind == TCString {
5422  			u = NewSlice(Typ[Uint8])
5423  		}
5424  		if sl, ok := u.(*Slice); ok {
5425  			matchTypeParam(pt.Elem, sl.Elem, tparams, typeMap)
5426  		}
5427  	case *syntax.FuncType:
5428  		sig, ok := SafeUnderlying(argType).(*Signature)
5429  		if !ok {
5430  			return
5431  		}
5432  		for i, p := range pt.ParamList {
5433  			if sig.Params != nil && i < int32(sig.Params.Len()) {
5434  				matchTypeParam(p.Type, sig.Params.At(int32(i)).Typ, tparams, typeMap)
5435  			}
5436  		}
5437  		for i, r := range pt.ResultList {
5438  			if sig.Results != nil && i < int32(sig.Results.Len()) {
5439  				matchTypeParam(r.Type, sig.Results.At(int32(i)).Typ, tparams, typeMap)
5440  			}
5441  		}
5442  	}
5443  }
5444  
5445  func inferFromConstraints(tparams []*syntax.Field, typeMap map[string]Type) {
5446  	for _, tp := range tparams {
5447  		if tp.Name == nil || tp.Type == nil {
5448  			continue
5449  		}
5450  		knownType, ok := typeMap[tp.Name.Value]
5451  		if !ok {
5452  			continue
5453  		}
5454  		extractConstraintTypeParams(tp.Type, knownType, tparams, typeMap)
5455  	}
5456  }
5457  
5458  func extractConstraintTypeParams(constraint syntax.Expr, concreteType Type, tparams []*syntax.Field, typeMap map[string]Type) {
5459  	if constraint == nil || concreteType == nil {
5460  		return
5461  	}
5462  	switch c := constraint.(type) {
5463  	case *syntax.Operation:
5464  		if c.Op == token.Tilde && c.Y == nil {
5465  			extractConstraintTypeParams(c.X, concreteType, tparams, typeMap)
5466  		}
5467  	case *syntax.SliceType:
5468  		// In Moxie, string and []byte are the same type. When the concrete
5469  		// type is string (Basic), treat it as []byte for constraint matching.
5470  		ct := concreteType
5471  		u := SafeUnderlying(ct)
5472  		if b, ok := u.(*Basic); ok && b.Kind == TCString {
5473  			ct = NewSlice(Typ[Uint8])
5474  			u = ct
5475  		}
5476  		if sl, ok := u.(*Slice); ok {
5477  			if name, ok2 := c.Elem.(*syntax.Name); ok2 {
5478  				for _, tp := range tparams {
5479  					if tp.Name != nil && tp.Name.Value == name.Value {
5480  						if _, already := typeMap[name.Value]; !already {
5481  							typeMap[name.Value] = sl.Elem
5482  						}
5483  					}
5484  				}
5485  			}
5486  		}
5487  	}
5488  }
5489  
5490  func inferTypeArgsFromFunc(fd *syntax.FuncDecl, args []SSAValue) (ts []Type) {
5491  	typeMap := map[string]Type{}
5492  	if fd.Type != nil {
5493  		for i, param := range fd.Type.ParamList {
5494  			if i >= len(args) || args[i] == nil || args[i].SSAType() == nil {
5495  				continue
5496  			}
5497  			matchTypeParam(param.Type, args[i].SSAType(), fd.TParamList, typeMap)
5498  		}
5499  	}
5500  	inferFromConstraints(fd.TParamList, typeMap)
5501  	var result []Type
5502  	for _, tp := range fd.TParamList {
5503  		if tp.Name != nil {
5504  			push(result, typeMap[tp.Name.Value])
5505  		}
5506  	}
5507  	return result
5508  }
5509  
5510  // inferTypeArgsFromArgASTs is a fallback for inferTypeArgsFromFunc when the
5511  // checker erased a generic instantiation (resolveGenericInst is a stub): the
5512  // checked type of an arg like ecdh.P256() is bare *Curve with no type args,
5513  // so type-level matching cannot bind P. Instead, unify the callee param's
5514  // type AST (*Curve[P]) against the argument EXPRESSION's declared type AST:
5515  // the result AST of the called function, or the enclosing function's param
5516  // AST (resolved through fb.typeSubst inside monomorphized bodies).
5517  func (fb *ssaFuncBuilder) inferTypeArgsFromArgASTs(fd *syntax.FuncDecl, argList []syntax.Expr, typeArgs []Type) (ts []Type) {
5518  	anyNil := false
5519  	for _, ta := range typeArgs {
5520  		if ta == nil {
5521  			anyNil = true
5522  		}
5523  	}
5524  	if !anyNil {
5525  		return typeArgs
5526  	}
5527  	typeMap := map[string]Type{}
5528  	for i, tp := range fd.TParamList {
5529  		if tp.Name != nil && i < len(typeArgs) && typeArgs[i] != nil {
5530  			typeMap[tp.Name.Value] = typeArgs[i]
5531  		}
5532  	}
5533  	if fd.Type != nil {
5534  		for i, param := range fd.Type.ParamList {
5535  			if i >= len(argList) {
5536  				break
5537  			}
5538  			argAST, argSubst, argScope := fb.declaredTypeAST(argList[i])
5539  			if argAST == nil {
5540  				continue
5541  			}
5542  			fb.unifyParamAST(param.Type, argAST, fd.TParamList, typeMap, argSubst, argScope)
5543  		}
5544  	}
5545  	inferFromConstraints(fd.TParamList, typeMap)
5546  	var result []Type
5547  	for _, tp := range fd.TParamList {
5548  		if tp.Name != nil {
5549  			push(result, typeMap[tp.Name.Value])
5550  		}
5551  	}
5552  	return result
5553  }
5554  
5555  // declaredTypeAST returns the source-declared type AST of an argument
5556  // expression plus the subst map and scope needed to resolve concrete names
5557  // inside it. Two shapes matter: a call to a function whose FuncDecl AST is
5558  // recorded (its result type AST carries the un-erased generic instantiation),
5559  // and a bare name referring to a parameter of the enclosing function.
5560  func (fb *ssaFuncBuilder) declaredTypeAST(arg syntax.Expr) (e syntax.Expr, m map[string]Type, sc *Scope) {
5561  	switch a := arg.(type) {
5562  	case *syntax.CallExpr:
5563  		path := ""
5564  		fname := ""
5565  		switch fun := a.Fun.(type) {
5566  		case *syntax.SelectorExpr:
5567  			if pkgName, ok53 := fun.X.(*syntax.Name); ok53 {
5568  				if pn, ok2 := fb.lookupObject(pkgName.Value).(*PkgName); ok2 && pn.Imported != nil {
5569  					path = pn.Imported.Path
5570  					fname = fun.Sel.Value
5571  				}
5572  			}
5573  		case *syntax.Name:
5574  			path = fb.fn.Pkg.Pkg.Path
5575  			fname = fun.Value
5576  			if fb.srcScope != nil {
5577  				for gPkg, gScope := range cctx.genericPkgScopes {
5578  					if gScope == fb.srcScope {
5579  						path = gPkg
5580  						break
5581  					}
5582  				}
5583  			}
5584  		}
5585  		if fname == "" {
5586  			return nil, nil, nil
5587  		}
5588  		callee, ok := cctx.genericPkgLocalDecls[path|"."|fname]
5589  		if !ok {
5590  			return nil, nil, nil
5591  		}
5592  		if callee.Type == nil || len(callee.Type.ResultList) != 1 {
5593  			return nil, nil, nil
5594  		}
5595  		var scope *Scope
5596  		if cctx.genericPkgScopes != nil {
5597  			scope = cctx.genericPkgScopes[path]
5598  		}
5599  		return callee.Type.ResultList[0].Type, map[string]Type{}, scope
5600  	case *syntax.Name:
5601  		// Walk the closure parent chain: a free variable captured by a
5602  		// closure inside a monomorphized body is declared as a param of an
5603  		// enclosing function, not of the closure itself.
5604  		for cur := fb; cur != nil; cur = cur.parent {
5605  			if cur.decl == nil || cur.decl.Type == nil {
5606  				continue
5607  			}
5608  			for _, p := range cur.decl.Type.ParamList {
5609  				if p.Name != nil && p.Name.Value == a.Value {
5610  					return p.Type, cur.typeSubst, cur.srcScope
5611  				}
5612  			}
5613  		}
5614  	}
5615  	return nil, nil, nil
5616  }
5617  
5618  // unifyParamAST structurally unifies a callee parameter type AST against an
5619  // argument's declared type AST, binding callee type params in typeMap. Leaf
5620  // exprs on the arg side are resolved with (argSubst, argScope).
5621  func (fb *ssaFuncBuilder) unifyParamAST(paramAST syntax.Expr, argAST syntax.Expr, tparams []*syntax.Field, typeMap map[string]Type, argSubst map[string]Type, argScope *Scope) {
5622  	if paramAST == nil || argAST == nil {
5623  		return
5624  	}
5625  	switch pt := paramAST.(type) {
5626  	case *syntax.Name:
5627  		for _, tp := range tparams {
5628  			if tp.Name != nil && tp.Name.Value == pt.Value {
5629  				if _, already := typeMap[pt.Value]; already {
5630  					return
5631  				}
5632  				t := resolveTypeExprWithSubst(argAST, argSubst, argScope)
5633  				if t != nil {
5634  					typeMap[pt.Value] = t
5635  				}
5636  				return
5637  			}
5638  		}
5639  	case *syntax.Operation:
5640  		if pt.Y == nil && pt.Op == token.Mul {
5641  			if at, ok := argAST.(*syntax.Operation); ok && at.Y == nil && at.Op == token.Mul {
5642  				fb.unifyParamAST(pt.X, at.X, tparams, typeMap, argSubst, argScope)
5643  			}
5644  		}
5645  	case *syntax.IndexExpr:
5646  		if at, ok := argAST.(*syntax.IndexExpr); ok {
5647  			fb.unifyParamAST(pt.Index, at.Index, tparams, typeMap, argSubst, argScope)
5648  		}
5649  	case *syntax.ListExpr:
5650  		if at, ok := argAST.(*syntax.ListExpr); ok {
5651  			for i, el := range pt.ElemList {
5652  				if i < len(at.ElemList) {
5653  					fb.unifyParamAST(el, at.ElemList[i], tparams, typeMap, argSubst, argScope)
5654  				}
5655  			}
5656  		}
5657  	case *syntax.SliceType:
5658  		if at, ok := argAST.(*syntax.SliceType); ok {
5659  			fb.unifyParamAST(pt.Elem, at.Elem, tparams, typeMap, argSubst, argScope)
5660  		}
5661  	case *syntax.DotsType:
5662  		fb.unifyParamAST(pt.Elem, argAST, tparams, typeMap, argSubst, argScope)
5663  	}
5664  }
5665  
5666  // monomorphizeAndCall returns (value, handled). handled is true when the call
5667  // was emitted - the value is nil for void functions, so callers must NOT use
5668  // value-nilness to decide whether to fall through to a non-generic call path
5669  // (that double-emits the call).
5670  func (fb *ssaFuncBuilder) monomorphizeAndCall(fd *syntax.FuncDecl, baseName string, typeArgs []Type, args []SSAValue, targetPkg *SSAPackage, srcPkgPath string, hasDots bool) (s SSAValue, handled bool) {
5671  	for _, ta := range typeArgs {
5672  		if ta == nil {
5673  			return nil, false
5674  		}
5675  	}
5676  	mangledName := mangleGenericName(baseName, typeArgs)
5677  	if srcPkgPath != "" {
5678  		// Two generic funcs with the same name from different packages can
5679  		// mangle identically (e.g. crypto/pbkdf2.Key and
5680  		// crypto/internal/fips140/pbkdf2.Key, both instantiated at
5681  		// hash.Hash); without the source package in the name the second
5682  		// instantiation resolves to the first and recurses.
5683  		pfx := ""
5684  		for j := 0; j < len(srcPkgPath); j++ {
5685  			c := srcPkgPath[j]
5686  			if c == '/' {
5687  				pfx = pfx | "_"
5688  			} else {
5689  				pfx = pfx | string([]byte{c})
5690  			}
5691  		}
5692  		mangledName = pfx | "." | mangledName
5693  	}
5694  	if fn5, ok54 := targetPkg.Members[mangledName].(*SSAFunction); ok54 {
5695  		return fb.emitCallToSSAFunc(fn5, args, hasDots), true
5696  	}
5697  	typeSubst := map[string]Type{}
5698  	for i, tp := range fd.TParamList {
5699  		if tp.Name != nil && i < len(typeArgs) && typeArgs[i] != nil {
5700  			typeSubst[tp.Name.Value] = typeArgs[i]
5701  		}
5702  	}
5703  	var srcScope *Scope
5704  	if cctx.genericPkgScopes != nil {
5705  		if sc, ok := cctx.genericPkgScopes[srcPkgPath]; ok {
5706  			srcScope = sc
5707  		}
5708  	}
5709  	sig := resolveSignatureWithSubst(fd.Type, typeSubst, srcScope)
5710  	if sig == nil {
5711  		return nil, false
5712  	}
5713  	fn := &SSAFunction{
5714  		name:      mangledName,
5715  		Signature: sig,
5716  		Pkg:       targetPkg,
5717  		Prog:      fb.fn.Prog,
5718  	}
5719  	targetPkg.SetMember(mangledName, fn)
5720  	subFb := newSSAFuncBuilder(fn, fb.info)
5721  	subFb.typeSubst = typeSubst
5722  	subFb.srcScope = srcScope
5723  	subFb.buildBody(fd)
5724  	return fb.emitCallToSSAFunc(fn, args, hasDots), true
5725  }
5726  
5727  func (fb *ssaFuncBuilder) emitCallToSSAFunc(fn *SSAFunction, args []SSAValue, hasDots bool) (s SSAValue) {
5728  	if fn.Signature != nil {
5729  		if fn.Signature.Variadic && !hasDots {
5730  			args = fb.wrapVariadicArgs(args, fn.Signature)
5731  		}
5732  		args = fb.coerceArgsToInterface(args, fn.Signature)
5733  	}
5734  	var retType Type
5735  	if fn.Signature != nil && fn.Signature.Results != nil {
5736  		if fn.Signature.Results.Len() == 1 {
5737  			retType = fn.Signature.Results.At(0).Typ
5738  		} else if fn.Signature.Results.Len() > 1 {
5739  			retType = fn.Signature.Results
5740  		}
5741  	}
5742  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
5743  	call.typ = retType
5744  	call.name = fb.nextName()
5745  	fb.emit(call)
5746  	if retType == nil {
5747  		return nil
5748  	}
5749  	return call
5750  }
5751  
5752  func (fb *ssaFuncBuilder) tryGenericLocalCall(funcName string, argList []syntax.Expr, hasDots bool) (s SSAValue, handled bool) {
5753  	pkgPath := fb.fn.Pkg.Pkg.Path
5754  	key := pkgPath + "." + funcName
5755  	fd, ok := cctx.genericFuncDecls[key]
5756  	if !ok && fb.srcScope != nil {
5757  		for gPkg, gScope := range cctx.genericPkgScopes {
5758  			if gScope == fb.srcScope {
5759  				key = gPkg + "." + funcName
5760  				fd, ok = cctx.genericFuncDecls[key]
5761  				if !ok && gPkg != fb.fn.Pkg.Pkg.Path {
5762  					// Package-local non-generic helper called from a
5763  					// monomorphized body in ANOTHER package: instantiate it
5764  					// here, its symbol is unexported in the source package's
5765  					// object. Within the source package itself the local
5766  					// function is directly available.
5767  					fd, ok = cctx.genericPkgLocalDecls[key]
5768  				}
5769  				if ok {
5770  					pkgPath = gPkg
5771  					break
5772  				}
5773  			}
5774  		}
5775  	}
5776  	if !ok {
5777  		return nil, false
5778  	}
5779  	args := fb.buildArgs(argList)
5780  	typeArgs := inferTypeArgsFromFunc(fd, args)
5781  	typeArgs = fb.inferTypeArgsFromArgASTs(fd, argList, typeArgs)
5782  	return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
5783  }
5784  
5785  func (fb *ssaFuncBuilder) tryGenericPkgCall(pn *PkgName, funcName string, argList []syntax.Expr, hasDots bool) (s SSAValue, handled bool) {
5786  	imported := pn.Imported
5787  	if imported == nil {
5788  		return nil, false
5789  	}
5790  	key := imported.Path + "." + funcName
5791  	fd, ok := cctx.genericFuncDecls[key]
5792  	if !ok {
5793  		return nil, false
5794  	}
5795  	args := fb.buildArgs(argList)
5796  	typeArgs := inferTypeArgsFromFunc(fd, args)
5797  	typeArgs = fb.inferTypeArgsFromArgASTs(fd, argList, typeArgs)
5798  	return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, imported.Path, hasDots)
5799  }
5800  
5801  func (fb *ssaFuncBuilder) tryGenericCallFromIndex(ie *syntax.IndexExpr, argList []syntax.Expr, hasDots bool) (s SSAValue, handled bool) {
5802  	switch x := ie.X.(type) {
5803  	case *syntax.Name:
5804  		pkgPath := fb.fn.Pkg.Pkg.Path
5805  		key := pkgPath + "." + x.Value
5806  		fd, ok := cctx.genericFuncDecls[key]
5807  		if !ok && fb.srcScope != nil {
5808  			for gPkg, gScope := range cctx.genericPkgScopes {
5809  				if gScope == fb.srcScope {
5810  					key = gPkg + "." + x.Value
5811  					fd, ok = cctx.genericFuncDecls[key]
5812  					if ok {
5813  						pkgPath = gPkg
5814  						break
5815  					}
5816  				}
5817  			}
5818  		}
5819  		if !ok {
5820  			return nil, false
5821  		}
5822  		typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
5823  		args := fb.buildArgs(argList)
5824  		return fb.monomorphizeAndCall(fd, x.Value, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
5825  	case *syntax.SelectorExpr:
5826  		if pkgName, ok2 := x.X.(*syntax.Name); ok2 {
5827  			obj := fb.lookupObject(pkgName.Value)
5828  			if pn, ok3 := obj.(*PkgName); ok3 && pn.Imported != nil {
5829  				key := pn.Imported.Path + "." + x.Sel.Value
5830  				fd, ok4 := cctx.genericFuncDecls[key]
5831  				if !ok4 {
5832  					return nil, false
5833  				}
5834  				typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
5835  				args := fb.buildArgs(argList)
5836  				return fb.monomorphizeAndCall(fd, x.Sel.Value, typeArgs, args, fb.fn.Pkg, pn.Imported.Path, hasDots)
5837  			}
5838  		}
5839  	}
5840  	return nil, false
5841  }
5842  
5843  func (fb *ssaFuncBuilder) resolveExplicitTypeArgs(indexExpr syntax.Expr, fd *syntax.FuncDecl) (ts []Type) {
5844  	var typeExprs []syntax.Expr
5845  	if le, ok := indexExpr.(*syntax.ListExpr); ok {
5846  		typeExprs = le.ElemList
5847  	} else {
5848  		typeExprs = []syntax.Expr{indexExpr}
5849  	}
5850  	var result []Type
5851  	for _, te := range typeExprs {
5852  		t := fb.resolveTypeAST(te)
5853  		push(result, t)
5854  	}
5855  	if len(result) < len(fd.TParamList) {
5856  		typeMap := map[string]Type{}
5857  		for i, tp := range fd.TParamList {
5858  			if tp.Name != nil && i < len(result) && result[i] != nil {
5859  				typeMap[tp.Name.Value] = result[i]
5860  			}
5861  		}
5862  		inferFromConstraints(fd.TParamList, typeMap)
5863  		result = nil
5864  		for _, tp := range fd.TParamList {
5865  			if tp.Name != nil {
5866  				push(result, typeMap[tp.Name.Value])
5867  			}
5868  		}
5869  	}
5870  	return result
5871  }
5872  
5873  func exprTypeName(e syntax.Expr) (s string) {
5874  	switch ev := e.(type) {
5875  	case *syntax.Name:
5876  		return "Name(" | ev.Value | ")"
5877  	case *syntax.BasicLit:
5878  		return "BasicLit"
5879  	case *syntax.SelectorExpr:
5880  		if x, ok := ev.X.(*syntax.Name); ok {
5881  			return "Selector(" | x.Value | "." | ev.Sel.Value | ")"
5882  		}
5883  		return "Selector"
5884  	case *syntax.CallExpr:
5885  		return "Call"
5886  	case *syntax.Operation:
5887  		return "Op"
5888  	}
5889  	return "unknown"
5890  }
5891  
5892  func resolveInterfaceFromAST(e *syntax.InterfaceType) (t *TCInterface) {
5893  	var methods []*IfaceMethod
5894  	if e.MethodList != nil {
5895  		for _, f := range e.MethodList {
5896  			if f.Name != nil {
5897  				m := NewTCIfaceMethod(f.Name.Value, nil)
5898  				push(methods, m)
5899  			}
5900  		}
5901  	}
5902  	iface := NewTCInterface(methods, nil)
5903  	iface.Complete()
5904  	return iface
5905  }
5906