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