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 // - int = int32, uint = 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 int
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 uint
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 int64
92 elem Type
93 }
94
95 func NewArray(elem Type, n int64) *Array { return &Array{len: n, elem: elem} }
96 func (t *Array) Len() int64 { 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 int
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 }
173
174 func NewTCVar(pkg *TCPackage, name string, typ Type) *TCVar {
175 return &TCVar{pkg: pkg, name: name, typ: typ}
176 }
177 func NewTCField(pkg *TCPackage, name string, typ Type, anonymous bool) *TCVar {
178 return &TCVar{pkg: pkg, name: name, typ: typ, anonymous: anonymous}
179 }
180 func (v *TCVar) Name() string { return v.name }
181 func (v *TCVar) Type() Type { return v.typ }
182 func (v *TCVar) Anonymous() bool { return v.anonymous }
183 func (v *TCVar) Pkg() *TCPackage { return v.pkg }
184 func (v *TCVar) Exported() bool { return len(v.name) > 0 && v.name[0] >= 'A' && v.name[0] <= 'Z' }
185 func (v *TCVar) objectTag() {}
186 func (v *TCVar) String() string { return v.name }
187
188 // ----------------------------------------------------------------------------
189 // Struct
190
191 type TCStruct struct {
192 fields []*TCVar
193 tags []string
194 }
195
196 func NewTCStruct(fields []*TCVar, tags []string) *TCStruct {
197 return &TCStruct{fields: fields, tags: tags}
198 }
199 func (t *TCStruct) NumFields() int { return len(t.fields) }
200 func (t *TCStruct) Field(i int) *TCVar { return t.fields[i] }
201 func (t *TCStruct) Tag(i int) string {
202 if i < len(t.tags) {
203 return t.tags[i]
204 }
205 return ""
206 }
207 func (t *TCStruct) Underlying() Type { return t }
208 func (t *TCStruct) String() string {
209 var sb bytes.Buffer
210 sb.WriteString("struct{")
211 for i, f := range t.fields {
212 if i > 0 {
213 sb.WriteString("; ")
214 }
215 if !f.anonymous {
216 sb.WriteString(f.name)
217 sb.WriteByte(' ')
218 }
219 sb.WriteString(f.typ.String())
220 if tag := t.Tag(i); tag != "" {
221 fmt.Fprintf(&sb, " %q", tag)
222 }
223 }
224 sb.WriteByte('}')
225 return sb.String()
226 }
227
228 // ----------------------------------------------------------------------------
229 // Tuple (multi-return, parameter list)
230
231 type Tuple struct{ vars []*TCVar }
232
233 func NewTuple(vars ...*TCVar) *Tuple { return &Tuple{vars: vars} }
234 func (t *Tuple) Len() int { return len(t.vars) }
235 func (t *Tuple) At(i int) *TCVar { return t.vars[i] }
236 func (t *Tuple) Underlying() Type { return t }
237 func (t *Tuple) String() string {
238 if t == nil || len(t.vars) == 0 {
239 return "()"
240 }
241 var sb bytes.Buffer
242 sb.WriteByte('(')
243 for i, v := range t.vars {
244 if i > 0 {
245 sb.WriteString(", ")
246 }
247 sb.WriteString(v.typ.String())
248 }
249 sb.WriteByte(')')
250 return sb.String()
251 }
252
253 // ----------------------------------------------------------------------------
254 // Signature (function type)
255
256 type Signature struct {
257 recv *TCVar // nil for plain functions
258 params *Tuple
259 results *Tuple
260 variadic bool
261 }
262
263 func NewSignature(recv *TCVar, params, results *Tuple, variadic bool) *Signature {
264 return &Signature{recv: recv, params: params, results: results, variadic: variadic}
265 }
266 func (t *Signature) Recv() *TCVar { return t.recv }
267 func (t *Signature) Params() *Tuple { return t.params }
268 func (t *Signature) Results() *Tuple { return t.results }
269 func (t *Signature) Variadic() bool { return t.variadic }
270 func (t *Signature) Underlying() Type { return t }
271 func (t *Signature) String() string {
272 var sb bytes.Buffer
273 sb.WriteString("func")
274 if t.params != nil {
275 writeParams(&sb, t.params, t.variadic)
276 } else {
277 sb.WriteString("()")
278 }
279 if t.results != nil && t.results.Len() > 0 {
280 sb.WriteByte(' ')
281 if t.results.Len() == 1 && t.results.At(0).name == "" {
282 sb.WriteString(t.results.At(0).typ.String())
283 } else {
284 writeParams(&sb, t.results, false)
285 }
286 }
287 return sb.String()
288 }
289
290 func writeParams(sb *bytes.Buffer, t *Tuple, variadic bool) {
291 sb.WriteByte('(')
292 for i, v := range t.vars {
293 if i > 0 {
294 sb.WriteString(", ")
295 }
296 if v.name != "" {
297 sb.WriteString(v.name)
298 sb.WriteByte(' ')
299 }
300 if variadic && i == len(t.vars)-1 {
301 if sl, ok := v.typ.(*Slice); ok {
302 sb.WriteString("...")
303 sb.WriteString(sl.elem.String())
304 continue
305 }
306 }
307 sb.WriteString(v.typ.String())
308 }
309 sb.WriteByte(')')
310 }
311
312 // ----------------------------------------------------------------------------
313 // Interface
314
315 // IfaceMethod holds a method signature for an interface.
316 type IfaceMethod struct {
317 name string
318 sig *Signature
319 }
320
321 func (m *IfaceMethod) Name() string { return m.name }
322 func (m *IfaceMethod) Sig() *Signature { return m.sig }
323
324 // IfaceMethod constructor used by the bridge package.
325 func NewTCIfaceMethod(name string, sig *Signature) *IfaceMethod {
326 return &IfaceMethod{name: name, sig: sig}
327 }
328
329 type TCInterface struct {
330 methods []*IfaceMethod
331 embeds []Type
332 complete bool
333 allMethods []*IfaceMethod
334 }
335
336 func NewTCInterface(methods []*IfaceMethod, embeds []Type) *TCInterface {
337 return &TCInterface{methods: methods, embeds: embeds}
338 }
339 func (t *TCInterface) NumMethods() int { return len(t.allMethods) }
340 func (t *TCInterface) Method(i int) *IfaceMethod { return t.allMethods[i] }
341 func (t *TCInterface) NumExplicitMethods() int { return len(t.methods) }
342 func (t *TCInterface) ExplicitMethod(i int) *IfaceMethod { return t.methods[i] }
343 func (t *TCInterface) NumEmbeddeds() int { return len(t.embeds) }
344 func (t *TCInterface) EmbeddedType(i int) Type { return t.embeds[i] }
345 func (t *TCInterface) IsEmpty() bool { return len(t.allMethods) == 0 }
346 func (t *TCInterface) Underlying() Type { return t }
347 func (t *TCInterface) String() string {
348 if t.IsEmpty() {
349 return "interface{}"
350 }
351 var sb bytes.Buffer
352 sb.WriteString("interface{")
353 for i, m := range t.allMethods {
354 if i > 0 {
355 sb.WriteString("; ")
356 }
357 sb.WriteString(m.name)
358 // write sig without "func" prefix
359 sig := m.sig
360 if sig.params != nil {
361 writeParams(&sb, sig.params, sig.variadic)
362 } else {
363 sb.WriteString("()")
364 }
365 if sig.results != nil && sig.results.Len() > 0 {
366 sb.WriteByte(' ')
367 if sig.results.Len() == 1 {
368 sb.WriteString(sig.results.At(0).typ.String())
369 } else {
370 writeParams(&sb, sig.results, false)
371 }
372 }
373 }
374 sb.WriteByte('}')
375 return sb.String()
376 }
377
378 // complete fills allMethods from methods + embeds (called once after all types are resolved).
379 func (t *TCInterface) Complete() {
380 if t.complete {
381 return
382 }
383 seen := map[string]bool{}
384 t.allMethods = append(t.allMethods, t.methods...)
385 for _, m := range t.methods {
386 seen[m.name] = true
387 }
388 for _, embed := range t.embeds {
389 if embed == nil {
390 continue
391 }
392 u := safeUnderlying(embed)
393 if u == nil {
394 continue
395 }
396 if iface, ok := u.(*TCInterface); ok {
397 iface.Complete()
398 for _, m := range iface.allMethods {
399 if !seen[m.name] {
400 t.allMethods = append(t.allMethods, m)
401 seen[m.name] = true
402 }
403 }
404 }
405 }
406 t.complete = true
407 }
408
409 // ----------------------------------------------------------------------------
410 // TypeParam (generics)
411
412 type TypeParam struct {
413 id int
414 obj *TypeName
415 constraint Type
416 }
417
418 func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
419 return &TypeParam{obj: obj, constraint: constraint}
420 }
421 func (t *TypeParam) Obj() *TypeName { return t.obj }
422 func (t *TypeParam) Constraint() Type { return t.constraint }
423 func (t *TypeParam) Underlying() Type { return t }
424 func (t *TypeParam) String() string {
425 if t.obj != nil {
426 return t.obj.name
427 }
428 return fmt.Sprintf("T%d", t.id)
429 }
430
431 // ----------------------------------------------------------------------------
432 // Named (named types: type Foo struct{...})
433
434 type Named struct {
435 obj *TypeName // the type name declaration
436 underlying Type // the underlying type
437 methods []*TCFunc // methods with this type as receiver
438 tparams []*TypeParam
439 targs []Type // set when instantiated
440 }
441
442 func NewNamed(obj *TypeName, underlying Type) *Named {
443 n := &Named{obj: obj, underlying: underlying}
444 if obj != nil {
445 obj.typ = n
446 }
447 return n
448 }
449 func (t *Named) Obj() *TypeName { return t.obj }
450 func (t *Named) NumMethods() int { return len(t.methods) }
451 func (t *Named) Method(i int) *TCFunc { return t.methods[i] }
452 func (t *Named) AddMethod(m *TCFunc) { t.methods = append(t.methods, m) }
453 func (t *Named) TypeParams() []*TypeParam { return t.tparams }
454 func (t *Named) TypeArgs() []Type { return t.targs }
455 func (t *Named) Underlying() Type {
456 if t.underlying != nil {
457 return t.underlying.Underlying()
458 }
459 return t
460 }
461 func (t *Named) String() string {
462 if t.obj != nil {
463 if t.obj.pkg != nil {
464 return t.obj.pkg.path | "." | t.obj.name
465 }
466 return t.obj.name
467 }
468 return "<unnamed>"
469 }
470
471 // SetUnderlying sets the underlying type (used during type resolution).
472 func (t *Named) SetUnderlying(u Type) { t.underlying = u }
473
474 // safeUnderlying returns t.Underlying(), or nil if t is nil or its concrete
475 // value is a typed nil (interface with type descriptor but nil data pointer -
476 // common for unresolved Named types during B1 before all imports are loaded).
477 func safeUnderlying(t Type) (u Type) {
478 if t == nil {
479 return nil
480 }
481 defer func() {
482 if recover() != nil {
483 u = nil
484 }
485 }()
486 return t.Underlying()
487 }
488