tc_types.mx raw
1 // Package typecheck implements a Moxie-native type checker that consumes
2 // syntax.File AST nodes directly. It replaces go/types in the compiler
3 // pipeline once B3 (backend rewrite) is complete.
4 //
5 // Type system differences from Go:
6 // - string and []byte are the same type (Moxie text unification)
7 // - int32 = int32, uint32 = uint32 on all targets
8 // - no complex64/complex128
9 // - no goroutines (go keyword is a compile error)
10 // - spawn is a builtin with Codec constraints (not a type-level concept)
11 package main
12
13 import (
14 "bytes"
15 "fmt"
16 )
17
18 // Type is already defined in nodes.mx (syntax.Type interface).
19
20 // ----------------------------------------------------------------------------
21 // BasicKind
22
23 type BasicKind int32
24
25 const (
26 Invalid BasicKind = iota
27
28 // boolean
29 Bool
30
31 // integer
32 Int8
33 Int16
34 Int32
35 Int64
36 Uint8
37 Uint16
38 Uint32
39 Uint64
40
41 // float
42 Float32
43 Float64
44
45 // text - string and []byte are the same underlying kind in Moxie
46 TCString
47
48 // unsafe
49 UnsafePointer
50
51 // untyped constants
52 UntypedBool
53 UntypedInt
54 UntypedRune
55 UntypedFloat
56 UntypedString
57 UntypedNil
58 )
59
60 // BasicInfo is a bitmask of type properties.
61 type BasicInfo uint32
62
63 const (
64 IsBoolean BasicInfo = 1 << iota
65 IsInteger // includes unsigned
66 IsUnsigned // only for unsigned integer kinds
67 IsFloat
68 IsString
69 IsUntyped
70 IsOrdered // ordered by < (integers, floats, strings)
71 IsNumeric // integers + floats
72 )
73
74 // Basic is an elementary type (bool, int32, string, etc.).
75 type Basic struct {
76 kind BasicKind
77 info BasicInfo
78 name string
79 }
80
81 func (t *Basic) Kind() BasicKind { return t.kind }
82 func (t *Basic) Info() BasicInfo { return t.info }
83 func (t *Basic) Name() string { return t.name }
84 func (t *Basic) Underlying() Type { return t }
85 func (t *Basic) String() string { return t.name }
86
87 // ----------------------------------------------------------------------------
88 // Array
89
90 type Array struct {
91 len int32
92 elem Type
93 }
94
95 func NewArray(elem Type, n int32) *Array { return &Array{len: n, elem: elem} }
96 func (t *Array) Len() int32 { return t.len }
97 func (t *Array) Elem() Type { return t.elem }
98 func (t *Array) Underlying() Type { return t }
99 func (t *Array) String() string { return fmt.Sprintf("[%d]%s", t.len, t.elem) }
100
101 // ----------------------------------------------------------------------------
102 // Slice
103
104 type Slice struct{ elem Type }
105
106 func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
107 func (t *Slice) Elem() Type { return t.elem }
108 func (t *Slice) Underlying() Type { return t }
109 func (t *Slice) String() string { return "[]" | t.elem.String() }
110
111 // ----------------------------------------------------------------------------
112 // Pointer
113
114 type Pointer struct{ base Type }
115
116 func NewPointer(base Type) *Pointer { return &Pointer{base: base} }
117 func (t *Pointer) Elem() Type { return t.base }
118 func (t *Pointer) Underlying() Type { return t }
119 func (t *Pointer) String() string { return "*" | t.base.String() }
120
121 // ----------------------------------------------------------------------------
122 // Map
123
124 type TCMap struct{ key, elem Type }
125
126 func NewTCMap(key, elem Type) *TCMap { return &TCMap{key: key, elem: elem} }
127 func (t *TCMap) Key() Type { return t.key }
128 func (t *TCMap) Elem() Type { return t.elem }
129 func (t *TCMap) Underlying() Type { return t }
130 func (t *TCMap) String() string { return fmt.Sprintf("map[%s]%s", t.key, t.elem) }
131
132 // ----------------------------------------------------------------------------
133 // Chan
134
135 type TCChanDir int32
136
137 const (
138 TCSendRecv TCChanDir = iota
139 TCSendOnly
140 TCRecvOnly
141 )
142
143 type TCChan struct {
144 dir TCChanDir
145 elem Type
146 }
147
148 func NewTCChan(dir TCChanDir, elem Type) *TCChan { return &TCChan{dir: dir, elem: elem} }
149 func (t *TCChan) Dir() TCChanDir { return t.dir }
150 func (t *TCChan) Elem() Type { return t.elem }
151 func (t *TCChan) Underlying() Type { return t }
152 func (t *TCChan) String() string {
153 switch t.dir {
154 case TCSendOnly:
155 return "chan<- " | t.elem.String()
156 case TCRecvOnly:
157 return "<-chan " | t.elem.String()
158 }
159 return "chan " | t.elem.String()
160 }
161
162 // ----------------------------------------------------------------------------
163 // Var (a field or variable, used in Struct/Signature/Tuple)
164
165 type TCVar struct {
166 pkg *TCPackage
167 name string
168 typ Type
169 anonymous bool // embedded field (no explicit name)
170 used bool
171 pos interface{} // Pos - stored as interface to avoid import cycle
172 initVal ConstVal
173 }
174
175 func NewTCVar(pkg *TCPackage, name string, typ Type) *TCVar {
176 return &TCVar{pkg: pkg, name: name, typ: typ}
177 }
178 func NewTCField(pkg *TCPackage, name string, typ Type, anonymous bool) *TCVar {
179 return &TCVar{pkg: pkg, name: name, typ: typ, anonymous: anonymous}
180 }
181 func (v *TCVar) Name() string { return v.name }
182 func (v *TCVar) Type() Type { return v.typ }
183 func (v *TCVar) Anonymous() bool { return v.anonymous }
184 func (v *TCVar) Pkg() *TCPackage { return v.pkg }
185 func (v *TCVar) Exported() bool { return len(v.name) > 0 && v.name[0] >= 'A' && v.name[0] <= 'Z' }
186 func (v *TCVar) objectTag() {}
187 func (v *TCVar) String() string { return v.name }
188
189 // ----------------------------------------------------------------------------
190 // Struct
191
192 type TCStruct struct {
193 fields []*TCVar
194 tags []string
195 }
196
197 func NewTCStruct(fields []*TCVar, tags []string) *TCStruct {
198 return &TCStruct{fields: fields, tags: tags}
199 }
200 func (t *TCStruct) NumFields() int32 { return len(t.fields) }
201 func (t *TCStruct) Field(i int32) *TCVar { return t.fields[i] }
202 func (t *TCStruct) Tag(i int32) string {
203 if i < len(t.tags) {
204 return t.tags[i]
205 }
206 return ""
207 }
208 func (t *TCStruct) Underlying() Type { return t }
209 func (t *TCStruct) String() string {
210 var sb bytes.Buffer
211 sb.WriteString("struct{")
212 for i, f := range t.fields {
213 if i > 0 {
214 sb.WriteString("; ")
215 }
216 if !f.anonymous {
217 sb.WriteString(f.name)
218 sb.WriteByte(' ')
219 }
220 sb.WriteString(f.typ.String())
221 if tag := t.Tag(i); tag != "" {
222 fmt.Fprintf(&sb, " %q", tag)
223 }
224 }
225 sb.WriteByte('}')
226 return sb.String()
227 }
228
229 // ----------------------------------------------------------------------------
230 // Tuple (multi-return, parameter list)
231
232 type Tuple struct{ vars []*TCVar }
233
234 func NewTuple(vars ...*TCVar) *Tuple { return &Tuple{vars: vars} }
235 func (t *Tuple) Len() int32 { return len(t.vars) }
236 func (t *Tuple) At(i int32) *TCVar { return t.vars[i] }
237 func (t *Tuple) Underlying() Type { return t }
238 func (t *Tuple) String() string {
239 if t == nil || len(t.vars) == 0 {
240 return "()"
241 }
242 var sb bytes.Buffer
243 sb.WriteByte('(')
244 for i, v := range t.vars {
245 if i > 0 {
246 sb.WriteString(", ")
247 }
248 sb.WriteString(v.typ.String())
249 }
250 sb.WriteByte(')')
251 return sb.String()
252 }
253
254 // ----------------------------------------------------------------------------
255 // Signature (function type)
256
257 type Signature struct {
258 recv *TCVar // nil for plain functions
259 params *Tuple
260 results *Tuple
261 variadic bool
262 }
263
264 func NewSignature(recv *TCVar, params, results *Tuple, variadic bool) *Signature {
265 return &Signature{recv: recv, params: params, results: results, variadic: variadic}
266 }
267 func (t *Signature) Recv() *TCVar { return t.recv }
268 func (t *Signature) Params() *Tuple { return t.params }
269 func (t *Signature) Results() *Tuple { return t.results }
270 func (t *Signature) Variadic() bool { return t.variadic }
271 func (t *Signature) Underlying() Type { return t }
272 func (t *Signature) String() string {
273 var sb bytes.Buffer
274 sb.WriteString("func")
275 if t.params != nil {
276 writeParams(&sb, t.params, t.variadic)
277 } else {
278 sb.WriteString("()")
279 }
280 if t.results != nil && t.results.Len() > 0 {
281 sb.WriteByte(' ')
282 if t.results.Len() == 1 && t.results.At(0).name == "" {
283 sb.WriteString(t.results.At(0).typ.String())
284 } else {
285 writeParams(&sb, t.results, false)
286 }
287 }
288 return sb.String()
289 }
290
291 func writeParams(sb *bytes.Buffer, t *Tuple, variadic bool) {
292 sb.WriteByte('(')
293 for i, v := range t.vars {
294 if i > 0 {
295 sb.WriteString(", ")
296 }
297 if v.name != "" {
298 sb.WriteString(v.name)
299 sb.WriteByte(' ')
300 }
301 if variadic && i == len(t.vars)-1 {
302 if sl, ok := v.typ.(*Slice); ok {
303 sb.WriteString("...")
304 sb.WriteString(sl.elem.String())
305 continue
306 }
307 }
308 sb.WriteString(v.typ.String())
309 }
310 sb.WriteByte(')')
311 }
312
313 // ----------------------------------------------------------------------------
314 // Interface
315
316 // IfaceMethod holds a method signature for an interface.
317 type IfaceMethod struct {
318 name string
319 sig *Signature
320 }
321
322 func (m *IfaceMethod) Name() string { return m.name }
323 func (m *IfaceMethod) Sig() *Signature { return m.sig }
324
325 // IfaceMethod constructor used by the bridge package.
326 func NewTCIfaceMethod(name string, sig *Signature) *IfaceMethod {
327 return &IfaceMethod{name: name, sig: sig}
328 }
329
330 type TCInterface struct {
331 methods []*IfaceMethod
332 embeds []Type
333 complete bool
334 allMethods []*IfaceMethod
335 }
336
337 func NewTCInterface(methods []*IfaceMethod, embeds []Type) *TCInterface {
338 return &TCInterface{methods: methods, embeds: embeds}
339 }
340 func (t *TCInterface) NumMethods() int32 { return len(t.allMethods) }
341 func (t *TCInterface) Method(i int32) *IfaceMethod { return t.allMethods[i] }
342 func (t *TCInterface) NumExplicitMethods() int32 { return len(t.methods) }
343 func (t *TCInterface) ExplicitMethod(i int32) *IfaceMethod { return t.methods[i] }
344 func (t *TCInterface) NumEmbeddeds() int32 { return len(t.embeds) }
345 func (t *TCInterface) EmbeddedType(i int32) Type { return t.embeds[i] }
346 func (t *TCInterface) IsEmpty() bool { return len(t.allMethods) == 0 }
347 func (t *TCInterface) Underlying() Type { return t }
348 func (t *TCInterface) String() string {
349 if t.IsEmpty() {
350 return "interface{}"
351 }
352 var sb bytes.Buffer
353 sb.WriteString("interface{")
354 for i, m := range t.allMethods {
355 if i > 0 {
356 sb.WriteString("; ")
357 }
358 sb.WriteString(m.name)
359 // write sig without "func" prefix
360 sig := m.sig
361 if sig.params != nil {
362 writeParams(&sb, sig.params, sig.variadic)
363 } else {
364 sb.WriteString("()")
365 }
366 if sig.results != nil && sig.results.Len() > 0 {
367 sb.WriteByte(' ')
368 if sig.results.Len() == 1 {
369 sb.WriteString(sig.results.At(0).typ.String())
370 } else {
371 writeParams(&sb, sig.results, false)
372 }
373 }
374 }
375 sb.WriteByte('}')
376 return sb.String()
377 }
378
379 // complete fills allMethods from methods + embeds (called once after all types are resolved).
380 func (t *TCInterface) Complete() {
381 if t.complete {
382 return
383 }
384 seen := map[string]bool{}
385 t.allMethods = append(t.allMethods, t.methods...)
386 for _, m := range t.methods {
387 seen[m.name] = true
388 }
389 for _, embed := range t.embeds {
390 if embed == nil {
391 continue
392 }
393 u := safeUnderlying(embed)
394 if u == nil {
395 continue
396 }
397 if iface, ok := u.(*TCInterface); ok {
398 iface.Complete()
399 for _, m := range iface.allMethods {
400 if !seen[m.name] {
401 t.allMethods = append(t.allMethods, m)
402 seen[m.name] = true
403 }
404 }
405 }
406 }
407 t.complete = true
408 }
409
410 // ----------------------------------------------------------------------------
411 // TypeParam (generics)
412
413 type TypeParam struct {
414 id int32
415 obj *TypeName
416 constraint Type
417 }
418
419 func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
420 return &TypeParam{obj: obj, constraint: constraint}
421 }
422 func (t *TypeParam) Obj() *TypeName { return t.obj }
423 func (t *TypeParam) Constraint() Type { return t.constraint }
424 func (t *TypeParam) Underlying() Type { return t }
425 func (t *TypeParam) String() string {
426 if t.obj != nil {
427 return t.obj.name
428 }
429 return fmt.Sprintf("T%d", t.id)
430 }
431
432 // ----------------------------------------------------------------------------
433 // Named (named types: type Foo struct{...})
434
435 type Named struct {
436 obj *TypeName // the type name declaration
437 underlying Type // the underlying type
438 methods []*TCFunc // methods with this type as receiver
439 tparams []*TypeParam
440 targs []Type // set when instantiated
441 }
442
443 func NewNamed(obj *TypeName, underlying Type) *Named {
444 n := &Named{obj: obj, underlying: underlying}
445 if obj != nil {
446 obj.typ = n
447 }
448 return n
449 }
450 func (t *Named) Obj() *TypeName { return t.obj }
451 func (t *Named) NumMethods() int32 { return len(t.methods) }
452 func (t *Named) Method(i int32) *TCFunc { return t.methods[i] }
453 func (t *Named) AddMethod(m *TCFunc) { t.methods = append(t.methods, m) }
454 func (t *Named) TypeParams() []*TypeParam { return t.tparams }
455 func (t *Named) TypeArgs() []Type { return t.targs }
456 func (t *Named) Underlying() Type {
457 if t == nil {
458 return nil
459 }
460 if t.underlying != nil {
461 return t.underlying.Underlying()
462 }
463 return t
464 }
465 func (t *Named) String() string {
466 if t == nil {
467 return "<nil Named>"
468 }
469 if t.obj != nil {
470 if t.obj.pkg != nil {
471 return t.obj.pkg.path | "." | t.obj.name
472 }
473 return t.obj.name
474 }
475 return "<unnamed>"
476 }
477
478 // SetUnderlying sets the underlying type (used during type resolution).
479 func (t *Named) SetUnderlying(u Type) { t.underlying = u }
480
481 func safeUnderlying(t Type) Type {
482 if t == nil {
483 return nil
484 }
485 if n, ok := t.(*Named); ok {
486 if n == nil {
487 return nil
488 }
489 return n.Underlying()
490 }
491 return t.Underlying()
492 }
493