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