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