tc_resolve.mx raw
1 package types
2
3 import (
4 "git.smesh.lol/moxie/pkg/syntax"
5 "git.smesh.lol/moxie/pkg/token"
6 )
7
8 // resolveTypeExpr resolves a type expression to a Type.
9 // This is the core of the type system - translating AST type nodes to Type values.
10 func (c *Checker) resolveTypeExpr(e syntax.Expr) (t Type) {
11 if e == nil {
12 return nil
13 }
14 switch ev := e.(type) {
15 case *syntax.Name:
16 return c.resolveTypeName(ev)
17 case *syntax.SelectorExpr:
18 return c.resolveQualifiedTypeName(ev)
19 case *syntax.Operation:
20 // *T (pointer)
21 if ev.Y == nil && ev.Op == token.Mul {
22 base := c.resolveTypeExpr(ev.X)
23 if base == nil {
24 return nil
25 }
26 return NewPointer(base)
27 }
28 // ~T (approximation element in type constraints) - treat as T for B1
29 if ev.Y == nil && ev.Op == token.Tilde {
30 return c.resolveTypeExpr(ev.X)
31 }
32 // T | U (union element in type constraints) - return first operand for B1
33 if ev.Y != nil && ev.Op == token.Or {
34 c.resolveTypeExpr(ev.Y) // resolve both sides to catch undefined errors
35 return c.resolveTypeExpr(ev.X)
36 }
37 case *syntax.SliceType:
38 elem := c.resolveTypeExpr(ev.Elem)
39 if elem == nil {
40 return nil
41 }
42 if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
43 return Typ[TCString]
44 }
45 return NewSlice(elem)
46 case *syntax.ArrayType:
47 elem := c.resolveTypeExpr(ev.Elem)
48 if elem == nil {
49 return nil
50 }
51 if ev.Len == nil {
52 return NewArray(elem, -1)
53 }
54 n := c.evalArrayLen(ev.Len)
55 return NewArray(elem, n)
56 case *syntax.MapType:
57 key := c.resolveTypeExpr(ev.Key)
58 val := c.resolveTypeExpr(ev.Value)
59 if key == nil || val == nil {
60 return nil
61 }
62 return NewTCMap(key, val)
63 case *syntax.ChanType:
64 elem := c.resolveTypeExpr(ev.Elem)
65 if elem == nil {
66 return nil
67 }
68 var dir TCChanDir
69 switch ev.Dir {
70 case syntax.SendOnly:
71 dir = TCSendOnly
72 case syntax.RecvOnly:
73 dir = TCRecvOnly
74 default:
75 dir = TCSendRecv
76 }
77 return NewTCChan(dir, elem)
78 case *syntax.StructType:
79 return c.resolveStructType(ev)
80 case *syntax.InterfaceType:
81 return c.resolveInterfaceType(ev)
82 case *syntax.FuncType:
83 return c.resolveFuncType(ev, nil)
84 case *syntax.IndexExpr:
85 // generic instantiation T[A, B, ...]
86 return c.resolveGenericInst(ev)
87 case *syntax.DotsType:
88 elem := c.resolveTypeExpr(ev.Elem)
89 if elem == nil {
90 return nil
91 }
92 if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
93 return Typ[TCString]
94 }
95 return NewSlice(elem)
96 }
97 c.errorf(e.Pos(), "cannot resolve type expression")
98 return nil
99 }
100
101 func (c *Checker) resolveTypeName(e *syntax.Name) (t Type) {
102 _, obj := c.lookupType(e.Value)
103 if obj == nil {
104 c.errorf(e.Pos(), "undefined: " | e.Value)
105 return nil
106 }
107 if tn, ok := obj.(*TypeName); ok {
108 if c.info != nil {
109 c.info.Uses[e] = tn
110 }
111 return tn.Typ
112 }
113 c.errorf(e.Pos(), e.Value | " is not a type")
114 return nil
115 }
116
117 func (c *Checker) resolveQualifiedTypeName(e *syntax.SelectorExpr) (t Type) {
118 pkgName, ok := e.X.(*syntax.Name)
119 if !ok {
120 c.errorf(e.Pos(), "invalid type expression")
121 return nil
122 }
123 // lookupType walks localScope -> fileScope -> pkg scope so the file's
124 // own import binding wins over a same-named import in another file.
125 _, obj := c.lookupType(pkgName.Value)
126 if obj == nil {
127 c.errorf(e.Pos(), "undefined: " | pkgName.Value)
128 return nil
129 }
130 pkgObj, ok2 := obj.(*PkgName)
131 if !ok2 {
132 c.errorf(e.Pos(), pkgName.Value | " is not a package")
133 return nil
134 }
135 imported := pkgObj.Imported
136 if imported == nil {
137 return nil
138 }
139 typeObj := imported.Scope.Lookup(e.Sel.Value)
140 if typeObj == nil {
141 c.errorf(e.Sel.Pos(), "undefined: " | pkgName.Value | "." | e.Sel.Value)
142 return nil
143 }
144 if tn, ok3 := typeObj.(*TypeName); ok3 {
145 return tn.Typ
146 }
147 c.errorf(e.Sel.Pos(), pkgName.Value | "." | e.Sel.Value | " is not a type")
148 return nil
149 }
150
151 func (c *Checker) resolveStructType(e *syntax.StructType) (t *TCStruct) {
152 var fields []*TCVar
153 var tags []string
154 for i, f := range e.FieldList {
155 typ := c.resolveTypeExpr(f.Type)
156 if f.Name != nil {
157 push(fields, NewTCField(c.pkg, f.Name.Value, typ, false))
158 } else {
159 // anonymous/embedded
160 name := TypeBaseName(typ)
161 push(fields, NewTCField(c.pkg, name, typ, true))
162 }
163 tag := ""
164 if i < len(e.TagList) && e.TagList[i] != nil {
165 tag = e.TagList[i].Value
166 }
167 push(tags, tag)
168 }
169 return NewTCStruct(fields, tags)
170 }
171
172 func (c *Checker) resolveInterfaceType(e *syntax.InterfaceType) (t *TCInterface) {
173 var methods []*IfaceMethod
174 var embeds []Type
175 for _, f := range e.MethodList {
176 if f.Name == nil {
177 // embedded type
178 typ := c.resolveTypeExpr(f.Type)
179 if typ != nil {
180 push(embeds, typ)
181 }
182 continue
183 }
184 ft, ok := f.Type.(*syntax.FuncType)
185 if !ok {
186 continue
187 }
188 sig := c.resolveFuncType(ft, nil)
189 if sig != nil {
190 push(methods, &IfaceMethod{Name: f.Name.Value, Sig: sig})
191 }
192 }
193 iface := NewTCInterface(methods, embeds)
194 iface.Complete()
195 return iface
196 }
197
198 // resolveFuncType converts a FuncType AST node to a Signature.
199 // recv is optional (non-nil only for method declarations).
200 func (c *Checker) resolveFuncType(ft *syntax.FuncType, recv *syntax.Field) (s *Signature) {
201 if ft == nil {
202 return nil
203 }
204 var recvVar *TCVar
205 if recv != nil {
206 recvTyp := c.resolveTypeExpr(recv.Type)
207 recvName := ""
208 if recv.Name != nil {
209 recvName = recv.Name.Value
210 }
211 recvVar = NewTCVar(c.pkg, recvName, recvTyp)
212 }
213
214 params := c.resolveFieldList(ft.ParamList)
215 results := c.resolveFieldList(ft.ResultList)
216
217 variadic := false
218 if len(ft.ParamList) > 0 {
219 last := ft.ParamList[len(ft.ParamList)-1]
220 if _, ok := last.Type.(*syntax.DotsType); ok {
221 variadic = true
222 // unwrap: the slice type is already resolved in resolveFieldList
223 }
224 }
225
226 return NewSignature(recvVar, params, results, variadic)
227 }
228
229 func (c *Checker) resolveFieldList(fields []*syntax.Field) (t *Tuple) {
230 if len(fields) == 0 {
231 return nil
232 }
233 var vars []*TCVar
234 for _, f := range fields {
235 typ := c.resolveTypeExpr(f.Type)
236 name := ""
237 if f.Name != nil {
238 name = f.Name.Value
239 }
240 push(vars, NewTCVar(c.pkg, name, typ))
241 }
242 return NewTuple(vars...)
243 }
244
245 func (c *Checker) resolveGenericInst(e *syntax.IndexExpr) (t Type) {
246 // TODO: full generic instantiation
247 return c.resolveTypeExpr(e.X)
248 }
249
250 // TypeBaseName returns the name of the base type for an anonymous field.
251 func TypeBaseName(t Type) (s string) {
252 if t == nil {
253 return ""
254 }
255 switch tt := t.(type) {
256 case *Named:
257 if tt.Obj != nil {
258 return tt.Obj.Name
259 }
260 case *Pointer:
261 return TypeBaseName(tt.Base)
262 case *Basic:
263 return tt.Name
264 }
265 return ""
266 }
267