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