builder.mx raw

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