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