ssa_builder.mx raw

   1  package main
   2  
   3  func asType(t Type) Type { return t }
   4  
   5  // CreatePackage builds the SSA Package from type-checked syntax files.
   6  func (prog *SSAProgram) CreatePackage(pkg *TCPackage, files []*File, info *Info) *SSAPackage {
   7  	p := &SSAPackage{
   8  		Prog:    prog,
   9  		Pkg:     pkg,
  10  		Members: map[string]SSAMember{},
  11  	}
  12  	prog.packages[pkg] = p
  13  	prog.imported[pkg.Path()] = p
  14  
  15  	pb := &ssaPkgBuilder{pkg: p, info: info, prog: prog}
  16  
  17  	for _, f := range files {
  18  		pb.registerImportsAndTypes(f)
  19  	}
  20  	for _, f := range files {
  21  		pb.registerFile(f)
  22  	}
  23  	for _, f := range files {
  24  		pb.buildFile(f)
  25  	}
  26  	return p
  27  }
  28  
  29  // ssaPkgBuilder builds one SSAPackage.
  30  type ssaPkgBuilder struct {
  31  	pkg  *SSAPackage
  32  	info *Info
  33  	prog *SSAProgram
  34  }
  35  
  36  func (pb *ssaPkgBuilder) registerImportsAndTypes(f *File) {
  37  	for _, d := range f.DeclList {
  38  		switch d := d.(type) {
  39  		case *ImportDecl:
  40  			pb.registerImport(d)
  41  		case *TypeDecl:
  42  			pb.registerType(d)
  43  		}
  44  	}
  45  }
  46  
  47  func (pb *ssaPkgBuilder) registerFile(f *File) {
  48  	for _, d := range f.DeclList {
  49  		switch d := d.(type) {
  50  		case *FuncDecl:
  51  			pb.registerFunc(d)
  52  		case *VarDecl:
  53  			pb.registerVar(d)
  54  		case *ConstDecl:
  55  			pb.registerConst(d)
  56  		}
  57  	}
  58  }
  59  
  60  func (pb *ssaPkgBuilder) registerImport(d *ImportDecl) {
  61  	if d.Path == nil {
  62  		return
  63  	}
  64  	path := d.Path.Value
  65  	if len(path) >= 2 && path[0] == '"' {
  66  		path = path[1 : len(path)-1]
  67  	}
  68  	localName := ""
  69  	if d.LocalPkgName != nil {
  70  		localName = d.LocalPkgName.Value
  71  	}
  72  	if localName == "" {
  73  		for i := len(path) - 1; i >= 0; i-- {
  74  			if path[i] == '/' {
  75  				localName = path[i+1:]
  76  				break
  77  			}
  78  		}
  79  		if localName == "" {
  80  			localName = path
  81  		}
  82  	}
  83  	if localName == "." || localName == "_" {
  84  		return
  85  	}
  86  	existing := pb.pkg.Pkg.Scope().Lookup(localName)
  87  	if existing != nil {
  88  		return
  89  	}
  90  	impPkg := pb.prog.ImportedPackage(path)
  91  	if impPkg != nil && impPkg.Pkg != nil {
  92  		pn := NewPkgName(nil, localName, impPkg.Pkg)
  93  		pb.pkg.Pkg.Scope().Insert(pn)
  94  	} else {
  95  		ensureImportRegistry()
  96  		regPkg := importRegistry[path]
  97  		if regPkg != nil {
  98  			pn := NewPkgName(nil, localName, regPkg)
  99  			pb.pkg.Pkg.Scope().Insert(pn)
 100  		}
 101  	}
 102  }
 103  
 104  func pkgResolveTypeAST(pkg *SSAPackage, e Expr) Type {
 105  	if e == nil {
 106  		return nil
 107  	}
 108  	switch e := e.(type) {
 109  	case *Name:
 110  		if _, obj := Universe.LookupParent(e.Value); obj != nil {
 111  			if tn, ok := obj.(*TypeName); ok {
 112  				return tn.Type()
 113  			}
 114  		}
 115  		if pkg != nil {
 116  			obj := pkg.Pkg.Scope().Lookup(e.Value)
 117  			if tn, ok := obj.(*TypeName); ok {
 118  				return tn.Type()
 119  			}
 120  		}
 121  	case *Operation:
 122  		if e.Y == nil && e.Op == Mul {
 123  			base := pkgResolveTypeAST(pkg, e.X)
 124  			if base != nil {
 125  				return NewPointer(base)
 126  			}
 127  		}
 128  	case *SliceType:
 129  		elem := pkgResolveTypeAST(pkg, e.Elem)
 130  		if elem != nil {
 131  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
 132  				return Typ[TCString]
 133  			}
 134  			return NewSlice(elem)
 135  		}
 136  	case *MapType:
 137  		key := pkgResolveTypeAST(pkg, e.Key)
 138  		val := pkgResolveTypeAST(pkg, e.Value)
 139  		if key != nil && val != nil {
 140  			return NewTCMap(key, val)
 141  		}
 142  	case *FuncType:
 143  		return pkgResolveSigAST(pkg, e)
 144  	case *SelectorExpr:
 145  		if x, ok := e.X.(*Name); ok {
 146  			var pn *PkgName
 147  			if okv, okok := pkg.Pkg.Scope().Lookup(x.Value).(*PkgName); okok {
 148  				pn = okv
 149  			}
 150  			if pn != nil && pn.Imported() != nil {
 151  				sel := pn.Imported().Scope().Lookup(e.Sel.Value)
 152  				if tn, ok2 := sel.(*TypeName); ok2 {
 153  					return tn.Type()
 154  				}
 155  			}
 156  		}
 157  	case *InterfaceType:
 158  		return NewTCInterface(nil, nil)
 159  	}
 160  	return nil
 161  }
 162  
 163  func pkgResolveSigAST(pkg *SSAPackage, ft *FuncType) *Signature {
 164  	if ft == nil {
 165  		return nil
 166  	}
 167  	var params []*TCVar
 168  	for _, p := range ft.ParamList {
 169  		typ := pkgResolveTypeAST(pkg, p.Type)
 170  		pname := ""
 171  		if p.Name != nil {
 172  			pname = p.Name.Value
 173  		}
 174  		params = append(params, NewTCVar(nil, pname, typ))
 175  	}
 176  	var results []*TCVar
 177  	for _, r := range ft.ResultList {
 178  		typ := pkgResolveTypeAST(pkg, r.Type)
 179  		rname := ""
 180  		if r.Name != nil {
 181  			rname = r.Name.Value
 182  		}
 183  		results = append(results, NewTCVar(nil, rname, typ))
 184  	}
 185  	var pTuple, rTuple *Tuple
 186  	if len(params) > 0 {
 187  		pTuple = NewTuple(params...)
 188  	}
 189  	if len(results) > 0 {
 190  		rTuple = NewTuple(results...)
 191  	}
 192  	return NewSignature(nil, pTuple, rTuple, false)
 193  }
 194  
 195  func (pb *ssaPkgBuilder) registerFunc(d *FuncDecl) {
 196  	if len(d.TParamList) > 0 {
 197  		return
 198  	}
 199  	if d.Recv != nil {
 200  		pb.registerMethod(d)
 201  		return
 202  	}
 203  	if d.Name.Value == "init" {
 204  		writeStr(2, "compile error: init() is not allowed; use main() for package initialization\n")
 205  		return
 206  	}
 207  	var obj *TCFunc
 208  	if o := pb.pkg.Pkg.Scope().Lookup(d.Name.Value); o != nil {
 209  		if okv, okok := o.(*TCFunc); okok {
 210  			obj = okv
 211  		}
 212  	}
 213  	var sig *Signature
 214  	if obj != nil {
 215  		if okv, okok := obj.Type().(*Signature); okok {
 216  			sig = okv
 217  		}
 218  	}
 219  	if sig == nil && d.Type != nil {
 220  		sig = pkgResolveSigAST(pb.pkg, d.Type)
 221  	}
 222  	fn := &SSAFunction{
 223  		name:      d.Name.Value,
 224  		object:    obj,
 225  		Signature: sig,
 226  		pos:       0,
 227  		Pkg:       pb.pkg,
 228  		Prog:      pb.prog,
 229  	}
 230  	if compileExportMap != nil {
 231  		if ename, ok := compileExportMap[d.Name.Value]; ok {
 232  			fn.externalSymbol = ename
 233  			fn.isExternC = true
 234  		}
 235  	}
 236  	if d.Body == nil && isNoContextExtern(pb.pkg.Pkg.Path(), d.Name.Value) {
 237  		fn.isExternC = true
 238  	}
 239  	pb.pkg.Members[fn.name] = fn
 240  }
 241  
 242  func checkInitBody(body *BlockStmt) string {
 243  	for _, s := range body.List {
 244  		if err := checkInitStmt(s); err != "" {
 245  			return err
 246  		}
 247  	}
 248  	return ""
 249  }
 250  
 251  func checkInitStmt(s Stmt) string {
 252  	switch s := s.(type) {
 253  	case *SelectStmt:
 254  		return "select{} not allowed in init()"
 255  	case *BlockStmt:
 256  		for _, sub := range s.List {
 257  			if err := checkInitStmt(sub); err != "" {
 258  				return err
 259  			}
 260  		}
 261  	case *IfStmt:
 262  		if s.Then != nil {
 263  			if err := checkInitStmt(s.Then); err != "" {
 264  				return err
 265  			}
 266  		}
 267  		if s.Else != nil {
 268  			if err := checkInitStmt(s.Else); err != "" {
 269  				return err
 270  			}
 271  		}
 272  	case *ForStmt:
 273  		if s.Body != nil {
 274  			if err := checkInitStmt(s.Body); err != "" {
 275  				return err
 276  			}
 277  		}
 278  	case *SwitchStmt:
 279  		for _, cc := range s.Body {
 280  			for _, sub := range cc.Body {
 281  				if err := checkInitStmt(sub); err != "" {
 282  					return err
 283  				}
 284  			}
 285  		}
 286  	case *ExprStmt:
 287  		if err := checkInitExpr(s.X); err != "" {
 288  			return err
 289  		}
 290  	}
 291  	return ""
 292  }
 293  
 294  func checkInitExpr(x Expr) string {
 295  	if x == nil {
 296  		return ""
 297  	}
 298  	if c, ok := x.(*CallExpr); ok {
 299  		if n, ok2 := c.Fun.(*Name); ok2 && n.Value == "spawn" {
 300  			return "spawn() not allowed in init()"
 301  		}
 302  	}
 303  	return ""
 304  }
 305  
 306  func isNoContextExtern(pkg, name string) bool {
 307  	if pkg == "internal/runtime/syscall" && name == "Syscall6" {
 308  		return true
 309  	}
 310  	if pkg == "syscall" {
 311  		switch name {
 312  		case "runtime_entersyscall", "runtime_exitsyscall",
 313  			"Exit", "Getpagesize", "gettimeofday",
 314  			"runtime_BeforeExec", "runtime_AfterExec",
 315  			"runtime_BeforeFork", "runtime_AfterFork", "runtime_AfterForkInChild":
 316  			return true
 317  		}
 318  	}
 319  	if pkg == "os" {
 320  		switch name {
 321  		case "putchar", "getchar", "buffered", "gosched", "runtime_args":
 322  			return true
 323  		}
 324  	}
 325  	return false
 326  }
 327  
 328  func (pb *ssaPkgBuilder) registerMethod(d *FuncDecl) {
 329  	recvTypeName := ssaRecvTypeName(d.Recv)
 330  	if recvTypeName == "" {
 331  		return
 332  	}
 333  	mangledName := recvTypeName | "." | d.Name.Value
 334  	var obj *TCFunc
 335  	obj = pb.findMethod(recvTypeName, d.Name.Value)
 336  	var sig *Signature
 337  	if obj != nil {
 338  		if okv, okok := obj.Type().(*Signature); okok {
 339  			sig = okv
 340  		}
 341  	}
 342  	if sig == nil && d.Type != nil {
 343  		sig = pkgResolveSigAST(pb.pkg, d.Type)
 344  	}
 345  	fn := &SSAFunction{
 346  		name:      mangledName,
 347  		object:    obj,
 348  		Signature: sig,
 349  		pos:       0,
 350  		Pkg:       pb.pkg,
 351  		Prog:      pb.prog,
 352  	}
 353  	pb.pkg.Members[mangledName] = fn
 354  }
 355  
 356  func ssaRecvTypeName(recv *Field) string {
 357  	if recv == nil {
 358  		return ""
 359  	}
 360  	switch t := recv.Type.(type) {
 361  	case *Name:
 362  		return t.Value
 363  	case *Operation:
 364  		if t.Y == nil && t.Op == Mul {
 365  			if n, ok := t.X.(*Name); ok {
 366  				return n.Value
 367  			}
 368  		}
 369  	}
 370  	return ""
 371  }
 372  
 373  func (pb *ssaPkgBuilder) findMethod(typeName string, methodName string) *TCFunc {
 374  	obj := pb.pkg.Pkg.Scope().Lookup(typeName)
 375  	if obj == nil {
 376  		return nil
 377  	}
 378  	tn, ok := obj.(*TypeName)
 379  	if !ok {
 380  		return nil
 381  	}
 382  	named, ok := tn.Type().(*Named)
 383  	if !ok {
 384  		return nil
 385  	}
 386  	for i := 0; i < named.NumMethods(); i++ {
 387  		m := named.Method(i)
 388  		if m.Name() == methodName {
 389  			return m
 390  		}
 391  	}
 392  	return nil
 393  }
 394  
 395  func (pb *ssaPkgBuilder) registerVar(d *VarDecl) {
 396  	for _, name := range d.NameList {
 397  		var obj *TCVar
 398  		if o := pb.pkg.Pkg.Scope().Lookup(name.Value); o != nil {
 399  			if okv, okok := o.(*TCVar); okok {
 400  				obj = okv
 401  			}
 402  		}
 403  		var typ Type
 404  		if obj != nil {
 405  			typ = obj.Type()
 406  		}
 407  		if typ == nil && d.Type != nil {
 408  			typ = pkgResolveTypeAST(pb.pkg, d.Type)
 409  		}
 410  		g := &SSAGlobal{
 411  			name:   name.Value,
 412  			object: obj,
 413  			typ:    NewPointer(typ),
 414  			pos:    0,
 415  			pkg:    pb.pkg,
 416  		}
 417  		if obj != nil && obj.initVal != nil {
 418  			g.initConst = obj.initVal
 419  			g.initType = typ
 420  		}
 421  		pb.pkg.Members[name.Value] = g
 422  	}
 423  }
 424  
 425  func (pb *ssaPkgBuilder) registerType(d *TypeDecl) {
 426  	var obj *TypeName
 427  	if o := pb.pkg.Pkg.Scope().Lookup(d.Name.Value); o != nil {
 428  		if okv, okok := o.(*TypeName); okok {
 429  			obj = okv
 430  		}
 431  	}
 432  	if obj == nil {
 433  		underlying := pkgResolveTypeAST(pb.pkg, d.Type)
 434  		if underlying == nil {
 435  			underlying = &TCStruct{}
 436  		}
 437  		named := NewNamed(NewTypeName(pb.pkg.Pkg, d.Name.Value, nil), underlying)
 438  		named.obj.typ = named
 439  		pb.pkg.Pkg.Scope().Insert(named.obj)
 440  		obj = named.obj
 441  	}
 442  	t := &SSAType_{object: obj, pkg: pb.pkg}
 443  	pb.pkg.Members[d.Name.Value] = t
 444  }
 445  
 446  func (pb *ssaPkgBuilder) registerConst(d *ConstDecl) {
 447  	for _, name := range d.NameList {
 448  		var obj *TCConst
 449  		if o := pb.pkg.Pkg.Scope().Lookup(name.Value); o != nil {
 450  			if okv, okok := o.(*TCConst); okok {
 451  				obj = okv
 452  			}
 453  		}
 454  		if obj == nil {
 455  			continue
 456  		}
 457  		c := &SSANamedConst{
 458  			object: obj,
 459  			Value:  &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())},
 460  			pkg:    pb.pkg,
 461  		}
 462  		pb.pkg.Members[name.Value] = c
 463  	}
 464  }
 465  
 466  func (pb *ssaPkgBuilder) buildFile(f *File) {
 467  	for _, d := range f.DeclList {
 468  		if fd, ok := d.(*FuncDecl); ok {
 469  			pb.buildFunc(fd)
 470  		}
 471  	}
 472  }
 473  
 474  func (pb *ssaPkgBuilder) buildFunc(d *FuncDecl) {
 475  	if len(d.TParamList) > 0 {
 476  		return
 477  	}
 478  	if d.Body == nil {
 479  		return
 480  	}
 481  	name := d.Name.Value
 482  	if d.Recv != nil {
 483  		rtn := ssaRecvTypeName(d.Recv)
 484  		if rtn != "" {
 485  			name = rtn | "." | d.Name.Value
 486  		}
 487  	}
 488  	var fn *SSAFunction
 489  	if okv, okok := pb.pkg.Members[name].(*SSAFunction); okok {
 490  		fn = okv
 491  	}
 492  	if fn == nil {
 493  		return
 494  	}
 495  	fb := newSSAFuncBuilder(fn, pb.info)
 496  	fb.buildBody(d)
 497  }
 498  
 499  // ssaFuncBuilder builds one SSAFunction body.
 500  type ssaFuncBuilder struct {
 501  	fn           *SSAFunction
 502  	info         *Info
 503  	parent       *ssaFuncBuilder
 504  	currentBlock *SSABasicBlock
 505  	vars         map[Object]*SSAAlloc
 506  	localTypes   map[string]Type
 507  	localConsts  map[string]*SSAConst
 508  	freeVarPtrs  map[string]*SSAFreeVar
 509  	namedResults []*SSAAlloc
 510  	paramAllocas []*SSAAlloc
 511  	tailBlock    *SSABasicBlock
 512  	counter      int32
 513  
 514  	loops        []ssaLoopState
 515  	pendingLabel string
 516  	labels       map[string]*SSABasicBlock
 517  	deferred     int32
 518  	typeSubst    map[string]Type
 519  	srcScope     *Scope
 520  }
 521  
 522  type ssaLoopState struct {
 523  	label string
 524  	body  *SSABasicBlock
 525  	post  *SSABasicBlock
 526  	done  *SSABasicBlock
 527  }
 528  
 529  func newSSAFuncBuilder(fn *SSAFunction, info *Info) *ssaFuncBuilder {
 530  	return &ssaFuncBuilder{
 531  		fn:         fn,
 532  		info:       info,
 533  		vars:       map[Object]*SSAAlloc{},
 534  		localTypes: map[string]Type{},
 535  	}
 536  }
 537  
 538  func (fb *ssaFuncBuilder) newBlock(comment string) *SSABasicBlock {
 539  	return NewSSABasicBlock(fb.fn, comment)
 540  }
 541  
 542  func (fb *ssaFuncBuilder) labelBlock(name string) *SSABasicBlock {
 543  	if fb.labels == nil {
 544  		fb.labels = map[string]*SSABasicBlock{}
 545  	}
 546  	if b := fb.labels[name]; b != nil {
 547  		return b
 548  	}
 549  	b := fb.newBlock("label." + name)
 550  	fb.labels[name] = b
 551  	return b
 552  }
 553  
 554  func (fb *ssaFuncBuilder) emit(instr SSAInstruction) {
 555  	if fb.currentBlock == nil {
 556  		return
 557  	}
 558  	instr.setBlock(fb.currentBlock)
 559  	fb.currentBlock.Instrs = append(fb.currentBlock.Instrs, instr)
 560  }
 561  
 562  func (fb *ssaFuncBuilder) nextName() string {
 563  	fb.counter++
 564  	return "t" | ssaItoa(fb.counter)
 565  }
 566  
 567  func (fb *ssaFuncBuilder) buildBody(d *FuncDecl) {
 568  	entry := fb.newBlock("entry")
 569  	fb.currentBlock = entry
 570  
 571  	sig := fb.fn.Signature
 572  	if sig == nil {
 573  		return
 574  	}
 575  	params := sig.Params()
 576  	if d.Recv != nil {
 577  		recv := sig.Recv()
 578  		if recv != nil {
 579  			recvName := recv.Name()
 580  			if recvName == "" && d.Recv.Name != nil {
 581  				recvName = d.Recv.Name.Value
 582  			}
 583  			p := &SSAParameter{
 584  				name:   recvName,
 585  				typ:    recv.Type(),
 586  				pos:    0,
 587  				parent: fb.fn,
 588  			}
 589  			fb.fn.Params = append(fb.fn.Params, p)
 590  			if recvName != "" && recvName != "_" {
 591  				recvObj := NewTCVar(fb.fn.Pkg.Pkg, recvName, recv.Type())
 592  				p.object = recvObj
 593  				alloc := fb.emitAlloc(recv.Type(), 0)
 594  				fb.vars[recvObj] = alloc
 595  				fb.paramAllocas = append(fb.paramAllocas, alloc)
 596  				fb.emitStore(alloc, p)
 597  			}
 598  		}
 599  	}
 600  	if params != nil {
 601  		for i := 0; i < params.Len(); i++ {
 602  			pvar := params.At(i)
 603  			p := &SSAParameter{
 604  				name:   pvar.Name(),
 605  				typ:    pvar.Type(),
 606  				pos:    fb.fn.pos,
 607  				parent: fb.fn,
 608  			}
 609  			fb.fn.Params = append(fb.fn.Params, p)
 610  			if pvar.Name() != "" && pvar.Name() != "_" {
 611  				obj := NewTCVar(fb.fn.Pkg.Pkg, pvar.Name(), pvar.Type())
 612  				alloc := fb.emitAlloc(pvar.Type(), p.pos)
 613  				fb.vars[obj] = alloc
 614  				fb.paramAllocas = append(fb.paramAllocas, alloc)
 615  				fb.emitStore(alloc, p)
 616  			}
 617  		}
 618  	}
 619  
 620  	if sig.Results() != nil {
 621  		for i := 0; i < sig.Results().Len(); i++ {
 622  			r := sig.Results().At(i)
 623  			if r.Name() != "" && r.Name() != "_" {
 624  				alloc := fb.emitAlloc(r.Type(), fb.fn.pos)
 625  				fb.namedResults = append(fb.namedResults, alloc)
 626  				fb.fn.Locals = append(fb.fn.Locals, alloc)
 627  				fb.vars[r] = alloc
 628  			}
 629  		}
 630  	}
 631  
 632  	if len(fb.paramAllocas) > 0 {
 633  		fb.tailBlock = fb.newBlock("tailcall")
 634  		fb.emit(&SSAJump{Comment: "enter.body"})
 635  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, fb.tailBlock)
 636  		fb.tailBlock.Preds = append(fb.tailBlock.Preds, fb.currentBlock)
 637  		fb.currentBlock = fb.tailBlock
 638  	}
 639  
 640  	if d.Body != nil {
 641  		fb.buildBlock(d.Body)
 642  	}
 643  
 644  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
 645  		if len(fb.namedResults) > 0 {
 646  			var vals []SSAValue
 647  			for _, nr := range fb.namedResults {
 648  				elemType := nr.SSAType()
 649  				if p, ok := elemType.(*Pointer); ok {
 650  					elemType = p.Elem()
 651  				}
 652  				vals = append(vals, fb.emitLoad(nr, elemType))
 653  			}
 654  			fb.emitReturn(vals, 0)
 655  		} else {
 656  			fb.emitReturn(nil, 0)
 657  		}
 658  	}
 659  	fb.fn.NamedResults = fb.namedResults
 660  }
 661  
 662  func (fb *ssaFuncBuilder) emitAlloc(typ Type, pos int32) *SSAAlloc {
 663  	a := &SSAAlloc{Heap: false}
 664  	a.typ = NewPointer(typ)
 665  	a.pos = pos
 666  	a.name = fb.nextName()
 667  	fb.emit(a)
 668  	fb.fn.Locals = append(fb.fn.Locals, a)
 669  	return a
 670  }
 671  
 672  func (fb *ssaFuncBuilder) emitStore(addr SSAValue, val SSAValue) {
 673  	fb.emit(&SSAStore{Addr: addr, Val: val})
 674  }
 675  
 676  func (fb *ssaFuncBuilder) emitLoad(addr SSAValue, typ Type) SSAValue {
 677  	u := &SSAUnOp{Op: OpMul, X: addr}
 678  	u.typ = typ
 679  	u.name = fb.nextName()
 680  	fb.emit(u)
 681  	return u
 682  }
 683  
 684  func (fb *ssaFuncBuilder) emitReturn(vals []SSAValue, pos int32) {
 685  	fb.emit(&SSAReturn{Results: vals, pos: pos})
 686  	fb.currentBlock = nil
 687  }
 688  
 689  func (fb *ssaFuncBuilder) blockTerminated(b *SSABasicBlock) bool {
 690  	if len(b.Instrs) == 0 {
 691  		return false
 692  	}
 693  	switch b.Instrs[len(b.Instrs)-1].(type) {
 694  	case *SSAReturn, *SSAJump, *SSAIf, *SSAPanic:
 695  		return true
 696  	}
 697  	return false
 698  }
 699  
 700  // Statement builders.
 701  
 702  func (fb *ssaFuncBuilder) buildBlock(b *BlockStmt) {
 703  	if b == nil {
 704  		return
 705  	}
 706  	for _, s := range b.List {
 707  		fb.buildStmt(s)
 708  	}
 709  }
 710  
 711  func (fb *ssaFuncBuilder) buildStmt(s Stmt) {
 712  	if s == nil {
 713  		return
 714  	}
 715  	if ls, ok := s.(*LabeledStmt); ok {
 716  		if ls.Label != nil {
 717  			fb.pendingLabel = ls.Label.Value
 718  			lblBlock := fb.labelBlock(ls.Label.Value)
 719  			if fb.currentBlock != nil {
 720  				fb.emit(&SSAJump{Comment: "goto.label." + ls.Label.Value})
 721  				fb.currentBlock.Succs = append(fb.currentBlock.Succs, lblBlock)
 722  				lblBlock.Preds = append(lblBlock.Preds, fb.currentBlock)
 723  			}
 724  			fb.currentBlock = lblBlock
 725  		}
 726  		fb.buildStmt(ls.Stmt)
 727  		fb.pendingLabel = ""
 728  		return
 729  	}
 730  	if fb.currentBlock == nil {
 731  		return
 732  	}
 733  	switch s := s.(type) {
 734  	case *EmptyStmt:
 735  		// nothing
 736  	case *ExprStmt:
 737  		fb.buildExpr(s.X)
 738  	case *AssignStmt:
 739  		fb.buildAssign(s)
 740  	case *BlockStmt:
 741  		fb.buildBlock(s)
 742  	case *DeclStmt:
 743  		for _, d := range s.DeclList {
 744  			fb.buildLocalDecl(d)
 745  		}
 746  	case *IfStmt:
 747  		fb.buildIf(s)
 748  	case *ForStmt:
 749  		fb.buildFor(s)
 750  	case *SwitchStmt:
 751  		fb.buildSwitch(s)
 752  	case *SelectStmt:
 753  		fb.buildSelect(s)
 754  	case *ReturnStmt:
 755  		fb.buildReturn(s)
 756  	case *BranchStmt:
 757  		fb.buildBranch(s)
 758  	case *SendStmt:
 759  		ch := fb.buildExpr(s.Chan)
 760  		val := fb.buildExpr(s.Value)
 761  		if ch != nil && val != nil {
 762  			fb.emit(&SSASend{Chan: ch, X: val})
 763  		}
 764  	case *CallStmt:
 765  		var call *CallExpr
 766  		if okv, okok := s.Call.(*CallExpr); okok {
 767  			call = okv
 768  		}
 769  		switch s.Tok {
 770  		case Go:
 771  			if call != nil {
 772  				fb.buildGoStmt(call)
 773  			}
 774  		case Defer:
 775  			if call != nil {
 776  				fb.buildDeferStmt(call)
 777  			}
 778  		default:
 779  			fb.buildExpr(s.Call)
 780  		}
 781  	}
 782  }
 783  
 784  func (fb *ssaFuncBuilder) buildAssign(s *AssignStmt) {
 785  	if s.Rhs == nil {
 786  		lv := fb.buildExpr(s.Lhs)
 787  		if lv == nil {
 788  			return
 789  		}
 790  		one := &SSAConst{typ: lv.SSAType(), val: constInt{1}}
 791  		op := OpAdd
 792  		if s.Op == Sub {
 793  			op = OpSub
 794  		}
 795  		bin := &SSABinOp{Op: op, X: lv, Y: one}
 796  		bin.typ = lv.SSAType()
 797  		bin.name = fb.nextName()
 798  		fb.emit(bin)
 799  		fb.buildStore(s.Lhs, bin)
 800  		return
 801  	}
 802  	if s.Op == Def {
 803  		fb.buildShortVarDecl(s)
 804  		return
 805  	}
 806  	if s.Op != 0 {
 807  		lv := fb.buildExpr(s.Lhs)
 808  		rv := fb.buildExpr(s.Rhs)
 809  		if lv == nil || rv == nil {
 810  			return
 811  		}
 812  		op := compoundOp(s.Op)
 813  		bin := &SSABinOp{Op: op, X: lv, Y: rv}
 814  		bin.typ = lv.SSAType()
 815  		bin.name = fb.nextName()
 816  		fb.emit(bin)
 817  		fb.buildStore(s.Lhs, bin)
 818  		return
 819  	}
 820  	lhsList, lhsIsList := s.Lhs.(*ListExpr)
 821  	rhsList, rhsIsList := s.Rhs.(*ListExpr)
 822  	if lhsIsList && rhsIsList && len(lhsList.ElemList) == len(rhsList.ElemList) {
 823  		vals := []SSAValue{:len(rhsList.ElemList)}
 824  		for i, re := range rhsList.ElemList {
 825  			vals[i] = fb.buildExpr(re)
 826  		}
 827  		for i, le := range lhsList.ElemList {
 828  			if vals[i] != nil {
 829  				fb.buildStore(le, vals[i])
 830  			}
 831  		}
 832  		return
 833  	}
 834  	if lhsIsList && len(lhsList.ElemList) == 2 {
 835  		if ae, ok := s.Rhs.(*AssertExpr); ok {
 836  			x := fb.buildExpr(ae.X)
 837  			assertedType := fb.resolveType(ae.Type)
 838  			if x != nil && assertedType != nil {
 839  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
 840  				ta.typ = NewTuple(
 841  					NewTCVar(nil, "val", assertedType),
 842  					NewTCVar(nil, "ok", Typ[Bool]),
 843  				)
 844  				ta.name = fb.nextName()
 845  				fb.emit(ta)
 846  				for i, le := range lhsList.ElemList {
 847  					if n, ok := le.(*Name); ok && n.Value == "_" {
 848  						continue
 849  					}
 850  					ext := &SSAExtract{Tuple: ta, Index: i}
 851  					ext.typ = ssaTupleElemType(ta.typ, i)
 852  					ext.name = fb.nextName()
 853  					fb.emit(ext)
 854  					fb.buildStore(le, ext)
 855  				}
 856  				return
 857  			}
 858  		}
 859  		if ie, ok := s.Rhs.(*IndexExpr); ok {
 860  			x := fb.buildExpr(ie.X)
 861  			idx := fb.buildExpr(ie.Index)
 862  			if x != nil && idx != nil {
 863  				if mt, ok2 := safeUnderlying(x.SSAType()).(*TCMap); ok2 {
 864  					idx = fb.coerceToInterface(idx, mt.Key())
 865  					l := &SSALookup{X: x, Index: idx, CommaOk: true}
 866  					l.typ = NewTuple(
 867  						NewTCVar(nil, "v", mt.Elem()),
 868  						NewTCVar(nil, "ok", Typ[Bool]),
 869  					)
 870  					l.name = fb.nextName()
 871  					fb.emit(l)
 872  					for i, le := range lhsList.ElemList {
 873  						if n, ok := le.(*Name); ok && n.Value == "_" {
 874  							continue
 875  						}
 876  						ext := &SSAExtract{Tuple: l, Index: i}
 877  						ext.typ = ssaTupleElemType(l.typ, i)
 878  						ext.name = fb.nextName()
 879  						fb.emit(ext)
 880  						fb.buildStore(le, ext)
 881  					}
 882  					return
 883  				}
 884  			}
 885  		}
 886  	}
 887  	rhs := fb.buildExpr(s.Rhs)
 888  	if rhs == nil {
 889  		return
 890  	}
 891  	fb.buildStore(s.Lhs, rhs)
 892  }
 893  
 894  func (fb *ssaFuncBuilder) coerceToInterface(val SSAValue, targetType Type) SSAValue {
 895  	if targetType == nil || val == nil || val.SSAType() == nil {
 896  		return val
 897  	}
 898  	if _, isIface := safeUnderlying(targetType).(*TCInterface); isIface {
 899  		if _, alreadyIface := safeUnderlying(val.SSAType()).(*TCInterface); !alreadyIface {
 900  			mi := &SSAMakeInterface{X: val}
 901  			mi.typ = targetType
 902  			mi.name = fb.nextName()
 903  			fb.emit(mi)
 904  			return mi
 905  		}
 906  	}
 907  	return val
 908  }
 909  
 910  func (fb *ssaFuncBuilder) buildStore(lhs Expr, val SSAValue) {
 911  	if lhs == nil {
 912  		panic("buildStore: nil lhs")
 913  	}
 914  	switch lhs := lhs.(type) {
 915  	case *Name:
 916  		if lhs == nil {
 917  			panic("buildStore: nil *Name after type switch")
 918  		}
 919  		if lhs.Value == "_" {
 920  			return
 921  		}
 922  		obj := fb.lookupObject(lhs.Value)
 923  		if obj == nil {
 924  			return
 925  		}
 926  		if alloc, ok := fb.vars[obj]; ok {
 927  			val = fb.coerceToInterface(val, obj.Type())
 928  			fb.emitStore(alloc, val)
 929  		} else if fv, ok := fb.freeVarPtrs[lhs.Value]; ok {
 930  			val = fb.coerceToInterface(val, obj.Type())
 931  			fb.emitStore(fv, val)
 932  		} else if g, ok := fb.fn.Pkg.Members[lhs.Value].(*SSAGlobal); ok {
 933  			if p, ok2 := g.SSAType().(*Pointer); ok2 && p.Elem() != nil {
 934  				val = fb.coerceToInterface(val, p.Elem())
 935  			}
 936  			fb.emitStore(g, val)
 937  		}
 938  	case *Operation:
 939  		if lhs.Y == nil && lhs.Op == Mul {
 940  			ptr := fb.buildExpr(lhs.X)
 941  			if ptr != nil {
 942  				if p, ok2 := ptr.SSAType().(*Pointer); ok2 && p.Elem() != nil {
 943  					val = fb.coerceToInterface(val, p.Elem())
 944  				}
 945  				fb.emitStore(ptr, val)
 946  			}
 947  		}
 948  	case *SelectorExpr:
 949  		addr := fb.buildSelectorAddr(lhs)
 950  		if addr == nil {
 951  			return
 952  		}
 953  		if p, ok2 := addr.SSAType().(*Pointer); ok2 && p.Elem() != nil {
 954  			val = fb.coerceToInterface(val, p.Elem())
 955  		}
 956  		fb.emitStore(addr, val)
 957  	case *IndexExpr:
 958  		base := fb.buildExpr(lhs.X)
 959  		idx := fb.buildExpr(lhs.Index)
 960  		if base == nil || idx == nil {
 961  			return
 962  		}
 963  		if m, isMap := safeUnderlying(base.SSAType()).(*TCMap); isMap {
 964  			idx = fb.coerceToInterface(idx, m.Key())
 965  			val = fb.coerceToInterface(val, m.Elem())
 966  			fb.emit(&SSAMapUpdate{Map: base, Key: idx, Value: val})
 967  			return
 968  		}
 969  		// For array LHS assignment, resolve the address of the base directly
 970  		// so SSAIndexAddr GEPs into the original, not a stack copy.
 971  		var baseAddr SSAValue
 972  		if n, ok := lhs.X.(*Name); ok {
 973  			obj := fb.lookupObject(n.Value)
 974  			if obj != nil {
 975  				if alloc, ok2 := fb.vars[obj]; ok2 {
 976  					baseAddr = alloc
 977  				} else if g, ok2 := fb.fn.Pkg.Members[n.Value].(*SSAGlobal); ok2 {
 978  					baseAddr = g
 979  				}
 980  			}
 981  		} else if sel, ok := lhs.X.(*SelectorExpr); ok {
 982  			baseAddr = fb.buildSelectorAddr(sel)
 983  		}
 984  		if baseAddr != nil {
 985  			if _, isArr := safeUnderlying(base.SSAType()).(*Array); isArr {
 986  				ia := &SSAIndexAddr{X: baseAddr, Index: idx}
 987  				ia.typ = NewPointer(ssaElemType(base.SSAType()))
 988  				ia.name = fb.nextName()
 989  				fb.emit(ia)
 990  				if p, ok2 := ia.SSAType().(*Pointer); ok2 && p.Elem() != nil {
 991  					val = fb.coerceToInterface(val, p.Elem())
 992  				}
 993  				fb.emitStore(ia, val)
 994  				return
 995  			}
 996  		}
 997  		ia := &SSAIndexAddr{X: base, Index: idx}
 998  		ia.typ = NewPointer(ssaElemType(base.SSAType()))
 999  		ia.name = fb.nextName()
1000  		fb.emit(ia)
1001  		if p, ok2 := ia.SSAType().(*Pointer); ok2 && p.Elem() != nil {
1002  			val = fb.coerceToInterface(val, p.Elem())
1003  		}
1004  		fb.emitStore(ia, val)
1005  	case *ListExpr:
1006  		for i, e := range lhs.ElemList {
1007  			ext := &SSAExtract{Tuple: val, Index: i}
1008  			ext.typ = ssaTupleElemType(val.SSAType(), i)
1009  			ext.name = fb.nextName()
1010  			fb.emit(ext)
1011  			fb.buildStore(e, ext)
1012  		}
1013  	}
1014  }
1015  
1016  func (fb *ssaFuncBuilder) buildShortVarDecl(s *AssignStmt) {
1017  	names := ssaExprNames(s.Lhs)
1018  	if len(names) == 2 {
1019  		if ae, ok := s.Rhs.(*AssertExpr); ok {
1020  			x := fb.buildExpr(ae.X)
1021  			assertedType := fb.resolveType(ae.Type)
1022  			if x != nil && assertedType != nil {
1023  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1024  				ta.typ = NewTuple(
1025  					NewTCVar(nil, "val", assertedType),
1026  					NewTCVar(nil, "ok", Typ[Bool]),
1027  				)
1028  				ta.name = fb.nextName()
1029  				fb.emit(ta)
1030  				for i, name := range names {
1031  					if name.Value == "_" {
1032  						continue
1033  					}
1034  					ext := &SSAExtract{Tuple: ta, Index: i}
1035  					ext.typ = ssaTupleElemType(ta.typ, i)
1036  					ext.name = fb.nextName()
1037  					fb.emit(ext)
1038  					fb.removeVar(name.Value)
1039  					obj := NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1040  					alloc := fb.emitAlloc(ext.typ, 0)
1041  					fb.vars[obj] = alloc
1042  					fb.emitStore(alloc, ext)
1043  				}
1044  				return
1045  			}
1046  		}
1047  		if ie, ok := s.Rhs.(*IndexExpr); ok {
1048  			x := fb.buildExpr(ie.X)
1049  			idx := fb.buildExpr(ie.Index)
1050  			if x != nil && idx != nil {
1051  				if mt, ok2 := safeUnderlying(x.SSAType()).(*TCMap); ok2 {
1052  					idx = fb.coerceToInterface(idx, mt.Key())
1053  					l := &SSALookup{X: x, Index: idx, CommaOk: true}
1054  					l.typ = NewTuple(
1055  						NewTCVar(nil, "v", mt.Elem()),
1056  						NewTCVar(nil, "ok", Typ[Bool]),
1057  					)
1058  					l.name = fb.nextName()
1059  					fb.emit(l)
1060  					for i, name := range names {
1061  						if name.Value == "_" {
1062  							continue
1063  						}
1064  						ext := &SSAExtract{Tuple: l, Index: i}
1065  						ext.typ = ssaTupleElemType(l.typ, i)
1066  						ext.name = fb.nextName()
1067  						fb.emit(ext)
1068  						fb.removeVar(name.Value)
1069  						var obj Object
1070  						if fb.info != nil {
1071  							obj = fb.info.Defs[name]
1072  						}
1073  						if obj == nil {
1074  							obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1075  						}
1076  						alloc := fb.emitAlloc(ext.typ, 0)
1077  						fb.vars[obj] = alloc
1078  						fb.emitStore(alloc, ext)
1079  					}
1080  					return
1081  				}
1082  			}
1083  		}
1084  	}
1085  	if rhsList, ok := s.Rhs.(*ListExpr); ok && len(rhsList.ElemList) == len(names) {
1086  		vals := []SSAValue{:len(rhsList.ElemList)}
1087  		for i, re := range rhsList.ElemList {
1088  			vals[i] = fb.buildExpr(re)
1089  		}
1090  		for i, name := range names {
1091  			if name.Value == "_" {
1092  				continue
1093  			}
1094  			var typ Type
1095  			if vals[i] != nil {
1096  				typ = vals[i].SSAType()
1097  			}
1098  			fb.removeVar(name.Value)
1099  			var obj Object
1100  			if fb.info != nil {
1101  				obj = fb.info.Defs[name]
1102  			}
1103  			if obj == nil {
1104  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1105  			}
1106  			alloc := fb.emitAlloc(typ, 0)
1107  			fb.vars[obj] = alloc
1108  			if vals[i] != nil {
1109  				fb.emitStore(alloc, vals[i])
1110  			}
1111  		}
1112  		return
1113  	}
1114  
1115  	rhs := fb.buildExpr(s.Rhs)
1116  
1117  	isTuple := false
1118  	var tup *Tuple
1119  	if rhs != nil {
1120  		tup, isTuple = rhs.SSAType().(*Tuple)
1121  	}
1122  	for i, name := range names {
1123  		if name.Value == "_" {
1124  			continue
1125  		}
1126  		var typ Type
1127  		if rhs != nil {
1128  			if isTuple && i < tup.Len() {
1129  				typ = tup.At(i).Type()
1130  			} else if i == 0 {
1131  				typ = rhs.SSAType()
1132  			}
1133  		}
1134  		if typ == nil {
1135  			typ = Typ[Int32]
1136  		}
1137  		fb.removeVar(name.Value)
1138  		var obj Object
1139  		if fb.info != nil {
1140  			obj = fb.info.Defs[name]
1141  		}
1142  		if obj == nil {
1143  			obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1144  		}
1145  		alloc := fb.emitAlloc(typ, 0)
1146  		fb.vars[obj] = alloc
1147  		var initVal SSAValue
1148  		if rhs != nil {
1149  			if isTuple {
1150  				ext := &SSAExtract{Tuple: rhs, Index: i}
1151  				ext.typ = typ
1152  				ext.name = fb.nextName()
1153  				fb.emit(ext)
1154  				initVal = ext
1155  			} else if i == 0 {
1156  				initVal = rhs
1157  			}
1158  		}
1159  		if initVal != nil {
1160  			fb.emitStore(alloc, initVal)
1161  		}
1162  	}
1163  }
1164  
1165  func (fb *ssaFuncBuilder) buildLocalDecl(d Decl) {
1166  	switch d := d.(type) {
1167  	case *VarDecl:
1168  		var typ Type
1169  		if fb.info != nil && len(d.NameList) > 0 {
1170  			if obj := fb.info.Defs[d.NameList[0]]; obj != nil {
1171  				typ = obj.Type()
1172  			}
1173  		}
1174  		if typ == nil && d.Type != nil {
1175  			typ = fb.resolveType(d.Type)
1176  		}
1177  		initVal := fb.buildExpr(d.Values)
1178  		for _, name := range d.NameList {
1179  			if name.Value == "_" {
1180  				continue
1181  			}
1182  			fb.removeVar(name.Value)
1183  			var obj Object
1184  			if fb.info != nil {
1185  				obj = fb.info.Defs[name]
1186  			}
1187  			if obj == nil {
1188  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, typ)
1189  			}
1190  			alloc := fb.emitAlloc(obj.Type(), 0)
1191  			fb.vars[obj] = alloc
1192  			fb.fn.Locals = append(fb.fn.Locals, alloc)
1193  			if initVal != nil {
1194  				initVal = fb.coerceToInterface(initVal, obj.Type())
1195  				fb.emitStore(alloc, initVal)
1196  			} else {
1197  				fb.emitStore(alloc, &SSAConst{typ: obj.Type(), val: nil})
1198  			}
1199  		}
1200  	case *ConstDecl:
1201  		if d.Values != nil && len(d.NameList) > 0 {
1202  			if fb.localConsts == nil {
1203  				fb.localConsts = map[string]*SSAConst{}
1204  			}
1205  			if list, ok := d.Values.(*ListExpr); ok {
1206  				for i, name := range d.NameList {
1207  					if i < len(list.ElemList) {
1208  						if v := fb.buildExpr(list.ElemList[i]); v != nil {
1209  							if c, ok2 := v.(*SSAConst); ok2 {
1210  								fb.localConsts[name.Value] = c
1211  							}
1212  						}
1213  					}
1214  				}
1215  			} else if len(d.NameList) == 1 {
1216  				if v := fb.buildExpr(d.Values); v != nil {
1217  					if c, ok2 := v.(*SSAConst); ok2 {
1218  						fb.localConsts[d.NameList[0].Value] = c
1219  					}
1220  				}
1221  			}
1222  		}
1223  	case *TypeDecl:
1224  		if d.Name != nil {
1225  			resolved := fb.resolveTypeAST(d.Type)
1226  			if resolved != nil {
1227  				fb.localTypes[d.Name.Value] = resolved
1228  			}
1229  		}
1230  	}
1231  }
1232  
1233  func (fb *ssaFuncBuilder) buildIf(s *IfStmt) {
1234  	var savedVars map[Object]*SSAAlloc
1235  	if s.Init != nil {
1236  		savedVars = fb.saveVars()
1237  		fb.buildStmt(s.Init)
1238  	}
1239  	if fb.currentBlock == nil {
1240  		if savedVars != nil {
1241  			fb.vars = savedVars
1242  		}
1243  		return
1244  	}
1245  	cond := fb.buildExpr(s.Cond)
1246  	if cond == nil {
1247  		if savedVars != nil {
1248  			fb.vars = savedVars
1249  		}
1250  		return
1251  	}
1252  
1253  	thenBlock := fb.newBlock("if.then")
1254  	var elseBlock *SSABasicBlock
1255  	doneBlock := fb.newBlock("if.done")
1256  
1257  	if s.Else != nil {
1258  		elseBlock = fb.newBlock("if.else")
1259  	} else {
1260  		elseBlock = doneBlock
1261  	}
1262  
1263  	fb.emit(&SSAIf{Cond: cond})
1264  	fb.currentBlock.Succs = append(fb.currentBlock.Succs, thenBlock, elseBlock)
1265  	thenBlock.Preds = append(thenBlock.Preds, fb.currentBlock)
1266  	elseBlock.Preds = append(elseBlock.Preds, fb.currentBlock)
1267  
1268  	fb.currentBlock = thenBlock
1269  	fb.buildBlock(s.Then)
1270  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1271  		fb.emit(&SSAJump{Comment: "if.done"})
1272  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1273  		doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1274  	}
1275  
1276  	if s.Else != nil {
1277  		fb.currentBlock = elseBlock
1278  		fb.buildStmt(s.Else)
1279  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1280  			fb.emit(&SSAJump{Comment: "if.done"})
1281  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1282  			doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1283  		}
1284  	}
1285  
1286  	fb.currentBlock = doneBlock
1287  	if savedVars != nil {
1288  		fb.vars = savedVars
1289  	}
1290  }
1291  
1292  func (fb *ssaFuncBuilder) buildFor(s *ForStmt) {
1293  	var savedVars map[Object]*SSAAlloc
1294  	if s.Init != nil {
1295  		if rc, ok := s.Init.(*RangeClause); ok {
1296  			fb.buildRangeLoop(s, rc)
1297  			return
1298  		}
1299  		savedVars = fb.saveVars()
1300  		fb.buildStmt(s.Init)
1301  	}
1302  
1303  	condBlock := fb.newBlock("for.cond")
1304  	bodyBlock := fb.newBlock("for.body")
1305  	postBlock := fb.newBlock("for.post")
1306  	doneBlock := fb.newBlock("for.done")
1307  
1308  	fb.emit(&SSAJump{Comment: "for.cond"})
1309  	fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1310  	condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1311  
1312  	fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: postBlock, done: doneBlock})
1313  	fb.pendingLabel = ""
1314  
1315  	fb.currentBlock = condBlock
1316  	if s.Cond != nil {
1317  		cond := fb.buildExpr(s.Cond)
1318  		if cond != nil {
1319  			fb.emit(&SSAIf{Cond: cond})
1320  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock, doneBlock)
1321  			bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1322  			doneBlock.Preds = append(doneBlock.Preds, condBlock)
1323  		}
1324  	} else {
1325  		fb.emit(&SSAJump{Comment: "for.body"})
1326  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock)
1327  		bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1328  	}
1329  
1330  	fb.currentBlock = bodyBlock
1331  	fb.buildBlock(s.Body)
1332  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1333  		fb.emit(&SSAJump{Comment: "for.post"})
1334  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, postBlock)
1335  		postBlock.Preds = append(postBlock.Preds, fb.currentBlock)
1336  	}
1337  
1338  	fb.currentBlock = postBlock
1339  	if s.Post != nil {
1340  		fb.buildStmt(s.Post)
1341  	}
1342  	if fb.currentBlock != nil {
1343  		fb.emit(&SSAJump{Comment: "for.cond"})
1344  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1345  		condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1346  	}
1347  
1348  	fb.loops = fb.loops[:len(fb.loops)-1]
1349  	fb.currentBlock = doneBlock
1350  	if savedVars != nil {
1351  		fb.vars = savedVars
1352  	}
1353  }
1354  
1355  func (fb *ssaFuncBuilder) buildRangeLoop(s *ForStmt, rc *RangeClause) {
1356  	iterExpr := fb.buildExpr(rc.X)
1357  	if iterExpr == nil {
1358  		return
1359  	}
1360  
1361  	r := &SSARange{X: iterExpr}
1362  	r.typ = Typ[Invalid]
1363  	r.name = fb.nextName()
1364  	fb.emit(r)
1365  
1366  	bodyBlock := fb.newBlock("range.body")
1367  	doneBlock := fb.newBlock("range.done")
1368  
1369  	condBlock := fb.newBlock("range.cond")
1370  
1371  	fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, body: bodyBlock, post: condBlock, done: doneBlock})
1372  	fb.pendingLabel = ""
1373  	fb.emit(&SSAJump{Comment: "range.cond"})
1374  	fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1375  	condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1376  
1377  	fb.currentBlock = condBlock
1378  	iterSSAType := iterExpr.SSAType()
1379  	nxt := &SSANext{Iter: r, IsString: ssaIsStringType(iterSSAType)}
1380  	keyTyp := asType(Typ[Int32])
1381  	valTyp := asType(Typ[Invalid])
1382  	iterT := iterExpr.SSAType()
1383  	iterU := safeUnderlying(iterT)
1384  	if sl, ok := iterU.(*Slice); ok {
1385  		valTyp = sl.Elem()
1386  	} else if sl, ok := iterT.(*Slice); ok {
1387  		valTyp = sl.Elem()
1388  	} else if mt, ok := iterU.(*TCMap); ok {
1389  		keyTyp = mt.Key()
1390  		valTyp = mt.Elem()
1391  	} else if mt, ok := iterT.(*TCMap); ok {
1392  		keyTyp = mt.Key()
1393  		valTyp = mt.Elem()
1394  	} else if ar, ok := iterU.(*Array); ok {
1395  		valTyp = ar.Elem()
1396  	} else if ar, ok := iterT.(*Array); ok {
1397  		valTyp = ar.Elem()
1398  	}
1399  	nxt.typ = NewTuple(
1400  		NewTCVar(nil, "ok", Typ[Bool]),
1401  		NewTCVar(nil, "k", keyTyp),
1402  		NewTCVar(nil, "v", valTyp),
1403  	)
1404  	nxt.name = fb.nextName()
1405  	fb.emit(nxt)
1406  
1407  	okExt := &SSAExtract{Tuple: nxt, Index: 0}
1408  	okExt.typ = Typ[Bool]
1409  	okExt.name = fb.nextName()
1410  	fb.emit(okExt)
1411  
1412  	fb.emit(&SSAIf{Cond: okExt})
1413  	fb.currentBlock.Succs = append(fb.currentBlock.Succs, bodyBlock, doneBlock)
1414  	bodyBlock.Preds = append(bodyBlock.Preds, condBlock)
1415  	doneBlock.Preds = append(doneBlock.Preds, condBlock)
1416  
1417  	fb.currentBlock = bodyBlock
1418  	if rc.Lhs != nil && rc.Def {
1419  		names := ssaExprNames(rc.Lhs)
1420  		for i, name := range names {
1421  			if name.Value == "_" {
1422  				continue
1423  			}
1424  			ext := &SSAExtract{Tuple: nxt, Index: i + 1}
1425  			ext.typ = ssaTupleElemType(nxt.typ, i+1)
1426  			ext.name = fb.nextName()
1427  			fb.emit(ext)
1428  			var obj Object
1429  			if fb.info != nil {
1430  				obj = fb.info.Defs[name]
1431  			}
1432  			if obj == nil {
1433  				obj = NewTCVar(fb.fn.Pkg.Pkg, name.Value, ext.typ)
1434  			}
1435  			fb.removeVar(name.Value)
1436  			alloc := fb.emitAlloc(ext.typ, 0)
1437  			fb.vars[obj] = alloc
1438  			fb.emitStore(alloc, ext)
1439  		}
1440  	}
1441  	fb.buildBlock(s.Body)
1442  	if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1443  		fb.emit(&SSAJump{Comment: "range.cond"})
1444  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, condBlock)
1445  		condBlock.Preds = append(condBlock.Preds, fb.currentBlock)
1446  	}
1447  
1448  	fb.loops = fb.loops[:len(fb.loops)-1]
1449  	fb.currentBlock = doneBlock
1450  }
1451  
1452  func (fb *ssaFuncBuilder) buildSwitch(s *SwitchStmt) {
1453  	var savedVars map[Object]*SSAAlloc
1454  	if s.Init != nil {
1455  		savedVars = fb.saveVars()
1456  		fb.buildStmt(s.Init)
1457  	}
1458  	if fb.currentBlock == nil {
1459  		if savedVars != nil {
1460  			fb.vars = savedVars
1461  		}
1462  		return
1463  	}
1464  
1465  	doneBlock := fb.newBlock("switch.done")
1466  	savedLoops := fb.loops
1467  	fb.loops = append(fb.loops, ssaLoopState{label: fb.pendingLabel, done: doneBlock})
1468  	fb.pendingLabel = ""
1469  
1470  	if s.Tag != nil {
1471  		if tsg, ok := s.Tag.(*TypeSwitchGuard); ok {
1472  			fb.buildTypeSwitch(s, tsg, doneBlock)
1473  			fb.loops = savedLoops
1474  			fb.currentBlock = doneBlock
1475  			if savedVars != nil {
1476  				fb.vars = savedVars
1477  			}
1478  			return
1479  		}
1480  	}
1481  
1482  	var tag SSAValue
1483  	if s.Tag != nil {
1484  		tag = fb.buildExpr(s.Tag)
1485  	}
1486  
1487  	for _, clause := range s.Body {
1488  		caseBlock := fb.newBlock("switch.case")
1489  		nextBlock := fb.newBlock("switch.next")
1490  
1491  		if clause.Cases != nil && tag != nil {
1492  			var cond SSAValue
1493  			caseExprs := []Expr{clause.Cases}
1494  			if list, ok := clause.Cases.(*ListExpr); ok {
1495  				caseExprs = list.ElemList
1496  			}
1497  			for _, ce := range caseExprs {
1498  				caseVal := fb.buildExpr(ce)
1499  				cmp := &SSABinOp{Op: OpEql, X: tag, Y: caseVal}
1500  				cmp.typ = Typ[Bool]
1501  				cmp.name = fb.nextName()
1502  				fb.emit(cmp)
1503  				if cond == nil {
1504  					cond = cmp
1505  				} else {
1506  					orOp := &SSABinOp{Op: OpLor, X: cond, Y: cmp}
1507  					orOp.typ = Typ[Bool]
1508  					orOp.name = fb.nextName()
1509  					fb.emit(orOp)
1510  					cond = orOp
1511  				}
1512  			}
1513  			fb.emit(&SSAIf{Cond: cond})
1514  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1515  			caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1516  			nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1517  		} else if clause.Cases != nil && tag == nil {
1518  			cond := fb.buildExpr(clause.Cases)
1519  			fb.emit(&SSAIf{Cond: cond})
1520  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1521  			caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1522  			nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1523  		} else {
1524  			fb.emit(&SSAJump{Comment: "switch.case"})
1525  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock)
1526  			caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1527  		}
1528  
1529  		fb.currentBlock = caseBlock
1530  		for _, stmt := range clause.Body {
1531  			fb.buildStmt(stmt)
1532  			if fb.currentBlock == nil {
1533  				break
1534  			}
1535  		}
1536  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1537  			fb.emit(&SSAJump{Comment: "switch.done"})
1538  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1539  			doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1540  		}
1541  		fb.currentBlock = nextBlock
1542  	}
1543  
1544  	if fb.currentBlock != nil {
1545  		fb.emit(&SSAJump{Comment: "switch.done"})
1546  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1547  		doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1548  	}
1549  
1550  	fb.loops = savedLoops
1551  	fb.currentBlock = doneBlock
1552  	if savedVars != nil {
1553  		fb.vars = savedVars
1554  	}
1555  }
1556  
1557  func (fb *ssaFuncBuilder) buildTypeSwitch(s *SwitchStmt, tsg *TypeSwitchGuard, doneBlock *SSABasicBlock) {
1558  	x := fb.buildExpr(tsg.X)
1559  	for _, clause := range s.Body {
1560  		caseBlock := fb.newBlock("typeswitch.case")
1561  		nextBlock := fb.newBlock("typeswitch.next")
1562  
1563  		if clause.Cases != nil {
1564  			caseExprs := []Expr{clause.Cases}
1565  			if list, ok := clause.Cases.(*ListExpr); ok {
1566  				caseExprs = list.ElemList
1567  			}
1568  
1569  			var cond SSAValue
1570  			var firstTA *SSATypeAssert
1571  			var firstType Type
1572  			for _, ce := range caseExprs {
1573  				if n, isName := ce.(*Name); isName && n.Value == "nil" {
1574  					nilType := x.SSAType()
1575  					if nilType == nil {
1576  						nilType = NewTCInterface(nil, nil)
1577  					}
1578  					nilCheck := &SSABinOp{Op: OpEql, X: x, Y: &SSAConst{typ: nilType, val: nil}}
1579  					nilCheck.typ = Typ[Bool]
1580  					nilCheck.name = fb.nextName()
1581  					fb.emit(nilCheck)
1582  					if cond == nil {
1583  						cond = nilCheck
1584  					} else {
1585  						orOp := &SSABinOp{Op: OpLor, X: cond, Y: nilCheck}
1586  						orOp.typ = Typ[Bool]
1587  						orOp.name = fb.nextName()
1588  						fb.emit(orOp)
1589  						cond = orOp
1590  					}
1591  					continue
1592  				}
1593  				var assertedType Type
1594  				if fb.info != nil {
1595  					tv := fb.info.Types[ce]
1596  					assertedType = tv.Type
1597  				}
1598  				if assertedType == nil {
1599  					assertedType = fb.resolveType(ce)
1600  				}
1601  				if assertedType == nil {
1602  					assertedType = Typ[Invalid]
1603  				}
1604  				ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: true}
1605  				ta.typ = NewTuple(
1606  					NewTCVar(nil, "val", assertedType),
1607  					NewTCVar(nil, "ok", Typ[Bool]),
1608  				)
1609  				ta.name = fb.nextName()
1610  				fb.emit(ta)
1611  				okExt := &SSAExtract{Tuple: ta, Index: 1}
1612  				okExt.typ = Typ[Bool]
1613  				okExt.name = fb.nextName()
1614  				fb.emit(okExt)
1615  				if firstTA == nil {
1616  					firstTA = ta
1617  					firstType = assertedType
1618  				}
1619  				if cond == nil {
1620  					cond = okExt
1621  				} else {
1622  					orOp := &SSABinOp{Op: OpLor, X: cond, Y: okExt}
1623  					orOp.typ = Typ[Bool]
1624  					orOp.name = fb.nextName()
1625  					fb.emit(orOp)
1626  					cond = orOp
1627  				}
1628  			}
1629  			fb.emit(&SSAIf{Cond: cond})
1630  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock, nextBlock)
1631  			caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1632  			nextBlock.Preds = append(nextBlock.Preds, fb.currentBlock)
1633  
1634  			fb.currentBlock = caseBlock
1635  			if tsg.Lhs != nil {
1636  				var guardVal SSAValue
1637  				var guardType Type
1638  				if firstTA != nil {
1639  					ext := &SSAExtract{Tuple: firstTA, Index: 0}
1640  					ext.typ = firstType
1641  					ext.name = fb.nextName()
1642  					fb.emit(ext)
1643  					guardVal = ext
1644  					guardType = firstType
1645  				} else {
1646  					guardType = x.SSAType()
1647  					if guardType == nil {
1648  						guardType = NewTCInterface(nil, nil)
1649  					}
1650  					guardVal = &SSAConst{typ: guardType, val: nil}
1651  				}
1652  				for old := range fb.vars {
1653  					if old.Name() == tsg.Lhs.Value {
1654  						delete(fb.vars, old)
1655  						break
1656  					}
1657  				}
1658  				obj := NewTCVar(fb.fn.Pkg.Pkg, tsg.Lhs.Value, guardType)
1659  				alloc := fb.emitAlloc(guardType, 0)
1660  				fb.vars[obj] = alloc
1661  				fb.emitStore(alloc, guardVal)
1662  			}
1663  		} else {
1664  			fb.emit(&SSAJump{Comment: "typeswitch.case"})
1665  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, caseBlock)
1666  			caseBlock.Preds = append(caseBlock.Preds, fb.currentBlock)
1667  			fb.currentBlock = caseBlock
1668  		}
1669  
1670  		for _, stmt := range clause.Body {
1671  			fb.buildStmt(stmt)
1672  			if fb.currentBlock == nil {
1673  				break
1674  			}
1675  		}
1676  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1677  			fb.emit(&SSAJump{Comment: "switch.done"})
1678  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1679  			doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1680  		}
1681  		fb.currentBlock = nextBlock
1682  	}
1683  	if fb.currentBlock != nil {
1684  		fb.emit(&SSAJump{Comment: "switch.done"})
1685  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1686  		doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1687  	}
1688  }
1689  
1690  func (fb *ssaFuncBuilder) buildSelect(s *SelectStmt) {
1691  	doneBlock := fb.newBlock("select.done")
1692  
1693  	var states []*SSASelectState
1694  	caseBlocks := [](*SSABasicBlock){:0:len(s.Body)}
1695  	for i, clause := range s.Body {
1696  		cb := fb.newBlock("select.case")
1697  		caseBlocks = append(caseBlocks, cb)
1698  		state := &SSASelectState{}
1699  		if clause.Comm != nil {
1700  			switch comm := clause.Comm.(type) {
1701  			case *SendStmt:
1702  				state.Dir = SelectDirSend
1703  				state.Chan = fb.buildExpr(comm.Chan)
1704  				state.Send = fb.buildExpr(comm.Value)
1705  			case *AssignStmt:
1706  				var chanExpr Expr
1707  				if op, ok2 := comm.Rhs.(*Operation); ok2 && op.Y == nil && op.Op == Recv {
1708  					chanExpr = op.X
1709  				}
1710  				if chanExpr != nil {
1711  					state.Dir = SelectDirRecv
1712  					state.Chan = fb.buildExpr(chanExpr)
1713  				}
1714  			case *ExprStmt:
1715  				if op, ok2 := comm.X.(*Operation); ok2 && op.Y == nil && op.Op == Recv {
1716  					state.Dir = SelectDirRecv
1717  					state.Chan = fb.buildExpr(op.X)
1718  				}
1719  			}
1720  		}
1721  		states = append(states, state)
1722  		_ = i
1723  	}
1724  
1725  	sel := &SSASelect{States: states, Blocking: true}
1726  	sel.typ = NewTuple(
1727  		NewTCVar(nil, "index", Typ[Int32]),
1728  		NewTCVar(nil, "recvOk", Typ[Bool]),
1729  	)
1730  	sel.name = fb.nextName()
1731  	fb.emit(sel)
1732  
1733  	for i, clause := range s.Body {
1734  		fb.currentBlock = caseBlocks[i]
1735  		for _, stmt := range clause.Body {
1736  			fb.buildStmt(stmt)
1737  			if fb.currentBlock == nil {
1738  				break
1739  			}
1740  		}
1741  		if fb.currentBlock != nil && !fb.blockTerminated(fb.currentBlock) {
1742  			fb.emit(&SSAJump{Comment: "select.done"})
1743  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1744  			doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1745  		}
1746  	}
1747  
1748  	fb.currentBlock = doneBlock
1749  }
1750  
1751  func (fb *ssaFuncBuilder) isSelfTailCall(e Expr) (*CallExpr, bool) {
1752  	call, ok := e.(*CallExpr)
1753  	if !ok || fb.tailBlock == nil || fb.deferred > 0 {
1754  		return nil, false
1755  	}
1756  	name, ok := call.Fun.(*Name)
1757  	if !ok {
1758  		return nil, false
1759  	}
1760  	obj := fb.lookupObject(name.Value)
1761  	if obj == nil {
1762  		return nil, false
1763  	}
1764  	tc, ok := obj.(*TCFunc)
1765  	if !ok || tc == nil {
1766  		return nil, false
1767  	}
1768  	var fn *SSAFunction
1769  	if okv, okok := fb.fn.Pkg.Members[name.Value].(*SSAFunction); okok {
1770  		fn = okv
1771  	}
1772  	if fn != fb.fn {
1773  		return nil, false
1774  	}
1775  	return call, true
1776  }
1777  
1778  func (fb *ssaFuncBuilder) buildReturn(s *ReturnStmt) {
1779  	if s.Results != nil {
1780  		if call, ok := fb.isSelfTailCall(s.Results); ok {
1781  			args := fb.buildArgs(call.ArgList)
1782  			if len(args) == len(fb.paramAllocas) {
1783  				for i, arg := range args {
1784  					fb.emitStore(fb.paramAllocas[i], arg)
1785  				}
1786  				fb.emit(&SSAJump{Comment: "tailcall"})
1787  				fb.currentBlock.Succs = append(fb.currentBlock.Succs, fb.tailBlock)
1788  				fb.tailBlock.Preds = append(fb.tailBlock.Preds, fb.currentBlock)
1789  				fb.currentBlock = nil
1790  				return
1791  			}
1792  		}
1793  	}
1794  	var vals []SSAValue
1795  	if s.Results != nil {
1796  		if list, ok := s.Results.(*ListExpr); ok {
1797  			for _, el := range list.ElemList {
1798  				v := fb.buildExpr(el)
1799  				if v != nil {
1800  					vals = append(vals, v)
1801  				}
1802  			}
1803  		} else {
1804  			v := fb.buildExpr(s.Results)
1805  			if v != nil {
1806  				if v.SSAType() == nil {
1807  					vals = append(vals, v)
1808  				} else if tup, ok := v.SSAType().(*Tuple); ok && tup.Len() > 1 {
1809  					for i := 0; i < tup.Len(); i++ {
1810  						ext := &SSAExtract{Tuple: v, Index: i}
1811  						ext.typ = tup.At(i).Type()
1812  						ext.name = fb.nextName()
1813  						fb.emit(ext)
1814  						vals = append(vals, ext)
1815  					}
1816  				} else {
1817  					vals = append(vals, v)
1818  				}
1819  			}
1820  		}
1821  	} else if len(fb.namedResults) > 0 {
1822  		for _, nr := range fb.namedResults {
1823  			elemType := nr.SSAType()
1824  			if p, ok := elemType.(*Pointer); ok {
1825  				elemType = p.Elem()
1826  			}
1827  			vals = append(vals, fb.emitLoad(nr, elemType))
1828  		}
1829  	}
1830  	if fb.fn.Signature != nil && fb.fn.Signature.Results() != nil {
1831  		for i, v := range vals {
1832  			if i < fb.fn.Signature.Results().Len() {
1833  				retType := fb.fn.Signature.Results().At(i).Type()
1834  				vals[i] = fb.coerceToInterface(v, retType)
1835  			}
1836  		}
1837  	}
1838  	fb.emitReturn(vals, 0)
1839  }
1840  
1841  func (fb *ssaFuncBuilder) buildBranch(s *BranchStmt) {
1842  	if fb.currentBlock == nil {
1843  		return
1844  	}
1845  	switch s.Tok {
1846  	case Break:
1847  		if len(fb.loops) > 0 {
1848  			var doneBlock *SSABasicBlock
1849  			if s.Label != nil {
1850  				for i := len(fb.loops) - 1; i >= 0; i-- {
1851  					if fb.loops[i].label == s.Label.Value {
1852  						doneBlock = fb.loops[i].done
1853  						break
1854  					}
1855  				}
1856  			}
1857  			if doneBlock == nil {
1858  				doneBlock = fb.loops[len(fb.loops)-1].done
1859  			}
1860  			fb.emit(&SSAJump{Comment: "break"})
1861  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, doneBlock)
1862  			doneBlock.Preds = append(doneBlock.Preds, fb.currentBlock)
1863  			fb.currentBlock = nil
1864  		}
1865  	case Continue:
1866  		for i := len(fb.loops) - 1; i >= 0; i-- {
1867  			postBlock := fb.loops[i].post
1868  			if postBlock == nil {
1869  				postBlock = fb.loops[i].body
1870  			}
1871  			if postBlock == nil {
1872  				continue
1873  			}
1874  			fb.emit(&SSAJump{Comment: "continue"})
1875  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, postBlock)
1876  			postBlock.Preds = append(postBlock.Preds, fb.currentBlock)
1877  			fb.currentBlock = nil
1878  			break
1879  		}
1880  	case Goto:
1881  		if s.Label != nil {
1882  			target := fb.labelBlock(s.Label.Value)
1883  			fb.emit(&SSAJump{Comment: "goto." + s.Label.Value})
1884  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, target)
1885  			target.Preds = append(target.Preds, fb.currentBlock)
1886  			fb.currentBlock = nil
1887  		}
1888  	case Return:
1889  		fb.emitReturn(nil, 0)
1890  	}
1891  }
1892  
1893  func (fb *ssaFuncBuilder) buildGoStmt(call *CallExpr) {
1894  	fn := fb.buildExpr(call.Fun)
1895  	if fn == nil {
1896  		return
1897  	}
1898  	args := fb.buildArgs(call.ArgList)
1899  	g := &SSAGo{Call: SSACallCommon{Value: fn, Args: args}}
1900  	fb.emit(g)
1901  }
1902  
1903  func (fb *ssaFuncBuilder) buildDeferStmt(call *CallExpr) {
1904  	fn := fb.buildExpr(call.Fun)
1905  	if fn == nil {
1906  		return
1907  	}
1908  	args := fb.buildArgs(call.ArgList)
1909  	d := &SSADefer{Call: SSACallCommon{Value: fn, Args: args}}
1910  	fb.emit(d)
1911  	fb.deferred++
1912  }
1913  
1914  // Expression builders.
1915  
1916  func (fb *ssaFuncBuilder) buildExpr(e Expr) SSAValue {
1917  	if e == nil || fb.currentBlock == nil {
1918  		return nil
1919  	}
1920  	switch e := e.(type) {
1921  	case *Name:
1922  		return fb.buildIdent(e)
1923  	case *BasicLit:
1924  		return fb.buildLit(e)
1925  	case *Operation:
1926  		return fb.buildOperation(e)
1927  	case *CallExpr:
1928  		return fb.buildCall(e)
1929  	case *SelectorExpr:
1930  		return fb.buildSelector(e)
1931  	case *IndexExpr:
1932  		return fb.buildIndex(e)
1933  	case *SliceExpr:
1934  		return fb.buildSlice(e)
1935  	case *AssertExpr:
1936  		return fb.buildAssert(e)
1937  	case *CompositeLit:
1938  		return fb.buildCompositeLit(e)
1939  	case *FuncLit:
1940  		return fb.buildFuncLit(e)
1941  	case *ParenExpr:
1942  		return fb.buildExpr(e.X)
1943  	case *ListExpr:
1944  		var last SSAValue
1945  		for _, el := range e.ElemList {
1946  			last = fb.buildExpr(el)
1947  		}
1948  		return last
1949  	case *KeyValueExpr:
1950  		return fb.buildExpr(e.Value)
1951  	}
1952  	return nil
1953  }
1954  
1955  func (fb *ssaFuncBuilder) buildIdent(e *Name) SSAValue {
1956  	if e.Value == "_" || e.Value == "nil" {
1957  		return &SSAConst{typ: nil, val: nil}
1958  	}
1959  	if fb.localConsts != nil {
1960  		if c, ok := fb.localConsts[e.Value]; ok {
1961  			return c
1962  		}
1963  	}
1964  	obj := fb.lookupObject(e.Value)
1965  	if obj == nil && fb.info != nil {
1966  		obj = fb.info.Uses[e]
1967  	}
1968  	if obj == nil {
1969  		if fb.fn.Pkg != nil {
1970  			if fn, ok := fb.fn.Pkg.Members[e.Value].(*SSAFunction); ok {
1971  				return fn
1972  			}
1973  			if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
1974  				return fb.emitLoad(g, g.typ)
1975  			}
1976  		}
1977  		return fb.builtinValue(e.Value)
1978  	}
1979  	switch obj := obj.(type) {
1980  	case *TCVar:
1981  		if alloc, ok := fb.vars[obj]; ok {
1982  			return fb.emitLoad(alloc, obj.Type())
1983  		}
1984  		if fv, ok := fb.freeVarPtrs[e.Value]; ok {
1985  			return fb.emitLoad(fv, obj.Type())
1986  		}
1987  		if fb.parent != nil {
1988  			if _, ok := fb.parent.vars[obj]; ok {
1989  				fv := fb.getOrCreateFreeVar(e.Value, obj.Type())
1990  				return fb.emitLoad(fv, obj.Type())
1991  			}
1992  		}
1993  		if g, ok := fb.fn.Pkg.Members[e.Value].(*SSAGlobal); ok {
1994  			return fb.emitLoad(g, obj.Type())
1995  		}
1996  		return &SSAConst{typ: obj.Type(), val: nil}
1997  	case *TCConst:
1998  		return &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())}
1999  	case *TCFunc:
2000  		var fn *SSAFunction
2001  		if okv, okok := fb.fn.Pkg.Members[e.Value].(*SSAFunction); okok {
2002  			fn = okv
2003  		}
2004  		if fn != nil {
2005  			return fn
2006  		}
2007  		return &SSAConst{typ: obj.Type(), val: nil}
2008  	case *TypeName:
2009  		return nil
2010  	case *Builtin:
2011  		return &SSABuiltin{id: obj.ID(), name: obj.Name()}
2012  	}
2013  	return nil
2014  }
2015  
2016  func (fb *ssaFuncBuilder) builtinValue(name string) SSAValue {
2017  	id, ok := ssaBuiltinID(name)
2018  	if !ok {
2019  		return nil
2020  	}
2021  	return &SSABuiltin{id: id, name: name}
2022  }
2023  
2024  func (fb *ssaFuncBuilder) buildLit(e *BasicLit) SSAValue {
2025  	cv := evalBasicLitLocal(e)
2026  	if cv == nil {
2027  		return nil
2028  	}
2029  	switch e.Kind {
2030  	case IntLit:
2031  		return &SSAConst{typ: Typ[UntypedInt], val: cv}
2032  	case FloatLit:
2033  		return &SSAConst{typ: Typ[UntypedFloat], val: cv}
2034  	case StringLit:
2035  		return &SSAConst{typ: Typ[UntypedString], val: cv}
2036  	case RuneLit:
2037  		return &SSAConst{typ: Typ[UntypedRune], val: cv}
2038  	}
2039  	return nil
2040  }
2041  
2042  func (fb *ssaFuncBuilder) buildOperation(e *Operation) SSAValue {
2043  	if e.Y == nil {
2044  		if e.Op == Add {
2045  			return fb.buildExpr(e.X)
2046  		}
2047  		op := syntaxOpToSSAOp(e.Op, true)
2048  		if op == OpAnd {
2049  			if name, ok := e.X.(*Name); ok {
2050  				obj := fb.lookupObject(name.Value)
2051  				if obj != nil {
2052  					if alloc, ok2 := fb.vars[obj]; ok2 {
2053  						return alloc
2054  					}
2055  					if g, ok2 := fb.fn.Pkg.Members[name.Value].(*SSAGlobal); ok2 {
2056  						return g
2057  					}
2058  				}
2059  			}
2060  			if ie, ok := e.X.(*IndexExpr); ok {
2061  				base := fb.buildExpr(ie.X)
2062  				idx := fb.buildExpr(ie.Index)
2063  				if base == nil || idx == nil {
2064  					return nil
2065  				}
2066  				ia := &SSAIndexAddr{X: base, Index: idx}
2067  				ia.typ = NewPointer(ssaElemType(base.SSAType()))
2068  				ia.name = fb.nextName()
2069  				fb.emit(ia)
2070  				return ia
2071  			}
2072  			if sel, ok := e.X.(*SelectorExpr); ok {
2073  				addr := fb.buildSelectorAddr(sel)
2074  				if addr != nil {
2075  					return addr
2076  				}
2077  			}
2078  			x := fb.buildExpr(e.X)
2079  			if x == nil {
2080  				return nil
2081  			}
2082  			a := &SSAAlloc{Heap: true}
2083  			a.typ = NewPointer(x.SSAType())
2084  			a.name = fb.nextName()
2085  			fb.emit(a)
2086  			fb.emitStore(a, x)
2087  			return a
2088  		}
2089  		x := fb.buildExpr(e.X)
2090  		if x == nil {
2091  			return nil
2092  		}
2093  		if op == OpArrow {
2094  			u := &SSAUnOp{Op: OpArrow, X: x}
2095  			u.typ = ssaChanElemType(x.SSAType())
2096  			u.name = fb.nextName()
2097  			fb.emit(u)
2098  			return u
2099  		}
2100  		u := &SSAUnOp{Op: op, X: x}
2101  		if op == OpMul {
2102  			if p, ok := x.SSAType().(*Pointer); ok {
2103  				u.typ = p.Elem()
2104  			} else {
2105  				u.typ = x.SSAType()
2106  			}
2107  		} else {
2108  			u.typ = x.SSAType()
2109  		}
2110  		u.name = fb.nextName()
2111  		fb.emit(u)
2112  		return u
2113  	}
2114  	op := syntaxOpToSSAOp(e.Op, false)
2115  	if op == OpLand || op == OpLor {
2116  		x := fb.buildExpr(e.X)
2117  		if x == nil {
2118  			return nil
2119  		}
2120  		rhsBlock := fb.newBlock("sc.rhs")
2121  		mergeBlock := fb.newBlock("sc.merge")
2122  		entryBlock := fb.currentBlock
2123  		fb.emit(&SSAIf{Cond: x})
2124  		if op == OpLand {
2125  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, rhsBlock, mergeBlock)
2126  		} else {
2127  			fb.currentBlock.Succs = append(fb.currentBlock.Succs, mergeBlock, rhsBlock)
2128  		}
2129  		rhsBlock.Preds = append(rhsBlock.Preds, entryBlock)
2130  		mergeBlock.Preds = append(mergeBlock.Preds, entryBlock)
2131  		fb.currentBlock = rhsBlock
2132  		y := fb.buildExpr(e.Y)
2133  		if y == nil {
2134  			y = &SSAConst{typ: Typ[Bool], val: constBool{false}}
2135  		}
2136  		fb.emit(&SSAJump{Comment: "sc.merge"})
2137  		fb.currentBlock.Succs = append(fb.currentBlock.Succs, mergeBlock)
2138  		mergeBlock.Preds = append(mergeBlock.Preds, fb.currentBlock)
2139  		fb.currentBlock = mergeBlock
2140  		var shortVal SSAValue
2141  		if op == OpLand {
2142  			shortVal = &SSAConst{typ: Typ[Bool], val: constBool{false}}
2143  		} else {
2144  			shortVal = &SSAConst{typ: Typ[Bool], val: constBool{true}}
2145  		}
2146  		phi := &SSAPhi{Edges: []SSAValue{shortVal, y}, Comment: "sc"}
2147  		phi.typ = Typ[Bool]
2148  		phi.name = fb.nextName()
2149  		fb.emit(phi)
2150  		return phi
2151  	}
2152  	x := fb.buildExpr(e.X)
2153  	y := fb.buildExpr(e.Y)
2154  	if x == nil || y == nil {
2155  		return nil
2156  	}
2157  	if xc, ok := x.(*SSAConst); ok {
2158  		if yc, ok2 := y.(*SSAConst); ok2 {
2159  			if xc.val != nil && yc.val != nil {
2160  				folded := evalBinaryLocal(e.Op, xc.val, yc.val)
2161  				if folded != nil {
2162  					ct := xc.typ
2163  					if ct == nil {
2164  						ct = yc.typ
2165  					}
2166  					if _, isBool := folded.(constBool); isBool {
2167  						ct = Typ[Bool]
2168  					}
2169  					return &SSAConst{typ: ct, val: folded}
2170  				}
2171  			}
2172  		}
2173  	}
2174  	b := &SSABinOp{Op: op, X: x, Y: y}
2175  	b.name = fb.nextName()
2176  	switch op {
2177  	case OpEql, OpNeq, OpLss, OpLeq, OpGtr, OpGeq:
2178  		b.typ = Typ[Bool]
2179  	default:
2180  		xT := x.SSAType()
2181  		yT := y.SSAType()
2182  		xUntyped := false
2183  		if xB, ok := safeUnderlying(xT).(*Basic); ok && xB.Info()&IsUntyped != 0 {
2184  			xUntyped = true
2185  		}
2186  		if xT != nil && !xUntyped {
2187  			b.typ = xT
2188  		} else if yT != nil {
2189  			b.typ = yT
2190  		} else {
2191  			b.typ = xT
2192  		}
2193  	}
2194  	fb.emit(b)
2195  	return b
2196  }
2197  
2198  func (fb *ssaFuncBuilder) buildCall(e *CallExpr) SSAValue {
2199  	if ie, ok := e.Fun.(*IndexExpr); ok {
2200  		if result := fb.tryGenericCallFromIndex(ie, e.ArgList, e.HasDots); result != nil {
2201  			return result
2202  		}
2203  	}
2204  	if name, ok := e.Fun.(*Name); ok {
2205  		obj := fb.lookupObject(name.Value)
2206  		if tn, ok2 := obj.(*TypeName); ok2 {
2207  			if _, isTP := tn.Type().(*TypeParam); !isTP {
2208  				args := fb.buildArgs(e.ArgList)
2209  				if len(args) == 1 && args[0] != nil {
2210  					conv := &SSAConvert{X: args[0]}
2211  					conv.typ = tn.Type()
2212  					conv.name = fb.nextName()
2213  					fb.emit(conv)
2214  					return conv
2215  				}
2216  				return nil
2217  			}
2218  		}
2219  		if result := fb.tryGenericLocalCall(name.Value, e.ArgList, e.HasDots); result != nil {
2220  			return result
2221  		}
2222  	}
2223  	if convType := fb.resolveTypeAST(e.Fun); convType != nil {
2224  		args := fb.buildArgs(e.ArgList)
2225  		if len(args) == 1 && args[0] != nil {
2226  			conv := &SSAConvert{X: args[0]}
2227  			conv.typ = convType
2228  			conv.name = fb.nextName()
2229  			fb.emit(conv)
2230  			return conv
2231  		}
2232  		return nil
2233  	}
2234  	if sel, ok := e.Fun.(*SelectorExpr); ok {
2235  		if name, ok2 := sel.X.(*Name); ok2 {
2236  			obj := fb.lookupObject(name.Value)
2237  			if pn, ok3 := obj.(*PkgName); ok3 {
2238  				return fb.buildPkgCall(pn, sel.Sel.Value, e.ArgList, e.HasDots)
2239  			}
2240  		}
2241  		recv := fb.buildExpr(sel.X)
2242  		if recv != nil && recv.SSAType() != nil {
2243  			if fn, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv); fn != nil {
2244  				args := fb.buildArgs(e.ArgList)
2245  				if fn.Signature != nil {
2246  					if fn.Signature.Variadic() && !e.HasDots {
2247  						args = fb.wrapVariadicArgs(args, fn.Signature)
2248  					}
2249  					args = fb.coerceArgsToInterface(args, fn.Signature)
2250  				}
2251  				allArgs := []SSAValue{:0:len(args) + 1}
2252  				allArgs = append(allArgs, fixedRecv)
2253  				for _, ma := range args {
2254  					allArgs = append(allArgs, ma)
2255  				}
2256  				var retType Type
2257  				if fn.Signature != nil {
2258  					if fn.Signature.Results() != nil && fn.Signature.Results().Len() == 1 {
2259  						retType = fn.Signature.Results().At(0).Type()
2260  					} else if fn.Signature.Results() != nil && fn.Signature.Results().Len() > 1 {
2261  						retType = fn.Signature.Results()
2262  					}
2263  				}
2264  				call := &SSACall{Call: SSACallCommon{Value: fn, Args: allArgs}}
2265  				call.typ = retType
2266  				call.name = fb.nextName()
2267  				fb.emit(call)
2268  				if retType == nil {
2269  					return nil
2270  				}
2271  				return call
2272  			}
2273  			if inv := fb.buildIfaceMethodCall(sel, recv, e.ArgList); inv != nil {
2274  				return inv
2275  			}
2276  		}
2277  	}
2278  	fn := fb.buildExpr(e.Fun)
2279  	args := fb.buildArgs(e.ArgList)
2280  
2281  	if fn == nil {
2282  		return nil
2283  	}
2284  	if bi, ok := fn.(*SSABuiltin); ok {
2285  		return fb.buildBuiltinCall(e, bi, args)
2286  	}
2287  
2288  	var retType Type
2289  	if fn.SSAType() != nil {
2290  		if sig, ok := safeUnderlying(fn.SSAType()).(*Signature); ok {
2291  			if sig.Results() != nil && sig.Results().Len() == 1 {
2292  				retType = sig.Results().At(0).Type()
2293  			} else if sig.Results() != nil && sig.Results().Len() > 1 {
2294  				retType = sig.Results()
2295  			}
2296  		}
2297  	} else if ssaFn, ok := fn.(*SSAFunction); ok && ssaFn.Signature != nil {
2298  		sig := ssaFn.Signature
2299  		if sig.Results() != nil && sig.Results().Len() == 1 {
2300  			retType = sig.Results().At(0).Type()
2301  		} else if sig.Results() != nil && sig.Results().Len() > 1 {
2302  			retType = sig.Results()
2303  		}
2304  	}
2305  
2306  	if fn.SSAType() != nil {
2307  		if sig, ok := safeUnderlying(fn.SSAType()).(*Signature); ok {
2308  			if sig.Variadic() && !e.HasDots {
2309  				args = fb.wrapVariadicArgs(args, sig)
2310  			}
2311  			args = fb.coerceArgsToInterface(args, sig)
2312  		}
2313  	}
2314  
2315  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
2316  	call.typ = retType
2317  	call.name = fb.nextName()
2318  	fb.emit(call)
2319  
2320  	if retType == nil {
2321  		return nil
2322  	}
2323  	return call
2324  }
2325  
2326  func (fb *ssaFuncBuilder) coerceArgsToInterface(args []SSAValue, sig *Signature) []SSAValue {
2327  	if sig.Params() == nil {
2328  		return args
2329  	}
2330  	for i := 0; i < len(args) && i < sig.Params().Len(); i++ {
2331  		paramType := sig.Params().At(i).Type()
2332  		if paramType == nil || args[i] == nil || args[i].SSAType() == nil {
2333  			continue
2334  		}
2335  		_, isIface := safeUnderlying(paramType).(*TCInterface)
2336  		if !isIface {
2337  			continue
2338  		}
2339  		_, argIsIface := safeUnderlying(args[i].SSAType()).(*TCInterface)
2340  		if argIsIface {
2341  			continue
2342  		}
2343  		mi := &SSAMakeInterface{X: args[i], IType: paramType}
2344  		mi.typ = paramType
2345  		mi.name = fb.nextName()
2346  		fb.emit(mi)
2347  		args[i] = mi
2348  	}
2349  	return args
2350  }
2351  
2352  func (fb *ssaFuncBuilder) wrapVariadicArgs(args []SSAValue, sig *Signature) []SSAValue {
2353  	if sig.Params() == nil {
2354  		return args
2355  	}
2356  	nFixed := sig.Params().Len() - 1
2357  	if nFixed < 0 {
2358  		nFixed = 0
2359  	}
2360  	if nFixed > len(args) {
2361  		nFixed = len(args)
2362  	}
2363  	nVariadic := len(args) - nFixed
2364  	if nVariadic <= 0 {
2365  		nilSlice := NewSSAConst(constNil{}, sig.Params().At(sig.Params().Len()-1).Type())
2366  		result := []SSAValue{:nFixed:nFixed}
2367  		copy(result, args[:nFixed])
2368  		return append(result, nilSlice)
2369  	}
2370  	sliceType := sig.Params().At(sig.Params().Len() - 1).Type()
2371  	var elemType Type
2372  	if sl, ok := safeUnderlying(sliceType).(*Slice); ok {
2373  		elemType = sl.Elem()
2374  	}
2375  	// HasDots lost in stage-2 compiled parser. Detect spread: if exactly 1
2376  	// variadic arg whose type matches the variadic param's slice type, and
2377  	// the element type is concrete, it must be a spread call (f(slice...)).
2378  	// Passing []T to ...T without dots is a type error for concrete T.
2379  	if nVariadic == 1 && elemType != nil {
2380  		if _, isIface := safeUnderlying(elemType).(*TCInterface); !isIface {
2381  			argT := args[nFixed].SSAType()
2382  			if argT != nil && Identical(argT, sliceType) {
2383  				return args
2384  			}
2385  		}
2386  	}
2387  	lenVal := NewSSAConst(constInt{int32(nVariadic)}, Typ[Int32])
2388  	ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal}
2389  	ms.typ = sliceType
2390  	ms.name = fb.nextName()
2391  	fb.emit(ms)
2392  	for i := 0; i < nVariadic; i++ {
2393  		idx := NewSSAConst(constInt{int32(i)}, Typ[Int32])
2394  		ia := &SSAIndexAddr{X: ms, Index: idx}
2395  		ia.typ = NewPointer(elemType)
2396  		ia.name = fb.nextName()
2397  		fb.emit(ia)
2398  		v := args[nFixed+i]
2399  		if elemType != nil {
2400  			v = fb.coerceToInterface(v, elemType)
2401  		}
2402  		fb.emitStore(ia, v)
2403  	}
2404  	result := []SSAValue{:nFixed:nFixed}
2405  	copy(result, args[:nFixed])
2406  	return append(result, ms)
2407  }
2408  
2409  func (fb *ssaFuncBuilder) buildArgs(argList []Expr) []SSAValue {
2410  	args := []SSAValue{:0:len(argList)}
2411  	for _, a := range argList {
2412  		v := fb.buildExpr(a)
2413  		if v != nil {
2414  			args = append(args, v)
2415  		}
2416  	}
2417  	return args
2418  }
2419  
2420  func (fb *ssaFuncBuilder) buildBuiltinCall(e *CallExpr, b *SSABuiltin, args []SSAValue) SSAValue {
2421  	switch b.id {
2422  	case BuiltinLen, BuiltinCap:
2423  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2424  		call.typ = Typ[Int32]
2425  		call.name = fb.nextName()
2426  		fb.emit(call)
2427  		return call
2428  	case BuiltinAppend:
2429  		if len(args) > 1 {
2430  			if sl, ok := safeUnderlying(args[0].SSAType()).(*Slice); ok {
2431  				if _, isIface := safeUnderlying(sl.Elem()).(*TCInterface); isIface {
2432  					for i := 1; i < len(args); i++ {
2433  						if e.HasDots && i == 1 {
2434  							continue
2435  						}
2436  						if args[i] == nil || args[i].SSAType() == nil {
2437  							continue
2438  						}
2439  						if _, argIface := safeUnderlying(args[i].SSAType()).(*TCInterface); argIface {
2440  							continue
2441  						}
2442  						mi := &SSAMakeInterface{X: args[i], IType: sl.Elem()}
2443  						mi.typ = sl.Elem()
2444  						mi.name = fb.nextName()
2445  						fb.emit(mi)
2446  						args[i] = mi
2447  					}
2448  				}
2449  			}
2450  		}
2451  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args, HasDots: e.HasDots}}
2452  		if len(args) > 0 {
2453  			call.typ = args[0].SSAType()
2454  		}
2455  		call.name = fb.nextName()
2456  		fb.emit(call)
2457  		return call
2458  	case BuiltinMake:
2459  		if len(e.ArgList) == 0 {
2460  			return nil
2461  		}
2462  		typ := fb.resolveType(e.ArgList[0])
2463  		return fb.emitMake(typ, args)
2464  	case BuiltinNew:
2465  		if len(e.ArgList) == 0 {
2466  			return nil
2467  		}
2468  		typ := fb.resolveType(e.ArgList[0])
2469  		a := &SSAAlloc{Heap: true}
2470  		a.typ = NewPointer(typ)
2471  		a.name = fb.nextName()
2472  		fb.emit(a)
2473  		return a
2474  	case BuiltinPanic:
2475  		if len(args) > 0 {
2476  			fb.emit(&SSAPanic{X: args[0]})
2477  			fb.currentBlock = nil
2478  		}
2479  		return nil
2480  	case BuiltinClose, BuiltinDelete, BuiltinClear, BuiltinPrint, BuiltinPrintln:
2481  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2482  		call.name = fb.nextName()
2483  		fb.emit(call)
2484  		return nil
2485  	case BuiltinCopy:
2486  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2487  		call.typ = Typ[Int32]
2488  		call.name = fb.nextName()
2489  		fb.emit(call)
2490  		return call
2491  	case BuiltinRecover:
2492  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2493  		call.typ = NewTCInterface(nil, nil)
2494  		call.name = fb.nextName()
2495  		fb.emit(call)
2496  		return call
2497  	case BuiltinMin, BuiltinMax:
2498  		call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2499  		if len(args) > 0 && args[0] != nil {
2500  			call.typ = args[0].SSAType()
2501  		} else {
2502  			call.typ = Typ[Int32]
2503  		}
2504  		call.name = fb.nextName()
2505  		fb.emit(call)
2506  		return call
2507  	}
2508  	call := &SSACall{Call: SSACallCommon{Value: b, Args: args}}
2509  	call.name = fb.nextName()
2510  	fb.emit(call)
2511  	return call
2512  }
2513  
2514  func (fb *ssaFuncBuilder) emitMake(typ Type, sizeArgs []SSAValue) SSAValue {
2515  	if typ == nil {
2516  		return nil
2517  	}
2518  	switch u := safeUnderlying(typ).(type) {
2519  	case *Basic:
2520  		if u.kind == TCString {
2521  			ms := &SSAMakeSlice{}
2522  			ms.typ = typ
2523  			ms.name = fb.nextName()
2524  			if len(sizeArgs) > 0 {
2525  				ms.Len = sizeArgs[0]
2526  			}
2527  			if len(sizeArgs) > 1 {
2528  				ms.Cap = sizeArgs[1]
2529  			}
2530  			fb.emit(ms)
2531  			return ms
2532  		}
2533  	case *Slice:
2534  		ms := &SSAMakeSlice{}
2535  		ms.typ = typ
2536  		ms.name = fb.nextName()
2537  		if len(sizeArgs) > 0 {
2538  			ms.Len = sizeArgs[0]
2539  		}
2540  		if len(sizeArgs) > 1 {
2541  			ms.Cap = sizeArgs[1]
2542  		}
2543  		fb.emit(ms)
2544  		return ms
2545  	case *TCMap:
2546  		mm := &SSAMakeMap{}
2547  		mm.typ = typ
2548  		mm.name = fb.nextName()
2549  		if len(sizeArgs) > 0 {
2550  			mm.Reserve = sizeArgs[0]
2551  		}
2552  		fb.emit(mm)
2553  		return mm
2554  	case *TCChan:
2555  		mc := &SSAMakeChan{}
2556  		mc.typ = typ
2557  		mc.name = fb.nextName()
2558  		if len(sizeArgs) > 0 {
2559  			mc.Size = sizeArgs[0]
2560  		}
2561  		fb.emit(mc)
2562  		return mc
2563  	}
2564  	return nil
2565  }
2566  
2567  func (fb *ssaFuncBuilder) buildSelector(e *SelectorExpr) SSAValue {
2568  	if name, ok := e.X.(*Name); ok {
2569  		obj := fb.lookupObject(name.Value)
2570  		if pn, ok2 := obj.(*PkgName); ok2 {
2571  			return fb.buildPkgMember(pn, e.Sel.Value)
2572  		}
2573  	}
2574  	fa := fb.buildSelectorAddr(e)
2575  	if fa != nil {
2576  		elemType := fa.SSAType()
2577  		if p, ok := safeUnderlying(elemType).(*Pointer); ok {
2578  			elemType = p.Elem()
2579  		}
2580  		return fb.emitLoad(fa, elemType)
2581  	}
2582  	recv := fb.buildExpr(e.X)
2583  	if recv == nil {
2584  		return nil
2585  	}
2586  	return fb.buildMethodValue(e, recv)
2587  }
2588  
2589  func (fb *ssaFuncBuilder) buildMethodValue(sel *SelectorExpr, recv SSAValue) SSAValue {
2590  	fn, fixedRecv := fb.resolveMethodCallWithRecv(sel, recv)
2591  	if fn == nil || fn.Signature == nil {
2592  		return nil
2593  	}
2594  	methodSig := fn.Signature
2595  	var wrapperParams *Tuple
2596  	if methodSig.Params() != nil && methodSig.Params().Len() > 0 {
2597  		vars := []*TCVar{:0:methodSig.Params().Len()}
2598  		for i := 0; i < methodSig.Params().Len(); i++ {
2599  			vars = append(vars, methodSig.Params().At(i))
2600  		}
2601  		wrapperParams = NewTuple(vars...)
2602  	}
2603  	wrapperSig := NewSignature(nil, wrapperParams, methodSig.Results(), methodSig.Variadic())
2604  	name := fb.fn.name | "__mval" | ssaItoa(len(fb.fn.AnonFuncs)+1)
2605  	wrapper := &SSAFunction{
2606  		name:      name,
2607  		Signature: wrapperSig,
2608  		Pkg:       fb.fn.Pkg,
2609  		Prog:      fb.fn.Prog,
2610  		parent:    fb.fn,
2611  	}
2612  	fb.fn.AnonFuncs = append(fb.fn.AnonFuncs, wrapper)
2613  	recvType := fixedRecv.SSAType()
2614  	fv := &SSAFreeVar{name: "recv", typ: recvType, parent: wrapper}
2615  	wrapper.FreeVars = append(wrapper.FreeVars, fv)
2616  	if wrapperParams != nil {
2617  		for i := 0; i < wrapperParams.Len(); i++ {
2618  			v := wrapperParams.At(i)
2619  			p := &SSAParameter{name: v.Name(), typ: v.Type(), parent: wrapper}
2620  			wrapper.Params = append(wrapper.Params, p)
2621  		}
2622  	}
2623  	entry := NewSSABasicBlock(wrapper, "entry")
2624  	args := []SSAValue{:0:1 + len(wrapper.Params)}
2625  	args = append(args, fv)
2626  	for _, p := range wrapper.Params {
2627  		args = append(args, p)
2628  	}
2629  	var retType Type
2630  	if methodSig.Results() != nil && methodSig.Results().Len() == 1 {
2631  		retType = methodSig.Results().At(0).Type()
2632  	} else if methodSig.Results() != nil && methodSig.Results().Len() > 1 {
2633  		retType = methodSig.Results()
2634  	}
2635  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
2636  	call.typ = retType
2637  	call.name = "t1"
2638  	call.setBlock(entry)
2639  	entry.Instrs = append(entry.Instrs, call)
2640  	ret := &SSAReturn{}
2641  	if retType != nil {
2642  		ret.Results = []SSAValue{call}
2643  	}
2644  	ret.setBlock(entry)
2645  	entry.Instrs = append(entry.Instrs, ret)
2646  	mc := &SSAMakeClosure{Fn: wrapper, Bindings: []SSAValue{fixedRecv}}
2647  	mc.typ = wrapperSig
2648  	mc.name = fb.nextName()
2649  	fb.emit(mc)
2650  	return mc
2651  }
2652  
2653  func (fb *ssaFuncBuilder) ensureImportedSSAPackage(imported *TCPackage) *SSAPackage {
2654  	impPkg := fb.fn.Prog.ImportedPackage(imported.Path())
2655  	if impPkg == nil {
2656  		impPkg = &SSAPackage{
2657  			Prog:    fb.fn.Prog,
2658  			Pkg:     imported,
2659  			Members: map[string]SSAMember{},
2660  		}
2661  		fb.fn.Prog.imported[imported.Path()] = impPkg
2662  		fb.fn.Prog.packages[imported] = impPkg
2663  	}
2664  	return impPkg
2665  }
2666  
2667  func (fb *ssaFuncBuilder) buildPkgMember(pn *PkgName, memberName string) SSAValue {
2668  	imported := pn.Imported()
2669  	if imported == nil {
2670  		return nil
2671  	}
2672  	obj := imported.Scope().Lookup(memberName)
2673  	if obj == nil {
2674  		return nil
2675  	}
2676  	switch obj := obj.(type) {
2677  	case *TCConst:
2678  		return &SSAConst{typ: obj.Type(), val: localizeConstVal(obj.Val(), obj.Type())}
2679  	case *TCVar:
2680  		impPkg := fb.ensureImportedSSAPackage(imported)
2681  		g, ok := impPkg.Members[memberName].(*SSAGlobal)
2682  		if !ok {
2683  			g = &SSAGlobal{
2684  				name: memberName,
2685  				typ:  NewPointer(obj.Type()),
2686  				pkg:  impPkg,
2687  			}
2688  			impPkg.Members[memberName] = g
2689  		}
2690  		return fb.emitLoad(g, obj.Type())
2691  	case *TCFunc:
2692  		impPkg := fb.ensureImportedSSAPackage(imported)
2693  		fn := impPkg.Func(memberName)
2694  		if fn != nil {
2695  			return fn
2696  		}
2697  		return nil
2698  	}
2699  	return nil
2700  }
2701  
2702  func (fb *ssaFuncBuilder) buildSelectorAddr(e *SelectorExpr) SSAValue {
2703  	var addr SSAValue
2704  	var structType Type
2705  	if inner, ok := e.X.(*SelectorExpr); ok {
2706  		addr = fb.buildSelectorAddr(inner)
2707  		if addr == nil {
2708  			return nil
2709  		}
2710  		structType = addr.SSAType()
2711  		if p, ok := safeUnderlying(structType).(*Pointer); ok {
2712  			structType = p.Elem()
2713  		}
2714  		if p, ok := safeUnderlying(structType).(*Pointer); ok {
2715  			ld := &SSAUnOp{Op: OpMul, X: addr}
2716  			ld.typ = structType
2717  			ld.name = fb.nextName()
2718  			fb.emit(ld)
2719  			addr = ld
2720  			structType = p.Elem()
2721  		}
2722  	} else if ie, ok := e.X.(*IndexExpr); ok {
2723  		x := fb.buildExpr(ie.X)
2724  		idx := fb.buildExpr(ie.Index)
2725  		if x == nil || idx == nil {
2726  			return nil
2727  		}
2728  		ia := &SSAIndexAddr{X: x, Index: idx}
2729  		elemT := ssaElemType(x.SSAType())
2730  		ia.typ = NewPointer(elemT)
2731  		ia.name = fb.nextName()
2732  		fb.emit(ia)
2733  		addr = ia
2734  		structType = elemT
2735  		if _, isPtr := safeUnderlying(elemT).(*Pointer); isPtr {
2736  			ld := fb.emitLoad(ia, elemT)
2737  			addr = ld
2738  			structType = elemT
2739  		}
2740  	} else {
2741  		x := fb.buildExpr(e.X)
2742  		if x == nil || x.SSAType() == nil {
2743  			if name, ok := e.X.(*Name); ok {
2744  				obj := fb.lookupObject(name.Value)
2745  				if pn, ok := obj.(*PkgName); ok {
2746  					return fb.buildPkgMemberAddr(pn, e.Sel.Value)
2747  				}
2748  			}
2749  			return nil
2750  		}
2751  		baseType := x.SSAType()
2752  		addr = x
2753  		if _, ok := safeUnderlying(baseType).(*Pointer); !ok {
2754  			if name, ok := e.X.(*Name); ok {
2755  				obj := fb.lookupObject(name.Value)
2756  				if obj != nil {
2757  					if alloc, ok2 := fb.vars[obj]; ok2 {
2758  						addr = alloc
2759  						baseType = NewPointer(baseType)
2760  					} else if fb.freeVarPtrs != nil {
2761  						if fv, ok2 := fb.freeVarPtrs[name.Value]; ok2 {
2762  							addr = fv
2763  							baseType = NewPointer(baseType)
2764  						}
2765  					}
2766  				}
2767  			}
2768  		}
2769  		structType = baseType
2770  		if p, ok := safeUnderlying(structType).(*Pointer); ok {
2771  			structType = p.Elem()
2772  		}
2773  	}
2774  	fieldIdx := fb.fieldIndex(structType, e.Sel.Value)
2775  	if fieldIdx >= 0 {
2776  		fa := &SSAFieldAddr{X: addr, Field: fieldIdx}
2777  		fa.typ = NewPointer(fb.fieldType(structType, fieldIdx))
2778  		fa.name = fb.nextName()
2779  		fb.emit(fa)
2780  		return fa
2781  	}
2782  	path := fb.findEmbeddedFieldPath(structType, e.Sel.Value)
2783  	if len(path) >= 2 {
2784  		cur := addr
2785  		curType := structType
2786  		for pi, idx := range path {
2787  			fa := &SSAFieldAddr{X: cur, Field: idx}
2788  			fa.typ = NewPointer(fb.fieldType(curType, idx))
2789  			fa.name = fb.nextName()
2790  			fb.emit(fa)
2791  			curType = fb.fieldType(curType, idx)
2792  			if pi < len(path)-1 {
2793  				if p, ok := safeUnderlying(curType).(*Pointer); ok {
2794  					ld := &SSAUnOp{Op: OpMul, X: fa}
2795  					ld.typ = curType
2796  					ld.name = fb.nextName()
2797  					fb.emit(ld)
2798  					cur = ld
2799  					curType = p.Elem()
2800  					continue
2801  				}
2802  			}
2803  			cur = fa
2804  		}
2805  		return cur
2806  	}
2807  	return nil
2808  }
2809  
2810  func (fb *ssaFuncBuilder) buildIndex(e *IndexExpr) SSAValue {
2811  	x := fb.buildExpr(e.X)
2812  	idx := fb.buildExpr(e.Index)
2813  	if x == nil || idx == nil {
2814  		return nil
2815  	}
2816  	if x.SSAType() == nil {
2817  		return nil
2818  	}
2819  	switch t := safeUnderlying(x.SSAType()).(type) {
2820  	case *TCMap:
2821  		idx = fb.coerceToInterface(idx, t.Key())
2822  		l := &SSALookup{X: x, Index: idx}
2823  		l.typ = t.Elem()
2824  		l.name = fb.nextName()
2825  		fb.emit(l)
2826  		return l
2827  	default:
2828  		ia := &SSAIndexAddr{X: x, Index: idx}
2829  		ia.typ = NewPointer(ssaElemType(x.SSAType()))
2830  		ia.name = fb.nextName()
2831  		fb.emit(ia)
2832  		return fb.emitLoad(ia, ssaElemType(x.SSAType()))
2833  	}
2834  }
2835  
2836  func (fb *ssaFuncBuilder) buildSlice(e *SliceExpr) SSAValue {
2837  	x := fb.buildExpr(e.X)
2838  	if x == nil {
2839  		return nil
2840  	}
2841  	sl := &SSASlice{X: x}
2842  	if len(e.Index) > 0 && e.Index[0] != nil {
2843  		sl.Low = fb.buildExpr(e.Index[0])
2844  	}
2845  	if len(e.Index) > 1 && e.Index[1] != nil {
2846  		sl.High = fb.buildExpr(e.Index[1])
2847  	}
2848  	if len(e.Index) > 2 && e.Index[2] != nil {
2849  		sl.Max = fb.buildExpr(e.Index[2])
2850  	}
2851  	sl.typ = ssaSliceOf(x.SSAType())
2852  	sl.name = fb.nextName()
2853  	fb.emit(sl)
2854  	return sl
2855  }
2856  
2857  func (fb *ssaFuncBuilder) buildAssert(e *AssertExpr) SSAValue {
2858  	x := fb.buildExpr(e.X)
2859  	assertedType := fb.resolveType(e.Type)
2860  	if x == nil {
2861  		return nil
2862  	}
2863  	ta := &SSATypeAssert{X: x, AssertedType: assertedType, CommaOk: false}
2864  	ta.typ = assertedType
2865  	ta.name = fb.nextName()
2866  	fb.emit(ta)
2867  	return ta
2868  }
2869  
2870  func (fb *ssaFuncBuilder) buildCompositeLit(e *CompositeLit) SSAValue {
2871  	var typ Type
2872  	if e.Type != nil {
2873  		typ = fb.resolveType(e.Type)
2874  	}
2875  	if typ == nil {
2876  		return nil
2877  	}
2878  
2879  	if sl, ok := safeUnderlying(typ).(*Slice); ok {
2880  		return fb.buildSliceLit(e, typ, sl)
2881  	}
2882  
2883  	if mt, isMap := safeUnderlying(typ).(*TCMap); isMap {
2884  		mm := &SSAMakeMap{}
2885  		mm.typ = typ
2886  		mm.name = fb.nextName()
2887  		fb.emit(mm)
2888  		for _, el := range e.ElemList {
2889  			if kv, ok := el.(*KeyValueExpr); ok {
2890  				k := fb.buildExpr(kv.Key)
2891  				v := fb.buildExpr(kv.Value)
2892  				if k != nil && v != nil {
2893  					k = fb.coerceToInterface(k, mt.Key())
2894  					v = fb.coerceToInterface(v, mt.Elem())
2895  					fb.emit(&SSAMapUpdate{Map: mm, Key: k, Value: v})
2896  				}
2897  			}
2898  		}
2899  		return mm
2900  	}
2901  
2902  	if ar, isArr := safeUnderlying(typ).(*Array); isArr {
2903  		return fb.buildArrayLit(e, typ, ar)
2904  	}
2905  
2906  	alloc := fb.emitAlloc(typ, 0)
2907  	posIdx := 0
2908  	for _, el := range e.ElemList {
2909  		if kv, ok := el.(*KeyValueExpr); ok {
2910  			if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
2911  				idx := fb.fieldIndex(typ, kv.Key.(*Name).Value)
2912  				if idx >= 0 {
2913  					fa := &SSAFieldAddr{X: alloc, Field: idx}
2914  					ft := fb.fieldType(typ, idx)
2915  					fa.typ = NewPointer(ft)
2916  					fa.name = fb.nextName()
2917  					fb.emit(fa)
2918  					v := fb.buildExpr(kv.Value)
2919  					if v != nil {
2920  						v = fb.coerceToInterface(v, ft)
2921  						fb.emitStore(fa, v)
2922  					}
2923  				}
2924  			}
2925  		} else {
2926  			v := fb.buildExpr(el)
2927  			if v != nil {
2928  				if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
2929  					ft := fb.fieldType(typ, posIdx)
2930  					fa := &SSAFieldAddr{X: alloc, Field: posIdx}
2931  					fa.typ = NewPointer(ft)
2932  					fa.name = fb.nextName()
2933  					fb.emit(fa)
2934  					v = fb.coerceToInterface(v, ft)
2935  					fb.emitStore(fa, v)
2936  				}
2937  			}
2938  			posIdx++
2939  		}
2940  	}
2941  	return fb.emitLoad(alloc, typ)
2942  }
2943  
2944  func (fb *ssaFuncBuilder) buildArrayLit(e *CompositeLit, typ Type, ar *Array) SSAValue {
2945  	if ar.Len() < 0 {
2946  		ar = NewArray(ar.Elem(), int32(len(e.ElemList)))
2947  		typ = ar
2948  	}
2949  	alloc := fb.emitAlloc(typ, 0)
2950  	elemTyp := ar.Elem()
2951  	for i, el := range e.ElemList {
2952  		var expr Expr
2953  		if kv, ok := el.(*KeyValueExpr); ok {
2954  			expr = kv.Value
2955  		} else {
2956  			expr = el
2957  		}
2958  		var v SSAValue
2959  		if cl, ok := expr.(*CompositeLit); ok && cl.Type == nil {
2960  			v = fb.buildCompositeLitWithType(cl, elemTyp)
2961  		} else {
2962  			v = fb.buildExpr(expr)
2963  		}
2964  		if v == nil {
2965  			continue
2966  		}
2967  		idx := &SSAConst{typ: Typ[Int32], val: constInt{int32(i)}}
2968  		ia := &SSAIndexAddr{X: alloc, Index: idx}
2969  		ia.typ = NewPointer(elemTyp)
2970  		ia.name = fb.nextName()
2971  		fb.emit(ia)
2972  		v = fb.coerceToInterface(v, elemTyp)
2973  		fb.emitStore(ia, v)
2974  	}
2975  	return fb.emitLoad(alloc, typ)
2976  }
2977  
2978  func (fb *ssaFuncBuilder) buildCompositeLitWithType(e *CompositeLit, typ Type) SSAValue {
2979  	if sl, ok := safeUnderlying(typ).(*Slice); ok {
2980  		return fb.buildSliceLit(e, typ, sl)
2981  	}
2982  	if ar, isArr := safeUnderlying(typ).(*Array); isArr {
2983  		return fb.buildArrayLit(e, typ, ar)
2984  	}
2985  	alloc := fb.emitAlloc(typ, 0)
2986  	posIdx := 0
2987  	for _, el := range e.ElemList {
2988  		if kv, ok := el.(*KeyValueExpr); ok {
2989  			if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
2990  				idx := fb.fieldIndex(typ, kv.Key.(*Name).Value)
2991  				if idx >= 0 {
2992  					ft := fb.fieldType(typ, idx)
2993  					fa := &SSAFieldAddr{X: alloc, Field: idx}
2994  					fa.typ = NewPointer(ft)
2995  					fa.name = fb.nextName()
2996  					fb.emit(fa)
2997  					v := fb.buildExpr(kv.Value)
2998  					if v != nil {
2999  						v = fb.coerceToInterface(v, ft)
3000  						fb.emitStore(fa, v)
3001  					}
3002  				}
3003  			}
3004  		} else {
3005  			v := fb.buildExpr(el)
3006  			if v != nil {
3007  				if _, ok2 := safeUnderlying(typ).(*TCStruct); ok2 {
3008  					ft := fb.fieldType(typ, posIdx)
3009  					fa := &SSAFieldAddr{X: alloc, Field: posIdx}
3010  					fa.typ = NewPointer(ft)
3011  					fa.name = fb.nextName()
3012  					fb.emit(fa)
3013  					v = fb.coerceToInterface(v, ft)
3014  					fb.emitStore(fa, v)
3015  				}
3016  			}
3017  			posIdx++
3018  		}
3019  	}
3020  	return fb.emitLoad(alloc, typ)
3021  }
3022  
3023  func (fb *ssaFuncBuilder) buildSliceLit(e *CompositeLit, typ Type, sl *Slice) SSAValue {
3024  	n := len(e.ElemList)
3025  	nVal := &SSAConst{typ: Typ[Int32], val: constInt{int32(n)}}
3026  	ms := &SSAMakeSlice{}
3027  	ms.typ = typ
3028  	ms.name = fb.nextName()
3029  	ms.Len = nVal
3030  	ms.Cap = nVal
3031  	fb.emit(ms)
3032  
3033  	for i, el := range e.ElemList {
3034  		var v SSAValue
3035  		if kv, ok := el.(*KeyValueExpr); ok {
3036  			v = fb.buildExpr(kv.Value)
3037  		} else {
3038  			v = fb.buildExpr(el)
3039  		}
3040  		if v == nil {
3041  			continue
3042  		}
3043  		idx := &SSAConst{typ: Typ[Int32], val: constInt{int32(i)}}
3044  		ia := &SSAIndexAddr{X: ms, Index: idx}
3045  		ia.typ = NewPointer(sl.Elem())
3046  		ia.name = fb.nextName()
3047  		fb.emit(ia)
3048  		v = fb.coerceToInterface(v, sl.Elem())
3049  		fb.emitStore(ia, v)
3050  	}
3051  	return ms
3052  }
3053  
3054  func (fb *ssaFuncBuilder) buildFuncLit(e *FuncLit) SSAValue {
3055  	var sig *Signature
3056  	if fb.info != nil {
3057  		if tv, ok := fb.info.Types[e]; ok {
3058  			if okv, okok := tv.Type.(*Signature); okok {
3059  				sig = okv
3060  			}
3061  		}
3062  	}
3063  	if sig == nil && e.Type != nil {
3064  		sig = tcResolveFuncInline(e.Type, fb.fn.Pkg.Pkg.Scope())
3065  	}
3066  	name := fb.fn.name | "__anon" | ssaItoa(len(fb.fn.AnonFuncs)+1)
3067  	anon := &SSAFunction{
3068  		name:      name,
3069  		Signature: sig,
3070  		pos:       0,
3071  		Pkg:       fb.fn.Pkg,
3072  		Prog:      fb.fn.Prog,
3073  		parent:    fb.fn,
3074  	}
3075  	fb.fn.AnonFuncs = append(fb.fn.AnonFuncs, anon)
3076  
3077  	ab := newSSAFuncBuilder(anon, fb.info)
3078  	ab.parent = fb
3079  	d := &FuncDecl{
3080  		Name: &Name{Value: name},
3081  		Type: e.Type,
3082  		Body: e.Body,
3083  	}
3084  	ab.buildBody(d)
3085  
3086  	if len(anon.FreeVars) == 0 {
3087  		return anon
3088  	}
3089  	bindings := []SSAValue{:0:len(anon.FreeVars)}
3090  	for _, fv := range anon.FreeVars {
3091  		obj := fb.lookupObject(fv.name)
3092  		if obj != nil {
3093  			if alloc, ok := fb.vars[obj]; ok {
3094  				alloc.Heap = true
3095  				bindings = append(bindings, alloc)
3096  			} else {
3097  				bindings = append(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
3098  			}
3099  		} else {
3100  			bindings = append(bindings, &SSAConst{typ: NewPointer(fv.typ), val: nil})
3101  		}
3102  	}
3103  	mc := &SSAMakeClosure{Fn: anon, Bindings: bindings}
3104  	mc.typ = sig
3105  	mc.name = fb.nextName()
3106  	fb.emit(mc)
3107  	return mc
3108  }
3109  
3110  func (fb *ssaFuncBuilder) saveVars() map[Object]*SSAAlloc {
3111  	saved := map[Object]*SSAAlloc{}
3112  	for k, v := range fb.vars {
3113  		saved[k] = v
3114  	}
3115  	return saved
3116  }
3117  
3118  func (fb *ssaFuncBuilder) removeVar(name string) {
3119  	for o := range fb.vars {
3120  		if o.Name() == name {
3121  			delete(fb.vars, o)
3122  			return
3123  		}
3124  	}
3125  }
3126  
3127  
3128  func (fb *ssaFuncBuilder) buildPkgMemberAddr(pn *PkgName, memberName string) SSAValue {
3129  	imported := pn.Imported()
3130  	if imported == nil {
3131  		return nil
3132  	}
3133  	obj := imported.Scope().Lookup(memberName)
3134  	if obj == nil {
3135  		return nil
3136  	}
3137  	switch obj := obj.(type) {
3138  	case *TCConst:
3139  		return nil
3140  	case *TCVar:
3141  		impPkg := fb.ensureImportedSSAPackage(imported)
3142  		g, ok := impPkg.Members[memberName].(*SSAGlobal)
3143  		if !ok {
3144  			g = &SSAGlobal{
3145  				name: memberName,
3146  				typ:  NewPointer(obj.Type()),
3147  				pkg:  impPkg,
3148  			}
3149  			impPkg.Members[memberName] = g
3150  		}
3151  		return g
3152  	}
3153  	return nil
3154  }
3155  
3156  func (fb *ssaFuncBuilder) buildPkgCall(pn *PkgName, funcName string, argList []Expr, hasDots bool) SSAValue {
3157  	imported := pn.Imported()
3158  	if imported == nil {
3159  		return nil
3160  	}
3161  	if imported.Path() == "unsafe" && funcName == "Slice" {
3162  		return fb.buildUnsafeSlice(argList)
3163  	}
3164  	if imported.Path() == "unsafe" && funcName == "SliceData" {
3165  		arg := fb.buildExpr(argList[0])
3166  		extract := &SSAExtract{Tuple: arg, Index: 0}
3167  		extract.typ = Typ[UnsafePointer]
3168  		extract.name = fb.nextName()
3169  		extract.setBlock(fb.currentBlock)
3170  		fb.currentBlock.Instrs = append(fb.currentBlock.Instrs, extract)
3171  		return extract
3172  	}
3173  	if result := fb.tryGenericPkgCall(pn, funcName, argList, hasDots); result != nil {
3174  		return result
3175  	}
3176  	obj := imported.Scope().Lookup(funcName)
3177  	if obj == nil {
3178  		return nil
3179  	}
3180  	fn, ok := obj.(*TCFunc)
3181  	if !ok {
3182  		return nil
3183  	}
3184  	impPkg := fb.ensureImportedSSAPackage(imported)
3185  	ssaFn := impPkg.Func(funcName)
3186  	if ssaFn == nil {
3187  		ssaFn = &SSAFunction{
3188  			name:      funcName,
3189  			object:    fn,
3190  			Signature: fn.Type().(*Signature),
3191  			Pkg:       impPkg,
3192  			Prog:      fb.fn.Prog,
3193  		}
3194  		if isNoContextExtern(imported.Path(), funcName) {
3195  			ssaFn.isExternC = true
3196  		}
3197  		impPkg.Members[funcName] = ssaFn
3198  	}
3199  	args := fb.buildArgs(argList)
3200  	var retType Type
3201  	if ssaFn.Signature != nil {
3202  		if ssaFn.Signature.Variadic() && !hasDots {
3203  			args = fb.wrapVariadicArgs(args, ssaFn.Signature)
3204  		}
3205  		args = fb.coerceArgsToInterface(args, ssaFn.Signature)
3206  		if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() == 1 {
3207  			retType = ssaFn.Signature.Results().At(0).Type()
3208  		} else if ssaFn.Signature.Results() != nil && ssaFn.Signature.Results().Len() > 1 {
3209  			retType = ssaFn.Signature.Results()
3210  		}
3211  	}
3212  	call := &SSACall{Call: SSACallCommon{Value: ssaFn, Args: args}}
3213  	call.typ = retType
3214  	call.name = fb.nextName()
3215  	fb.emit(call)
3216  	if retType == nil {
3217  		return nil
3218  	}
3219  	return call
3220  }
3221  
3222  func (fb *ssaFuncBuilder) buildUnsafeSlice(argList []Expr) SSAValue {
3223  	if len(argList) < 2 {
3224  		return nil
3225  	}
3226  	ptrVal := fb.buildExpr(argList[0])
3227  	lenVal := fb.buildExpr(argList[1])
3228  	if ptrVal == nil || lenVal == nil {
3229  		return nil
3230  	}
3231  	var elemType Type
3232  	if pt, ok := safeUnderlying(ptrVal.SSAType()).(*Pointer); ok {
3233  		elemType = pt.Elem()
3234  	}
3235  	if elemType == nil {
3236  		elemType = Typ[Uint8]
3237  	}
3238  	ms := &SSAMakeSlice{Len: lenVal, Cap: lenVal, Data: ptrVal}
3239  	if b, ok := elemType.(*Basic); ok && b.kind == Uint8 {
3240  		ms.typ = Typ[TCString]
3241  	} else {
3242  		ms.typ = NewSlice(elemType)
3243  	}
3244  	ms.name = fb.nextName()
3245  	fb.emit(ms)
3246  	return ms
3247  }
3248  
3249  // Helpers.
3250  
3251  func (fb *ssaFuncBuilder) lookupObject(name string) Object {
3252  	for obj := range fb.vars {
3253  		if obj.Name() == name {
3254  			return obj
3255  		}
3256  	}
3257  	if fb.parent != nil {
3258  		for obj := range fb.parent.vars {
3259  			if obj.Name() == name {
3260  				return obj
3261  			}
3262  		}
3263  	}
3264  	if fb.fn.Pkg != nil {
3265  		if _, obj := fb.fn.Pkg.Pkg.Scope().LookupParent(name); obj != nil {
3266  			return obj
3267  		}
3268  	}
3269  	if fb.srcScope != nil {
3270  		if _, obj := fb.srcScope.LookupParent(name); obj != nil {
3271  			return obj
3272  		}
3273  	}
3274  	if fb.info != nil {
3275  		return nil
3276  	}
3277  	return nil
3278  }
3279  
3280  func (fb *ssaFuncBuilder) getOrCreateFreeVar(name string, typ Type) SSAValue {
3281  	for _, fv := range fb.fn.FreeVars {
3282  		if fv.name == name {
3283  			return fv
3284  		}
3285  	}
3286  	fv := &SSAFreeVar{
3287  		name:   name,
3288  		typ:    typ,
3289  		parent: fb.fn,
3290  	}
3291  	fb.fn.FreeVars = append(fb.fn.FreeVars, fv)
3292  	if fb.freeVarPtrs == nil {
3293  		fb.freeVarPtrs = map[string]*SSAFreeVar{}
3294  	}
3295  	fb.freeVarPtrs[name] = fv
3296  	return fv
3297  }
3298  
3299  func (fb *ssaFuncBuilder) lookupVar(name string) *TCVar {
3300  	obj := fb.lookupObject(name)
3301  	var v *TCVar
3302  	if okv, okok := obj.(*TCVar); okok {
3303  		v = okv
3304  	}
3305  	return v
3306  }
3307  
3308  func (fb *ssaFuncBuilder) resolveMethodCallWithRecv(sel *SelectorExpr, recv SSAValue) (*SSAFunction, SSAValue) {
3309  	typ := recv.SSAType()
3310  	isPtr := false
3311  	if p, ok := safeUnderlying(typ).(*Pointer); ok {
3312  		typ = p.Elem()
3313  		isPtr = true
3314  	}
3315  	if _, ok := safeUnderlying(typ).(*TCInterface); ok {
3316  		return nil, nil
3317  	}
3318  	named, ok := typ.(*Named)
3319  	if !ok {
3320  		return nil, nil
3321  	}
3322  	typeName := ""
3323  	if named.Obj() != nil {
3324  		typeName = named.Obj().Name()
3325  	}
3326  	if typeName == "" {
3327  		return nil, nil
3328  	}
3329  	mangledName := typeName | "." | sel.Sel.Value
3330  	var fn *SSAFunction
3331  	if okv, okok := fb.fn.Pkg.Members[mangledName].(*SSAFunction); okok {
3332  		fn = okv
3333  	}
3334  	if fn == nil {
3335  		for i := 0; i < named.NumMethods(); i++ {
3336  			m := named.Method(i)
3337  			if m.Name() == sel.Sel.Value {
3338  				fn = fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
3339  				if named.Obj() != nil && named.Obj().Pkg() != nil && named.Obj().Pkg().Path() != fb.fn.Pkg.Pkg.Path() {
3340  					pkgPath := named.Obj().Pkg().Path()
3341  					fn.externalSymbol = pkgPath | "." | typeName | "." | sel.Sel.Value
3342  				}
3343  				break
3344  			}
3345  		}
3346  	}
3347  	if fn != nil {
3348  		if fn.Signature != nil && fn.Signature.Recv() != nil {
3349  			recvParam := fn.Signature.Recv()
3350  			_, recvIsPtr := safeUnderlying(recvParam.Type()).(*Pointer)
3351  			if recvIsPtr && !isPtr {
3352  				if nameExpr, ok2 := sel.X.(*Name); ok2 {
3353  					obj := fb.lookupObject(nameExpr.Value)
3354  					if obj != nil {
3355  						if alloc, ok3 := fb.vars[obj]; ok3 {
3356  							recv = alloc
3357  						}
3358  					}
3359  				} else if innerSel, ok2 := sel.X.(*SelectorExpr); ok2 {
3360  					addr := fb.buildSelectorAddr(innerSel)
3361  					if addr != nil {
3362  						recv = addr
3363  					}
3364  				}
3365  			}
3366  		}
3367  		return fn, recv
3368  	}
3369  	st, ok2 := safeUnderlying(named).(*TCStruct)
3370  	if !ok2 {
3371  		return nil, nil
3372  	}
3373  	if !isPtr {
3374  		fixed := false
3375  		if innerSel, ok3 := sel.X.(*SelectorExpr); ok3 {
3376  			addr := fb.buildSelectorAddr(innerSel)
3377  			if addr != nil {
3378  				recv = addr
3379  				fixed = true
3380  			}
3381  		}
3382  		if !fixed {
3383  			if nameExpr, ok3 := sel.X.(*Name); ok3 {
3384  				obj := fb.lookupObject(nameExpr.Value)
3385  				if obj != nil {
3386  					if a, ok4 := fb.vars[obj]; ok4 {
3387  						recv = a
3388  						fixed = true
3389  					}
3390  				}
3391  			}
3392  		}
3393  		if !fixed {
3394  			alloc := &SSAAlloc{}
3395  			alloc.typ = NewPointer(recv.SSAType())
3396  			alloc.name = fb.nextName()
3397  			fb.emit(alloc)
3398  			storeOp := &SSAStore{Addr: alloc, Val: recv}
3399  			fb.emit(storeOp)
3400  			recv = alloc
3401  		}
3402  	}
3403  	for i := 0; i < st.NumFields(); i++ {
3404  		f := st.Field(i)
3405  		if !f.Anonymous() {
3406  			continue
3407  		}
3408  		embedType := f.Type()
3409  		embedNamed, ok3 := embedType.(*Named)
3410  		if !ok3 {
3411  			if p, ok4 := embedType.(*Pointer); ok4 {
3412  				embedNamed, ok3 = p.Elem().(*Named)
3413  			}
3414  		}
3415  		if !ok3 || embedNamed.Obj() == nil {
3416  			continue
3417  		}
3418  		embedName := embedNamed.Obj().Name()
3419  		embedMangledName := embedName | "." | sel.Sel.Value
3420  		var embedFn *SSAFunction
3421  		if okv, okok := fb.fn.Pkg.Members[embedMangledName].(*SSAFunction); okok {
3422  			embedFn = okv
3423  		}
3424  		if embedFn != nil {
3425  			fieldAddr := &SSAFieldAddr{
3426  				X:     recv,
3427  				Field: i,
3428  			}
3429  			fieldAddr.typ = NewPointer(embedType)
3430  			fieldAddr.name = fb.nextName()
3431  			fb.emit(fieldAddr)
3432  			var embedRecv SSAValue = fieldAddr
3433  			if _, isEmbedPtr := safeUnderlying(embedType).(*Pointer); isEmbedPtr {
3434  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
3435  				ld.typ = embedType
3436  				ld.name = fb.nextName()
3437  				fb.emit(ld)
3438  				embedRecv = ld
3439  			}
3440  			return embedFn, embedRecv
3441  		}
3442  		embedSt, ok5 := safeUnderlying(embedNamed).(*TCStruct)
3443  		if !ok5 {
3444  			continue
3445  		}
3446  		for j := 0; j < embedSt.NumFields(); j++ {
3447  			f2 := embedSt.Field(j)
3448  			if !f2.Anonymous() {
3449  				continue
3450  			}
3451  			embed2Type := f2.Type()
3452  			embed2Named, ok6 := embed2Type.(*Named)
3453  			if !ok6 {
3454  				if p2, ok7 := embed2Type.(*Pointer); ok7 {
3455  					embed2Named, ok6 = p2.Elem().(*Named)
3456  				}
3457  			}
3458  			if !ok6 || embed2Named.Obj() == nil {
3459  				continue
3460  			}
3461  			embed2Name := embed2Named.Obj().Name()
3462  			embed2Mangled := embed2Name | "." | sel.Sel.Value
3463  			var embed2Fn *SSAFunction
3464  			if okv, okok := fb.fn.Pkg.Members[embed2Mangled].(*SSAFunction); okok {
3465  				embed2Fn = okv
3466  			}
3467  			if embed2Fn == nil {
3468  				continue
3469  			}
3470  			fieldAddr1 := &SSAFieldAddr{X: recv, Field: i}
3471  			fieldAddr1.typ = NewPointer(embedType)
3472  			fieldAddr1.name = fb.nextName()
3473  			fb.emit(fieldAddr1)
3474  			var cur1 SSAValue = fieldAddr1
3475  			curEmbedType := embedType
3476  			if p5, ok8 := safeUnderlying(embedType).(*Pointer); ok8 {
3477  				ld := &SSAUnOp{Op: OpMul, X: fieldAddr1}
3478  				ld.typ = embedType
3479  				ld.name = fb.nextName()
3480  				fb.emit(ld)
3481  				cur1 = ld
3482  				curEmbedType = p5.Elem()
3483  			}
3484  			_ = curEmbedType
3485  			fieldAddr2 := &SSAFieldAddr{X: cur1, Field: j}
3486  			fieldAddr2.typ = NewPointer(embed2Type)
3487  			fieldAddr2.name = fb.nextName()
3488  			fb.emit(fieldAddr2)
3489  			var embedRecv2 SSAValue = fieldAddr2
3490  			if _, isEmbedPtr2 := safeUnderlying(embed2Type).(*Pointer); isEmbedPtr2 {
3491  				ld2 := &SSAUnOp{Op: OpMul, X: fieldAddr2}
3492  				ld2.typ = embed2Type
3493  				ld2.name = fb.nextName()
3494  				fb.emit(ld2)
3495  				embedRecv2 = ld2
3496  			}
3497  			return embed2Fn, embedRecv2
3498  		}
3499  	}
3500  	return nil, nil
3501  }
3502  
3503  func (fb *ssaFuncBuilder) buildIfaceMethodCall(sel *SelectorExpr, recv SSAValue, argExprs []Expr) SSAValue {
3504  	typ := recv.SSAType()
3505  	if p, ok := safeUnderlying(typ).(*Pointer); ok {
3506  		typ = p.Elem()
3507  	}
3508  	iface, ok := safeUnderlying(typ).(*TCInterface)
3509  	if !ok {
3510  		return nil
3511  	}
3512  	var methodSig *Signature
3513  	for i := 0; i < iface.NumMethods(); i++ {
3514  		if iface.Method(i).Name() == sel.Sel.Value {
3515  			methodSig = iface.Method(i).Sig()
3516  			break
3517  		}
3518  	}
3519  	var retType Type
3520  	if methodSig != nil && methodSig.Results() != nil {
3521  		if methodSig.Results().Len() == 1 {
3522  			retType = methodSig.Results().At(0).Type()
3523  		} else if methodSig.Results().Len() > 1 {
3524  			retType = methodSig.Results()
3525  		}
3526  	}
3527  	args := fb.buildArgs(argExprs)
3528  	inv := &SSAInvoke{
3529  		X:          recv,
3530  		MethodName: sel.Sel.Value,
3531  		IfaceType:  iface,
3532  		Args:       args,
3533  	}
3534  	inv.typ = retType
3535  	inv.name = fb.nextName()
3536  	fb.emit(inv)
3537  	if retType == nil {
3538  		return nil
3539  	}
3540  	return inv
3541  }
3542  
3543  func (fb *ssaFuncBuilder) resolveType(e Expr) Type {
3544  	if fb.info != nil {
3545  		if tv, ok := fb.info.Types[e]; ok && tv.Type != nil {
3546  			return tv.Type
3547  		}
3548  	}
3549  	return fb.resolveTypeAST(e)
3550  }
3551  
3552  func (fb *ssaFuncBuilder) resolveTypeAST(e Expr) Type {
3553  	if e == nil {
3554  		return nil
3555  	}
3556  	switch e := e.(type) {
3557  	case *Name:
3558  		if fb.typeSubst != nil {
3559  			if t, ok := fb.typeSubst[e.Value]; ok {
3560  				return t
3561  			}
3562  		}
3563  		if t, ok := fb.localTypes[e.Value]; ok {
3564  			return t
3565  		}
3566  		obj := fb.lookupObject(e.Value)
3567  		if tn, ok := obj.(*TypeName); ok {
3568  			if tp, ok2 := tn.Type().(*TypeParam); ok2 && fb.typeSubst != nil {
3569  				if t, ok3 := fb.typeSubst[tp.String()]; ok3 {
3570  					return t
3571  				}
3572  			}
3573  			return tn.Type()
3574  		}
3575  	case *Operation:
3576  		if e.Y == nil && e.Op == Mul {
3577  			base := fb.resolveTypeAST(e.X)
3578  			if base != nil {
3579  				return NewPointer(base)
3580  			}
3581  		}
3582  	case *SliceType:
3583  		elem := fb.resolveTypeAST(e.Elem)
3584  		if elem != nil {
3585  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3586  				return Typ[TCString]
3587  			}
3588  			return NewSlice(elem)
3589  		}
3590  	case *ArrayType:
3591  		elem := fb.resolveTypeAST(e.Elem)
3592  		if elem != nil {
3593  			n := int32(-1)
3594  			if lit, ok := e.Len.(*BasicLit); ok {
3595  				n = ssaParseInt64(lit.Value)
3596  			}
3597  			return NewArray(elem, n)
3598  		}
3599  	case *MapType:
3600  		key := fb.resolveTypeAST(e.Key)
3601  		val := fb.resolveTypeAST(e.Value)
3602  		if key != nil && val != nil {
3603  			return NewTCMap(key, val)
3604  		}
3605  	case *StructType:
3606  		return fb.resolveStructTypeAST(e)
3607  	case *InterfaceType:
3608  		return fb.resolveInterfaceTypeAST(e)
3609  	case *FuncType:
3610  		return fb.resolveFuncTypeAST(e)
3611  	case *SelectorExpr:
3612  		if x, ok := e.X.(*Name); ok {
3613  			obj := fb.lookupObject(x.Value)
3614  			if pn, ok2 := obj.(*PkgName); ok2 && pn.Imported() != nil {
3615  				sel := pn.Imported().Scope().Lookup(e.Sel.Value)
3616  				if tn, ok3 := sel.(*TypeName); ok3 {
3617  					return tn.Type()
3618  				}
3619  			}
3620  		}
3621  	case *ParenExpr:
3622  		return fb.resolveTypeAST(e.X)
3623  	}
3624  	return nil
3625  }
3626  
3627  func (fb *ssaFuncBuilder) resolveInterfaceTypeAST(e *InterfaceType) *TCInterface {
3628  	var methods []*IfaceMethod
3629  	for _, f := range e.MethodList {
3630  		if f.Name == nil {
3631  			continue
3632  		}
3633  		ft, ok := f.Type.(*FuncType)
3634  		if !ok {
3635  			continue
3636  		}
3637  		sig := fb.resolveFuncTypeAST(ft)
3638  		if sig != nil {
3639  			methods = append(methods, NewTCIfaceMethod(f.Name.Value, sig))
3640  		}
3641  	}
3642  	iface := NewTCInterface(methods, nil)
3643  	iface.Complete()
3644  	return iface
3645  }
3646  
3647  func (fb *ssaFuncBuilder) resolveStructTypeAST(e *StructType) *TCStruct {
3648  	var fields []*TCVar
3649  	var tags []string
3650  	for i, f := range e.FieldList {
3651  		typ := fb.resolveTypeAST(f.Type)
3652  		if typ == nil {
3653  			return nil
3654  		}
3655  		name := ""
3656  		if f.Name != nil {
3657  			name = f.Name.Value
3658  		}
3659  		fields = append(fields, NewTCField(fb.fn.Pkg.Pkg, name, typ, f.Name == nil))
3660  		tag := ""
3661  		if i < len(e.TagList) && e.TagList[i] != nil {
3662  			tag = e.TagList[i].Value
3663  		}
3664  		tags = append(tags, tag)
3665  	}
3666  	return NewTCStruct(fields, tags)
3667  }
3668  
3669  func (fb *ssaFuncBuilder) resolveFuncTypeAST(ft *FuncType) *Signature {
3670  	if ft == nil {
3671  		return nil
3672  	}
3673  	var params []*TCVar
3674  	for _, p := range ft.ParamList {
3675  		typ := fb.resolveTypeAST(p.Type)
3676  		pname := ""
3677  		if p.Name != nil {
3678  			pname = p.Name.Value
3679  		}
3680  		params = append(params, NewTCVar(nil, pname, typ))
3681  	}
3682  	var results []*TCVar
3683  	for _, r := range ft.ResultList {
3684  		typ := fb.resolveTypeAST(r.Type)
3685  		rname := ""
3686  		if r.Name != nil {
3687  			rname = r.Name.Value
3688  		}
3689  		results = append(results, NewTCVar(nil, rname, typ))
3690  	}
3691  	var pTuple, rTuple *Tuple
3692  	if len(params) > 0 {
3693  		pTuple = NewTuple(params...)
3694  	}
3695  	if len(results) > 0 {
3696  		rTuple = NewTuple(results...)
3697  	}
3698  	return NewSignature(nil, pTuple, rTuple, false)
3699  }
3700  
3701  func (fb *ssaFuncBuilder) fieldIndex(t Type, name string) int32 {
3702  	if t == nil {
3703  		return -1
3704  	}
3705  	if pt, ok := safeUnderlying(t).(*Pointer); ok {
3706  		t = pt.Elem()
3707  	}
3708  	if st, ok := safeUnderlying(t).(*TCStruct); ok {
3709  		for i := 0; i < st.NumFields(); i++ {
3710  			if st.Field(i).Name() == name {
3711  				return i
3712  			}
3713  		}
3714  	}
3715  	return -1
3716  }
3717  
3718  func (fb *ssaFuncBuilder) findEmbeddedField(t Type, name string) (embedIdx int32, innerIdx int32) {
3719  	path := fb.findEmbeddedFieldPath(t, name)
3720  	if len(path) < 2 {
3721  		return -1, -1
3722  	}
3723  	return path[0], path[1]
3724  }
3725  
3726  func (fb *ssaFuncBuilder) findEmbeddedFieldPath(t Type, name string) []int32 {
3727  	if t == nil {
3728  		return nil
3729  	}
3730  	if pt, ok := safeUnderlying(t).(*Pointer); ok {
3731  		t = pt.Elem()
3732  	}
3733  	st, ok := safeUnderlying(t).(*TCStruct)
3734  	if !ok {
3735  		return nil
3736  	}
3737  	for i := 0; i < st.NumFields(); i++ {
3738  		f := st.Field(i)
3739  		if !f.Anonymous() {
3740  			continue
3741  		}
3742  		embedType := f.Type()
3743  		if pt, ok := safeUnderlying(embedType).(*Pointer); ok {
3744  			embedType = pt.Elem()
3745  		}
3746  		inner := fb.fieldIndex(embedType, name)
3747  		if inner >= 0 {
3748  			return []int32{i, inner}
3749  		}
3750  		sub := fb.findEmbeddedFieldPath(embedType, name)
3751  		if len(sub) > 0 {
3752  			return append([]int32{i}, sub...)
3753  		}
3754  	}
3755  	return nil
3756  }
3757  
3758  func (fb *ssaFuncBuilder) fieldType(t Type, idx int32) Type {
3759  	if t == nil {
3760  		return nil
3761  	}
3762  	if pt, ok := safeUnderlying(t).(*Pointer); ok {
3763  		t = pt.Elem()
3764  	}
3765  	if st, ok := safeUnderlying(t).(*TCStruct); ok {
3766  		if idx >= 0 && idx < st.NumFields() {
3767  			return st.Field(idx).Type()
3768  		}
3769  	}
3770  	return nil
3771  }
3772  
3773  func ssaExprNames(e Expr) []*Name {
3774  	if e == nil {
3775  		return nil
3776  	}
3777  	if n, ok := e.(*Name); ok {
3778  		return []*Name{n}
3779  	}
3780  	if l, ok := e.(*ListExpr); ok {
3781  		var names []*Name
3782  		for _, el := range l.ElemList {
3783  			if n, ok := el.(*Name); ok {
3784  				names = append(names, n)
3785  			}
3786  		}
3787  		return names
3788  	}
3789  	return nil
3790  }
3791  
3792  func localizeConstVal(val ConstVal, typ Type) ConstVal {
3793  	if val == nil {
3794  		return nil
3795  	}
3796  	return val
3797  }
3798  
3799  func mangleGenericName(baseName string, typeArgs []Type) string {
3800  	s := baseName | "__"
3801  	for i, t := range typeArgs {
3802  		if i > 0 {
3803  			s = s | "_"
3804  		}
3805  		if t == nil {
3806  			s = s | "nil"
3807  		} else {
3808  			ts := t.String()
3809  			for j := 0; j < len(ts); j++ {
3810  				c := ts[j]
3811  				if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') {
3812  					s = s | string([]byte{c})
3813  				} else if c == '.' {
3814  					s = s | "."
3815  				} else {
3816  					s = s | "_"
3817  				}
3818  			}
3819  		}
3820  	}
3821  	return s
3822  }
3823  
3824  func resolveTypeExprWithSubst(e Expr, typeSubst map[string]Type, pkgScope *Scope) Type {
3825  	if e == nil {
3826  		return nil
3827  	}
3828  	switch e := e.(type) {
3829  	case *Name:
3830  		if t, ok := typeSubst[e.Value]; ok {
3831  			return t
3832  		}
3833  		_, obj := Universe.LookupParent(e.Value)
3834  		if obj != nil {
3835  			if tn, ok := obj.(*TypeName); ok {
3836  				return tn.typ
3837  			}
3838  		}
3839  		if pkgScope != nil {
3840  			tobj := pkgScope.Lookup(e.Value)
3841  			if tobj != nil {
3842  				if tn, ok := tobj.(*TypeName); ok {
3843  					return tn.typ
3844  				}
3845  			}
3846  		}
3847  		if importRegistry != nil {
3848  			var regKeys []string
3849  			for k := range importRegistry {
3850  				regKeys = append(regKeys, k)
3851  			}
3852  			for i := 1; i < len(regKeys); i++ {
3853  				for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
3854  					regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
3855  				}
3856  			}
3857  			for _, k := range regKeys {
3858  				pkg := importRegistry[k]
3859  				tobj := pkg.Scope().Lookup(e.Value)
3860  				if tobj != nil {
3861  					if tn, ok := tobj.(*TypeName); ok {
3862  						return tn.typ
3863  					}
3864  				}
3865  			}
3866  		}
3867  		return nil
3868  	case *DotsType:
3869  		elem := resolveTypeExprWithSubst(e.Elem, typeSubst, pkgScope)
3870  		if elem != nil {
3871  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3872  				return Typ[TCString]
3873  			}
3874  			return NewSlice(elem)
3875  		}
3876  	case *SliceType:
3877  		elem := resolveTypeExprWithSubst(e.Elem, typeSubst, pkgScope)
3878  		if elem != nil {
3879  			if b, ok := elem.(*Basic); ok && b.kind == Uint8 {
3880  				return Typ[TCString]
3881  			}
3882  			return NewSlice(elem)
3883  		}
3884  	case *Operation:
3885  		if e.Y == nil && e.Op == Mul {
3886  			base := resolveTypeExprWithSubst(e.X, typeSubst, pkgScope)
3887  			if base != nil {
3888  				return NewPointer(base)
3889  			}
3890  		}
3891  	case *MapType:
3892  		key := resolveTypeExprWithSubst(e.Key, typeSubst, pkgScope)
3893  		val := resolveTypeExprWithSubst(e.Value, typeSubst, pkgScope)
3894  		if key != nil && val != nil {
3895  			return NewTCMap(key, val)
3896  		}
3897  	case *FuncType:
3898  		return resolveSignatureWithSubst(e, typeSubst, pkgScope)
3899  	case *SelectorExpr:
3900  		if pkgName, ok := e.X.(*Name); ok {
3901  			if importRegistry != nil {
3902  				var regKeys []string
3903  				for k := range importRegistry {
3904  					regKeys = append(regKeys, k)
3905  				}
3906  				for i := 1; i < len(regKeys); i++ {
3907  					for j := i; j > 0 && regKeys[j] < regKeys[j-1]; j-- {
3908  						regKeys[j], regKeys[j-1] = regKeys[j-1], regKeys[j]
3909  					}
3910  				}
3911  				for _, k := range regKeys {
3912  					pkg := importRegistry[k]
3913  					if pkg.Name() == pkgName.Value {
3914  						typeObj := pkg.Scope().Lookup(e.Sel.Value)
3915  						if typeObj != nil {
3916  							if tn, ok2 := typeObj.(*TypeName); ok2 {
3917  								return tn.typ
3918  							}
3919  						}
3920  						break
3921  					}
3922  				}
3923  			}
3924  		}
3925  	}
3926  	return nil
3927  }
3928  
3929  func resolveSignatureWithSubst(ft *FuncType, typeSubst map[string]Type, pkgScope *Scope) *Signature {
3930  	if ft == nil {
3931  		return nil
3932  	}
3933  	var params []*TCVar
3934  	variadic := false
3935  	for _, p := range ft.ParamList {
3936  		typ := resolveTypeExprWithSubst(p.Type, typeSubst, pkgScope)
3937  		name := ""
3938  		if p.Name != nil {
3939  			name = p.Name.Value
3940  		}
3941  		params = append(params, NewTCVar(nil, name, typ))
3942  	}
3943  	if len(ft.ParamList) > 0 {
3944  		last := ft.ParamList[len(ft.ParamList)-1]
3945  		if _, ok := last.Type.(*DotsType); ok {
3946  			variadic = true
3947  		}
3948  	}
3949  	var results []*TCVar
3950  	for _, r := range ft.ResultList {
3951  		typ := resolveTypeExprWithSubst(r.Type, typeSubst, pkgScope)
3952  		name := ""
3953  		if r.Name != nil {
3954  			name = r.Name.Value
3955  		}
3956  		results = append(results, NewTCVar(nil, name, typ))
3957  	}
3958  	var paramTuple *Tuple
3959  	if len(params) > 0 {
3960  		paramTuple = NewTuple(params...)
3961  	}
3962  	var resultTuple *Tuple
3963  	if len(results) > 0 {
3964  		resultTuple = NewTuple(results...)
3965  	}
3966  	return NewSignature(nil, paramTuple, resultTuple, variadic)
3967  }
3968  
3969  func matchTypeParam(paramType Expr, argType Type, tparams []*Field, typeMap map[string]Type) {
3970  	if paramType == nil || argType == nil {
3971  		return
3972  	}
3973  	switch pt := paramType.(type) {
3974  	case *Name:
3975  		for _, tp := range tparams {
3976  			if tp.Name != nil && tp.Name.Value == pt.Value {
3977  				typeMap[pt.Value] = argType
3978  				return
3979  			}
3980  		}
3981  	case *DotsType:
3982  		if sl, ok := safeUnderlying(argType).(*Slice); ok {
3983  			matchTypeParam(pt.Elem, sl.Elem(), tparams, typeMap)
3984  		} else {
3985  			matchTypeParam(pt.Elem, argType, tparams, typeMap)
3986  		}
3987  	case *SliceType:
3988  		if sl, ok := safeUnderlying(argType).(*Slice); ok {
3989  			matchTypeParam(pt.Elem, sl.Elem(), tparams, typeMap)
3990  		}
3991  	}
3992  }
3993  
3994  func inferFromConstraints(tparams []*Field, typeMap map[string]Type) {
3995  	for _, tp := range tparams {
3996  		if tp.Name == nil || tp.Type == nil {
3997  			continue
3998  		}
3999  		knownType, ok := typeMap[tp.Name.Value]
4000  		if !ok {
4001  			continue
4002  		}
4003  		extractConstraintTypeParams(tp.Type, knownType, tparams, typeMap)
4004  	}
4005  }
4006  
4007  func extractConstraintTypeParams(constraint Expr, concreteType Type, tparams []*Field, typeMap map[string]Type) {
4008  	if constraint == nil || concreteType == nil {
4009  		return
4010  	}
4011  	switch c := constraint.(type) {
4012  	case *Operation:
4013  		if c.Op == Tilde && c.Y == nil {
4014  			extractConstraintTypeParams(c.X, concreteType, tparams, typeMap)
4015  		}
4016  	case *SliceType:
4017  		if sl, ok := safeUnderlying(concreteType).(*Slice); ok {
4018  			if name, ok2 := c.Elem.(*Name); ok2 {
4019  				for _, tp := range tparams {
4020  					if tp.Name != nil && tp.Name.Value == name.Value {
4021  						if _, already := typeMap[name.Value]; !already {
4022  							typeMap[name.Value] = sl.Elem()
4023  						}
4024  					}
4025  				}
4026  			}
4027  		}
4028  	}
4029  }
4030  
4031  func inferTypeArgsFromFunc(fd *FuncDecl, args []SSAValue) []Type {
4032  	typeMap := map[string]Type{}
4033  	if fd.Type != nil {
4034  		for i, param := range fd.Type.ParamList {
4035  			if i >= len(args) || args[i] == nil || args[i].SSAType() == nil {
4036  				continue
4037  			}
4038  			matchTypeParam(param.Type, args[i].SSAType(), fd.TParamList, typeMap)
4039  		}
4040  	}
4041  	inferFromConstraints(fd.TParamList, typeMap)
4042  	var result []Type
4043  	for _, tp := range fd.TParamList {
4044  		if tp.Name != nil {
4045  			result = append(result, typeMap[tp.Name.Value])
4046  		}
4047  	}
4048  	return result
4049  }
4050  
4051  func (fb *ssaFuncBuilder) monomorphizeAndCall(fd *FuncDecl, baseName string, typeArgs []Type, args []SSAValue, targetPkg *SSAPackage, srcPkgPath string, hasDots bool) SSAValue {
4052  	mangledName := mangleGenericName(baseName, typeArgs)
4053  	if fn, ok := targetPkg.Members[mangledName].(*SSAFunction); ok {
4054  		return fb.emitCallToSSAFunc(fn, args, hasDots)
4055  	}
4056  	typeSubst := map[string]Type{}
4057  	for i, tp := range fd.TParamList {
4058  		if tp.Name != nil && i < len(typeArgs) && typeArgs[i] != nil {
4059  			typeSubst[tp.Name.Value] = typeArgs[i]
4060  		}
4061  	}
4062  	var srcScope *Scope
4063  	if genericPkgScopes != nil {
4064  		if sc, ok := genericPkgScopes[srcPkgPath]; ok {
4065  			srcScope = sc
4066  		}
4067  	}
4068  	sig := resolveSignatureWithSubst(fd.Type, typeSubst, srcScope)
4069  	if sig == nil {
4070  		return nil
4071  	}
4072  	fn := &SSAFunction{
4073  		name:      mangledName,
4074  		Signature: sig,
4075  		Pkg:       targetPkg,
4076  		Prog:      fb.fn.Prog,
4077  	}
4078  	targetPkg.Members[mangledName] = fn
4079  	subFb := newSSAFuncBuilder(fn, fb.info)
4080  	subFb.typeSubst = typeSubst
4081  	subFb.srcScope = srcScope
4082  	subFb.buildBody(fd)
4083  	return fb.emitCallToSSAFunc(fn, args, hasDots)
4084  }
4085  
4086  func (fb *ssaFuncBuilder) emitCallToSSAFunc(fn *SSAFunction, args []SSAValue, hasDots bool) SSAValue {
4087  	if fn.Signature != nil {
4088  		if fn.Signature.Variadic() && !hasDots {
4089  			args = fb.wrapVariadicArgs(args, fn.Signature)
4090  		}
4091  		args = fb.coerceArgsToInterface(args, fn.Signature)
4092  	}
4093  	var retType Type
4094  	if fn.Signature != nil && fn.Signature.Results() != nil {
4095  		if fn.Signature.Results().Len() == 1 {
4096  			retType = fn.Signature.Results().At(0).Type()
4097  		} else if fn.Signature.Results().Len() > 1 {
4098  			retType = fn.Signature.Results()
4099  		}
4100  	}
4101  	call := &SSACall{Call: SSACallCommon{Value: fn, Args: args}}
4102  	call.typ = retType
4103  	call.name = fb.nextName()
4104  	fb.emit(call)
4105  	if retType == nil {
4106  		return nil
4107  	}
4108  	return call
4109  }
4110  
4111  func (fb *ssaFuncBuilder) tryGenericLocalCall(funcName string, argList []Expr, hasDots bool) SSAValue {
4112  	pkgPath := fb.fn.Pkg.Pkg.Path()
4113  	key := pkgPath + "." + funcName
4114  	fd, ok := genericFuncDecls[key]
4115  	if !ok {
4116  		if fb.srcScope != nil && genericPkgScopes != nil {
4117  			for gPkg, gScope := range genericPkgScopes {
4118  				if gScope == fb.srcScope {
4119  					key = gPkg + "." + funcName
4120  					fd, ok = genericFuncDecls[key]
4121  					if ok {
4122  						pkgPath = gPkg
4123  						break
4124  					}
4125  				}
4126  			}
4127  		}
4128  		if !ok {
4129  			return nil
4130  		}
4131  	}
4132  	args := fb.buildArgs(argList)
4133  	typeArgs := inferTypeArgsFromFunc(fd, args)
4134  	return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
4135  }
4136  
4137  func (fb *ssaFuncBuilder) tryGenericPkgCall(pn *PkgName, funcName string, argList []Expr, hasDots bool) SSAValue {
4138  	imported := pn.Imported()
4139  	if imported == nil {
4140  		return nil
4141  	}
4142  	key := imported.Path() + "." + funcName
4143  	fd, ok := genericFuncDecls[key]
4144  	if !ok {
4145  		return nil
4146  	}
4147  	args := fb.buildArgs(argList)
4148  	typeArgs := inferTypeArgsFromFunc(fd, args)
4149  	return fb.monomorphizeAndCall(fd, funcName, typeArgs, args, fb.fn.Pkg, imported.Path(), hasDots)
4150  }
4151  
4152  func (fb *ssaFuncBuilder) tryGenericCallFromIndex(ie *IndexExpr, argList []Expr, hasDots bool) SSAValue {
4153  	switch x := ie.X.(type) {
4154  	case *Name:
4155  		pkgPath := fb.fn.Pkg.Pkg.Path()
4156  		key := pkgPath + "." + x.Value
4157  		fd, ok := genericFuncDecls[key]
4158  		if !ok {
4159  			if fb.srcScope != nil && genericPkgScopes != nil {
4160  				for gPkg, gScope := range genericPkgScopes {
4161  					if gScope == fb.srcScope {
4162  						key = gPkg + "." + x.Value
4163  						fd, ok = genericFuncDecls[key]
4164  						if ok {
4165  							pkgPath = gPkg
4166  							break
4167  						}
4168  					}
4169  				}
4170  			}
4171  			if !ok {
4172  				return nil
4173  			}
4174  		}
4175  		typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
4176  		args := fb.buildArgs(argList)
4177  		return fb.monomorphizeAndCall(fd, x.Value, typeArgs, args, fb.fn.Pkg, pkgPath, hasDots)
4178  	case *SelectorExpr:
4179  		if pkgName, ok2 := x.X.(*Name); ok2 {
4180  			obj := fb.lookupObject(pkgName.Value)
4181  			if pn, ok3 := obj.(*PkgName); ok3 && pn.Imported() != nil {
4182  				key := pn.Imported().Path() + "." + x.Sel.Value
4183  				fd, ok4 := genericFuncDecls[key]
4184  				if !ok4 {
4185  					return nil
4186  				}
4187  				typeArgs := fb.resolveExplicitTypeArgs(ie.Index, fd)
4188  				args := fb.buildArgs(argList)
4189  				return fb.monomorphizeAndCall(fd, x.Sel.Value, typeArgs, args, fb.fn.Pkg, pn.Imported().Path(), hasDots)
4190  			}
4191  		}
4192  	}
4193  	return nil
4194  }
4195  
4196  func (fb *ssaFuncBuilder) resolveExplicitTypeArgs(indexExpr Expr, fd *FuncDecl) []Type {
4197  	var typeExprs []Expr
4198  	if le, ok := indexExpr.(*ListExpr); ok {
4199  		typeExprs = le.ElemList
4200  	} else {
4201  		typeExprs = []Expr{indexExpr}
4202  	}
4203  	var result []Type
4204  	for _, te := range typeExprs {
4205  		t := fb.resolveTypeAST(te)
4206  		result = append(result, t)
4207  	}
4208  	if len(result) < len(fd.TParamList) {
4209  		typeMap := map[string]Type{}
4210  		for i, tp := range fd.TParamList {
4211  			if tp.Name != nil && i < len(result) && result[i] != nil {
4212  				typeMap[tp.Name.Value] = result[i]
4213  			}
4214  		}
4215  		inferFromConstraints(fd.TParamList, typeMap)
4216  		result = nil
4217  		for _, tp := range fd.TParamList {
4218  			if tp.Name != nil {
4219  				result = append(result, typeMap[tp.Name.Value])
4220  			}
4221  		}
4222  	}
4223  	return result
4224  }
4225