ssa_resolve.mx raw
1 package ssa
2
3 import (
4 "git.smesh.lol/moxie/pkg/token"
5 "git.smesh.lol/moxie/pkg/syntax"
6 "git.smesh.lol/moxie/pkg/types"
7 )
8
9 func (fb *ssaFuncBuilder) resolveMethodCallWithRecv(sel *syntax.SelectorExpr, recv SSAValue) (*SSAFunction, SSAValue) {
10 typ := recv.SSAType()
11 if typ == nil {
12 return nil, nil
13 }
14 isPtr := false
15 if p, ok := types.SafeUnderlying(typ).(*types.Pointer); ok {
16 typ = p.Elem()
17 isPtr = true
18 }
19 if _, ok := types.SafeUnderlying(typ).(*types.TCInterface); ok {
20 if named2, ok2 := typ.(*types.Named); !ok2 || named2.NumMethods() == 0 {
21 return nil, nil
22 }
23 }
24 // Handle Basic types (builtin stringers in runtime package)
25 if basic, ok2 := typ.(*types.Basic); ok2 {
26 typeName := basic.Name()
27 mangledName := typeName | "." | sel.Sel.Value
28 extSym := "runtime." | mangledName
29 for i := int32(0); i < basic.NumMethods(); i++ {
30 m := basic.Method(i)
31 if m.Name() == sel.Sel.Value {
32 fn := fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
33 fn.externalSymbol = extSym
34 return fn, recv
35 }
36 }
37 resolved := types.UntypedToTyped(basic)
38 if resolved == nil {
39 return nil, nil
40 }
41 switch rt := resolved.(type) {
42 case *types.Basic:
43 typeName = rt.Name()
44 mangledName = typeName | "." | sel.Sel.Value
45 extSym = "runtime." | mangledName
46 for i := int32(0); i < rt.NumMethods(); i++ {
47 m := rt.Method(i)
48 if m.Name() == sel.Sel.Value {
49 fn := fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
50 fn.externalSymbol = extSym
51 return fn, recv
52 }
53 }
54 return nil, nil
55 case *types.Named:
56 typ = rt
57 default:
58 return nil, nil
59 }
60 }
61 named, ok := typ.(*types.Named)
62 if !ok {
63 return nil, nil
64 }
65 typeName := ""
66 if named.Obj() != nil {
67 typeName = named.Obj().Name()
68 }
69 if typeName == "" {
70 return nil, nil
71 }
72 resolveNamed := named
73 if resolveNamed.NumMethods() == 0 {
74 cur := types.Type(resolveNamed)
75 for depth := 0; depth < 10; depth++ {
76 n, ok2 := cur.(*types.Named)
77 if !ok2 || n == nil { break }
78 if n.NumMethods() > 0 {
79 resolveNamed = n
80 if n.Obj() != nil && n.Obj().Name() != "" {
81 typeName = n.Obj().Name()
82 }
83 break
84 }
85 raw := n.RawUnderlying()
86 if raw == nil || raw == cur { break }
87 cur = raw
88 }
89 }
90 namedPkgPath := ""
91 if resolveNamed.Obj() != nil && resolveNamed.Obj().Pkg() != nil {
92 namedPkgPath = resolveNamed.Obj().Pkg().Path()
93 }
94 samePackage := namedPkgPath != "" && namedPkgPath == fb.fn.Pkg.Pkg.Path()
95 mangledName := typeName | "." | sel.Sel.Value
96 if !samePackage && namedPkgPath != "" {
97 mangledName = namedPkgPath | "." | typeName | "." | sel.Sel.Value
98 }
99 var fn *SSAFunction
100 if samePackage {
101 fn, _ = fb.fn.Pkg.Members[mangledName].(*SSAFunction)
102 }
103 if fn == nil {
104 for i := 0; i < resolveNamed.NumMethods(); i++ {
105 m := resolveNamed.Method(i)
106 if m.Name() == sel.Sel.Value {
107 fn = fb.fn.Pkg.ExternalFunc(mangledName, m.Signature())
108 if !samePackage && namedPkgPath != "" {
109 fn.externalSymbol = namedPkgPath | "." | typeName | "." | sel.Sel.Value
110 } else if resolveNamed.Obj() != nil && resolveNamed.Obj().Pkg() == nil {
111 fn.externalSymbol = "runtime." | mangledName
112 }
113 break
114 }
115 }
116 }
117 if fn != nil {
118 if fn.Signature != nil && fn.Signature.Recv() != nil {
119 recvParam := fn.Signature.Recv()
120 _, recvIsPtr := types.SafeUnderlying(recvParam.Type()).(*types.Pointer)
121 if recvIsPtr && !isPtr {
122 if nameExpr, ok2 := sel.X.(*syntax.Name); ok2 {
123 obj := fb.lookupObject(nameExpr.Value)
124 if obj != nil {
125 if alloc, ok3 := fb.vars[obj]; ok3 {
126 recv = alloc
127 }
128 }
129 } else if innerSel, ok2 := sel.X.(*syntax.SelectorExpr); ok2 {
130 addr := fb.buildSelectorAddr(innerSel)
131 if addr != nil {
132 recv = addr
133 }
134 }
135 }
136 }
137 return fn, recv
138 }
139 st, ok2 := types.SafeUnderlying(named).(*types.TCStruct)
140 if !ok2 {
141 return nil, nil
142 }
143 if !isPtr {
144 fixed := false
145 if innerSel, ok3 := sel.X.(*syntax.SelectorExpr); ok3 {
146 addr := fb.buildSelectorAddr(innerSel)
147 if addr != nil {
148 recv = addr
149 fixed = true
150 }
151 }
152 if !fixed {
153 if nameExpr, ok3 := sel.X.(*syntax.Name); ok3 {
154 obj := fb.lookupObject(nameExpr.Value)
155 if obj != nil {
156 if a, ok4 := fb.vars[obj]; ok4 {
157 recv = a
158 fixed = true
159 }
160 }
161 }
162 }
163 if !fixed {
164 alloc := &SSAAlloc{}
165 alloc.typ = types.NewPointer(recv.SSAType())
166 alloc.name = fb.nextName()
167 fb.emit(alloc)
168 storeOp := &SSAStore{Addr: alloc, Val: recv}
169 fb.emit(storeOp)
170 recv = alloc
171 }
172 }
173 for i := 0; i < st.NumFields(); i++ {
174 f := st.Field(i)
175 if !f.Anonymous() {
176 continue
177 }
178 embedType := f.Type()
179 embedNamed, ok3 := embedType.(*types.Named)
180 if !ok3 {
181 if p, ok4 := embedType.(*types.Pointer); ok4 {
182 embedNamed, ok3 = p.Elem().(*types.Named)
183 }
184 }
185 if !ok3 || embedNamed.Obj() == nil {
186 continue
187 }
188 embedName := embedNamed.Obj().Name()
189 embedSamePkg := embedNamed.Obj().Pkg() != nil && embedNamed.Obj().Pkg().Path() == fb.fn.Pkg.Pkg.Path()
190 embedMangledName := embedName | "." | sel.Sel.Value
191 if !embedSamePkg && embedNamed.Obj().Pkg() != nil {
192 embedMangledName = embedNamed.Obj().Pkg().Path() | "." | embedName | "." | sel.Sel.Value
193 }
194 var embedFn *SSAFunction
195 if embedSamePkg {
196 embedFn, _ = fb.fn.Pkg.Members[embedMangledName].(*SSAFunction)
197 }
198 if embedFn == nil {
199 for mi := int32(0); mi < int32(embedNamed.NumMethods()); mi++ {
200 m := embedNamed.Method(int32(mi))
201 if m.Name() == sel.Sel.Value {
202 embedFn = fb.fn.Pkg.ExternalFunc(embedMangledName, m.Signature())
203 if !embedSamePkg && embedNamed.Obj().Pkg() != nil {
204 embedFn.externalSymbol = embedNamed.Obj().Pkg().Path() | "." | embedName | "." | sel.Sel.Value
205 }
206 break
207 }
208 }
209 }
210 if embedFn != nil {
211 fieldAddr := &SSAFieldAddr{
212 X: recv,
213 Field: i,
214 }
215 fieldAddr.typ = types.NewPointer(embedType)
216 fieldAddr.name = fb.nextName()
217 fb.emit(fieldAddr)
218 var embedRecv SSAValue = fieldAddr
219 if _, isEmbedPtr := types.SafeUnderlying(embedType).(*types.Pointer); isEmbedPtr {
220 ld := &SSAUnOp{Op: OpMul, X: fieldAddr}
221 ld.typ = embedType
222 ld.name = fb.nextName()
223 fb.emit(ld)
224 embedRecv = ld
225 }
226 return embedFn, embedRecv
227 }
228 embedSt, ok5 := types.SafeUnderlying(embedNamed).(*types.TCStruct)
229 if !ok5 {
230 continue
231 }
232 for j := 0; j < embedSt.NumFields(); j++ {
233 f2 := embedSt.Field(j)
234 if !f2.Anonymous() {
235 continue
236 }
237 embed2Type := f2.Type()
238 embed2Named, ok6 := embed2Type.(*types.Named)
239 if !ok6 {
240 if p2, ok7 := embed2Type.(*types.Pointer); ok7 {
241 embed2Named, ok6 = p2.Elem().(*types.Named)
242 }
243 }
244 if !ok6 || embed2Named.Obj() == nil {
245 continue
246 }
247 embed2Name := embed2Named.Obj().Name()
248 embed2SamePkg := embed2Named.Obj().Pkg() != nil && embed2Named.Obj().Pkg().Path() == fb.fn.Pkg.Pkg.Path()
249 embed2Mangled := embed2Name | "." | sel.Sel.Value
250 if !embed2SamePkg && embed2Named.Obj().Pkg() != nil {
251 embed2Mangled = embed2Named.Obj().Pkg().Path() | "." | embed2Name | "." | sel.Sel.Value
252 }
253 var embed2Fn *SSAFunction
254 if embed2SamePkg {
255 embed2Fn, _ = fb.fn.Pkg.Members[embed2Mangled].(*SSAFunction)
256 }
257 if embed2Fn == nil {
258 for mi := int32(0); mi < int32(embed2Named.NumMethods()); mi++ {
259 m := embed2Named.Method(int32(mi))
260 if m.Name() == sel.Sel.Value {
261 embed2Fn = fb.fn.Pkg.ExternalFunc(embed2Mangled, m.Signature())
262 if !embed2SamePkg && embed2Named.Obj().Pkg() != nil {
263 embed2Fn.externalSymbol = embed2Named.Obj().Pkg().Path() | "." | embed2Name | "." | sel.Sel.Value
264 }
265 break
266 }
267 }
268 }
269 if embed2Fn == nil {
270 continue
271 }
272 fieldAddr1 := &SSAFieldAddr{X: recv, Field: i}
273 fieldAddr1.typ = types.NewPointer(embedType)
274 fieldAddr1.name = fb.nextName()
275 fb.emit(fieldAddr1)
276 var cur1 SSAValue = fieldAddr1
277 curEmbedType := embedType
278 if p5, ok8 := types.SafeUnderlying(embedType).(*types.Pointer); ok8 {
279 ld := &SSAUnOp{Op: OpMul, X: fieldAddr1}
280 ld.typ = embedType
281 ld.name = fb.nextName()
282 fb.emit(ld)
283 cur1 = ld
284 curEmbedType = p5.Elem()
285 }
286 _ = curEmbedType
287 fieldAddr2 := &SSAFieldAddr{X: cur1, Field: j}
288 fieldAddr2.typ = types.NewPointer(embed2Type)
289 fieldAddr2.name = fb.nextName()
290 fb.emit(fieldAddr2)
291 var embedRecv2 SSAValue = fieldAddr2
292 if _, isEmbedPtr2 := types.SafeUnderlying(embed2Type).(*types.Pointer); isEmbedPtr2 {
293 ld2 := &SSAUnOp{Op: OpMul, X: fieldAddr2}
294 ld2.typ = embed2Type
295 ld2.name = fb.nextName()
296 fb.emit(ld2)
297 embedRecv2 = ld2
298 }
299 return embed2Fn, embedRecv2
300 }
301 }
302 return nil, nil
303 }
304
305 func (fb *ssaFuncBuilder) buildIfaceMethodCall(sel *syntax.SelectorExpr, recv SSAValue, argExprs []syntax.Expr) (s SSAValue) {
306 typ := recv.SSAType()
307 if p, ok := types.SafeUnderlying(typ).(*types.Pointer); ok {
308 typ = p.Elem()
309 }
310 iface, ok := types.SafeUnderlying(typ).(*types.TCInterface)
311 if !ok {
312 return nil
313 }
314 var methodSig *types.Signature
315 for i := 0; i < iface.NumMethods(); i++ {
316 m := iface.Method(i)
317 if m == nil {
318 continue
319 }
320 if m.Name() == sel.Sel.Value {
321 methodSig = m.Sig()
322 break
323 }
324 }
325 var retType types.Type
326 if methodSig != nil && methodSig.Results() != nil {
327 if methodSig.Results().Len() == 1 {
328 retType = methodSig.Results().At(0).Type()
329 } else if methodSig.Results().Len() > 1 {
330 retType = methodSig.Results()
331 }
332 }
333 args := fb.buildArgs(argExprs)
334 inv := &SSAInvoke{
335 X: recv,
336 MethodName: sel.Sel.Value,
337 IfaceType: iface,
338 Args: args,
339 }
340 inv.typ = retType
341 inv.name = fb.nextName()
342 fb.emit(inv)
343 if retType == nil {
344 return nil
345 }
346 return inv
347 }
348
349 func (fb *ssaFuncBuilder) resolveType(e syntax.Expr) (t types.Type) {
350 if fb.info != nil {
351 if tv, ok := fb.info.Types[e]; ok && tv.Type != nil {
352 return tv.Type
353 }
354 }
355 t = fb.resolveTypeAST(e)
356 return t
357 }
358
359 func (fb *ssaFuncBuilder) resolveTypeAST(e syntax.Expr) (t types.Type) {
360 if e == nil {
361 return nil
362 }
363 switch e := e.(type) {
364 case *syntax.Name:
365 if fb.typeSubst != nil {
366 if t, ok := fb.typeSubst[e.Value]; ok {
367 return t
368 }
369 }
370 if t, ok := fb.localTypes[e.Value]; ok {
371 return t
372 }
373 obj := fb.lookupObject(e.Value)
374 if tn, ok := obj.(*types.TypeName); ok {
375 if tp, ok2 := tn.Type().(*types.TypeParam); ok2 && fb.typeSubst != nil {
376 if t, ok3 := fb.typeSubst[tp.String()]; ok3 {
377 return t
378 }
379 }
380 return tn.Type()
381 }
382 case *syntax.Operation:
383 if e.Y == nil && e.Op == token.Mul {
384 base := fb.resolveTypeAST(e.X)
385 if base != nil {
386 return types.NewPointer(base)
387 }
388 }
389 case *syntax.SliceType:
390 elem := fb.resolveTypeAST(e.Elem)
391 if elem != nil {
392 if b, ok := elem.(*types.Basic); ok && b.Kind() == types.Uint8 {
393 return types.Typ[types.TCString]
394 }
395 return types.NewSlice(elem)
396 }
397 case *syntax.ArrayType:
398 elem := fb.resolveTypeAST(e.Elem)
399 if elem != nil {
400 n := int64(-1)
401 if lit, ok := e.Len.(*syntax.BasicLit); ok {
402 n = ssaParseInt64(lit.Value)
403 } else if e.Len != nil {
404 cv := tcEvalConstExpr(e.Len, fb.fn.Pkg.Pkg.Scope(), -1)
405 if cv == nil && fb.localConsts != nil {
406 cv = fb.evalLocalConstExpr(e.Len)
407 }
408 if ci, ok := cv.(*types.ConstInt); ok {
409 n = ci.v
410 }
411 }
412 return types.NewArray(elem, n)
413 }
414 case *syntax.MapType:
415 key := fb.resolveTypeAST(e.Key)
416 val := fb.resolveTypeAST(e.Value)
417 if key != nil && val != nil {
418 return types.NewTCMap(key, val)
419 }
420 case *syntax.StructType:
421 return fb.resolveStructTypeAST(e)
422 case *syntax.ChanType:
423 elem := fb.resolveTypeAST(e.Elem)
424 if elem != nil {
425 dir := types.TCSendRecv
426 if e.Dir == syntax.SendOnly {
427 dir = types.TCSendOnly
428 } else if e.Dir == syntax.RecvOnly {
429 dir = types.TCRecvOnly
430 }
431 return types.NewTCChan(dir, elem)
432 }
433 case *syntax.InterfaceType:
434 return fb.resolveInterfaceTypeAST(e)
435 case *syntax.FuncType:
436 return fb.resolveFuncTypeAST(e)
437 case *syntax.SelectorExpr:
438 if x, ok := e.X.(*syntax.Name); ok {
439 obj := fb.lookupObject(x.Value)
440 if pn, ok2 := obj.(*types.PkgName); ok2 && pn.Imported() != nil {
441 sel := pn.Imported().Scope().Lookup(e.Sel.Value)
442 if tn, ok3 := sel.(*types.TypeName); ok3 {
443 return tn.Type()
444 }
445 }
446 }
447 case *syntax.ParenExpr:
448 return fb.resolveTypeAST(e.X)
449 }
450 return nil
451 }
452
453 func (fb *ssaFuncBuilder) resolveInterfaceTypeAST(e *syntax.InterfaceType) (t *types.TCInterface) {
454 var methods []*types.IfaceMethod
455 for _, f := range e.MethodList {
456 if f.Name == nil {
457 continue
458 }
459 ft, ok := f.Type.(*syntax.FuncType)
460 if !ok {
461 continue
462 }
463 sig := fb.resolveFuncTypeAST(ft)
464 if sig != nil {
465 methods = append(methods, types.NewTCIfaceMethod(f.Name.Value, sig))
466 }
467 }
468 iface := types.NewTCInterface(methods, nil)
469 iface.Complete()
470 return iface
471 }
472
473 func (fb *ssaFuncBuilder) resolveStructTypeAST(e *syntax.StructType) (t *types.TCStruct) {
474 var fields []*types.TCVar
475 var tags []string
476 for i, f := range e.FieldList {
477 typ := fb.resolveTypeAST(f.Type)
478 if typ == nil {
479 return nil
480 }
481 name := ""
482 if f.Name != nil {
483 name = f.Name.Value
484 }
485 fields = append(fields, types.NewTCField(fb.fn.Pkg.Pkg, name, typ, f.Name == nil))
486 tag := ""
487 if i < len(e.TagList) && e.TagList[i] != nil {
488 tag = e.TagList[i].Value
489 }
490 tags = append(tags, tag)
491 }
492 return types.NewTCStruct(fields, tags)
493 }
494
495 func (fb *ssaFuncBuilder) resolveFuncTypeAST(ft *syntax.FuncType) (s *types.Signature) {
496 if ft == nil {
497 return nil
498 }
499 var params []*types.TCVar
500 for _, p := range ft.ParamList {
501 typ := fb.resolveTypeAST(p.Type)
502 pname := ""
503 if p.Name != nil {
504 pname = p.Name.Value
505 }
506 params = append(params, types.NewTCVar(nil, pname, typ))
507 }
508 var results []*types.TCVar
509 for _, r := range ft.ResultList {
510 typ := fb.resolveTypeAST(r.Type)
511 rname := ""
512 if r.Name != nil {
513 rname = r.Name.Value
514 }
515 results = append(results, types.NewTCVar(nil, rname, typ))
516 }
517 var pTuple, rTuple *types.Tuple
518 if len(params) > 0 {
519 pTuple = types.NewTuple(params...)
520 }
521 if len(results) > 0 {
522 rTuple = types.NewTuple(results...)
523 }
524 return types.NewSignature(nil, pTuple, rTuple, false)
525 }
526
527 func (fb *ssaFuncBuilder) fieldIndex(t types.Type, name string) (n int32) {
528 if t == nil {
529 return -1
530 }
531 if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
532 t = pt.Elem()
533 }
534 if st, ok := types.SafeUnderlying(t).(*types.TCStruct); ok {
535 for i := 0; i < st.NumFields(); i++ {
536 if st.Field(i).Name() == name {
537 return i
538 }
539 }
540 }
541 return -1
542 }
543
544 func (fb *ssaFuncBuilder) findEmbeddedField(t types.Type, name string) (embedIdx int32, innerIdx int32) {
545 path := fb.findEmbeddedFieldPath(t, name)
546 if len(path) < 2 {
547 return -1, -1
548 }
549 return path[0], path[1]
550 }
551
552 func (fb *ssaFuncBuilder) findEmbeddedFieldPath(t types.Type, name string) (ss []int32) {
553 if t == nil {
554 return nil
555 }
556 if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
557 t = pt.Elem()
558 }
559 st, ok := types.SafeUnderlying(t).(*types.TCStruct)
560 if !ok {
561 return nil
562 }
563 for i := 0; i < st.NumFields(); i++ {
564 f := st.Field(i)
565 if !f.Anonymous() {
566 continue
567 }
568 embedType := f.Type()
569 if pt, ok := types.SafeUnderlying(embedType).(*types.Pointer); ok {
570 embedType = pt.Elem()
571 }
572 inner := fb.fieldIndex(embedType, name)
573 if inner >= 0 {
574 return []int32{i, inner}
575 }
576 sub := fb.findEmbeddedFieldPath(embedType, name)
577 if len(sub) > 0 {
578 return append([]int32{i}, sub...)
579 }
580 }
581 return nil
582 }
583
584 func (fb *ssaFuncBuilder) fieldType(t Type, idx int32) (tv types.Type) {
585 if t == nil {
586 return nil
587 }
588 if pt, ok := types.SafeUnderlying(t).(*types.Pointer); ok {
589 t = pt.Elem()
590 }
591 if st, ok := types.SafeUnderlying(t).(*types.TCStruct); ok {
592 if idx >= 0 && idx < st.NumFields() {
593 return st.Field(idx).Type()
594 }
595 }
596 return nil
597 }
598
599 func ssaExtractConst(v SSAValue) (s *SSAConst) {
600 if c, ok := v.(*SSAConst); ok {
601 return c
602 }
603 if conv, ok := v.(*SSAConvert); ok {
604 if c, ok2 := conv.X.(*SSAConst); ok2 {
605 return &SSAConst{typ: conv.SSAType(), val: c.val}
606 }
607 }
608 return nil
609 }
610
611 func ssaExprNames(e syntax.Expr) (ns []*syntax.Name) {
612 if e == nil {
613 return nil
614 }
615 if n, ok := e.(*syntax.Name); ok {
616 return []*syntax.Name{n}
617 }
618 if l, ok := e.(*syntax.ListExpr); ok {
619 var names []*syntax.Name
620 for _, el := range l.ElemList {
621 if n, ok := el.(*syntax.Name); ok {
622 names = append(names, n)
623 }
624 }
625 return names
626 }
627 return nil
628 }
629
630 func localizeConstVal(val ConstVal, typ types.Type) (c types.ConstVal) {
631 if val == nil {
632 return nil
633 }
634 return val
635 }
636