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