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 types
12
13 import (
14 "bytes"
15 "git.smesh.lol/moxie/pkg/token"
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 Methods []*TCFunc
80 }
81
82 func (t *Basic) Underlying() (tv Type) { return t }
83 func (t *Basic) String() (s string) { return t.Name }
84 func (t *Basic) NumMethods() (n int32) { return len(t.Methods) }
85 func (t *Basic) Method(i int32) (tv *TCFunc) { return t.Methods[i] }
86 func (t *Basic) AddMethod(m *TCFunc) {
87 for i := int32(0); i < len(t.Methods); i++ {
88 if t.Methods[i].Name == m.Name {
89 t.Methods[i] = m
90 return
91 }
92 }
93 if len(t.Methods) >= cap(t.Methods) {
94 old := t.Methods
95 t.Methods = []*TCFunc{:len(old):len(old) + 4}
96 copy(t.Methods, old)
97 }
98 push(t.Methods, m)
99 }
100
101 func (t *Named) AddMethod(m *TCFunc) {
102 for i := int32(0); i < len(t.Methods); i++ {
103 if t.Methods[i].Name == m.Name {
104 t.Methods[i] = m
105 return
106 }
107 }
108 n := len(t.Methods)
109 if n >= cap(t.Methods) {
110 old := t.Methods
111 t.Methods = []*TCFunc{:n:n + 4}
112 copy(t.Methods, old)
113 }
114 t.Methods = t.Methods[:n+1]
115 t.Methods[n] = m
116 }
117
118 func UntypedToTyped(b *Basic) (t Type) {
119 switch b.Kind {
120 case UntypedBool:
121 return Typ[Bool]
122 case UntypedInt:
123 return Typ[Int64]
124 case UntypedRune:
125 if Universe != nil {
126 obj := Universe.Lookup("rune")
127 if obj != nil {
128 if tn, ok := obj.(*TypeName); ok {
129 return tn.Typ
130 }
131 }
132 }
133 return Typ[Int32]
134 case UntypedFloat:
135 return Typ[Float64]
136 case UntypedString:
137 return Typ[TCString]
138 }
139 return nil
140 }
141
142 // ----------------------------------------------------------------------------
143 // Array
144
145 type Array struct {
146 Len int64
147 Elem Type
148 }
149
150 func NewArray(elem Type, n int64) (a *Array) {
151 a = (&Array{}); a.Len = n; a.Elem = elem; return a
152 }
153 func (t *Array) Underlying() (tv Type) { return t }
154 func (t *Array) String() (s string) { return "[" | token.Itoa64(t.Len) | "]" | t.Elem.String() }
155
156 // ----------------------------------------------------------------------------
157 // Slice
158
159 type Slice struct{ Elem Type }
160
161 func NewSlice(elem Type) (s *Slice) {
162 s = (&Slice{}); s.Elem = elem; return s
163 }
164 func (t *Slice) Underlying() (tv Type) { return t }
165 func (t *Slice) String() (s string) { return "[]" | t.Elem.String() }
166
167 // ----------------------------------------------------------------------------
168 // Pointer
169
170 type Pointer struct{ Base Type }
171
172 func NewPointer(base Type) (p *Pointer) {
173 p = (&Pointer{}); p.Base = base; return p
174 }
175 func (t *Pointer) Elem() (tv Type) { return t.Base }
176 func (t *Pointer) Underlying() (tv Type) { return t }
177 func (t *Pointer) String() (s string) { return "*" | t.Base.String() }
178
179 // ----------------------------------------------------------------------------
180 // Map
181
182 type TCMap struct{ Key, Elem Type }
183
184 func NewTCMap(key, elem Type) (t *TCMap) {
185 t = (&TCMap{}); t.Key = key; t.Elem = elem; return t
186 }
187 func (t *TCMap) Underlying() (tv Type) { return t }
188 func (t *TCMap) String() (s string) { return "map[" | t.Key.String() | "]" | t.Elem.String() }
189
190 // ----------------------------------------------------------------------------
191 // Chan
192
193 type TCChanDir int32
194
195 const (
196 TCSendRecv TCChanDir = iota
197 TCSendOnly
198 TCRecvOnly
199 )
200
201 type TCChan struct {
202 Dir TCChanDir
203 Elem Type
204 }
205
206 func NewTCChan(dir TCChanDir, elem Type) (t *TCChan) {
207 t = (&TCChan{}); t.Dir = dir; t.Elem = elem; return t
208 }
209 func (t *TCChan) Underlying() (tv Type) { return t }
210 func (t *TCChan) String() (s string) {
211 switch t.Dir {
212 case TCSendOnly:
213 return "chan<- " | t.Elem.String()
214 case TCRecvOnly:
215 return "<-chan " | t.Elem.String()
216 }
217 return "chan " | t.Elem.String()
218 }
219
220 // ----------------------------------------------------------------------------
221 // Var (a field or variable, used in Struct/Signature/Tuple)
222
223 type TCVar struct {
224 Pkg *TCPackage
225 Name string
226 Typ Type
227 Anonymous bool // embedded field (no explicit name)
228 Used bool
229 Pos interface{} // Pos - stored as interface to avoid import cycle
230 }
231
232 func NewTCVar(pkg *TCPackage, name string, typ Type) (t *TCVar) {
233 t = (&TCVar{}); t.Pkg = pkg; t.Name = name; t.Typ = typ; return t
234 }
235 func NewTCField(pkg *TCPackage, name string, typ Type, anonymous bool) (t *TCVar) {
236 t = (&TCVar{}); t.Pkg = pkg; t.Name = name; t.Typ = typ; t.Anonymous = anonymous; return t
237 }
238 func (v *TCVar) Exported() (ok bool) { return len(v.Name) > 0 && v.Name[0] >= 'A' && v.Name[0] <= 'Z' }
239 func (v *TCVar) objectTag() {}
240 func (v *TCVar) String() (s string) { return v.Name }
241
242 // ----------------------------------------------------------------------------
243 // Struct
244
245 type TCStruct struct {
246 Fields []*TCVar
247 Tags []string
248 }
249
250 func NewTCStruct(fields []*TCVar, tags []string) (t *TCStruct) {
251 t = (&TCStruct{}); t.Fields = fields; t.Tags = tags; return t
252 }
253 func (t *TCStruct) NumFields() (n int32) {
254 if t == nil {
255 return 0
256 }
257 return len(t.Fields)
258 }
259 func (t *TCStruct) Field(i int32) (tv *TCVar) {
260 if t == nil {
261 return nil
262 }
263 return t.Fields[i]
264 }
265 func (t *TCStruct) Tag(i int32) (s string) {
266 if i < len(t.Tags) {
267 return t.Tags[i]
268 }
269 return ""
270 }
271 func (t *TCStruct) Underlying() (tv Type) { return t }
272 func (t *TCStruct) String() (s string) {
273 var sb bytes.Buffer
274 sb.WriteString("struct{")
275 for i, f := range t.Fields {
276 if i > 0 {
277 sb.WriteString("; ")
278 }
279 if !f.Anonymous {
280 sb.WriteString(f.Name)
281 sb.WriteByte(' ')
282 }
283 sb.WriteString(f.Typ.String())
284 if tag := t.Tag(i); tag != "" {
285 sb.WriteString(" \"")
286 sb.WriteString(tag)
287 sb.WriteByte('"')
288 }
289 }
290 sb.WriteByte('}')
291 return sb.String()
292 }
293
294 // ----------------------------------------------------------------------------
295 // Tuple (multi-return, parameter list)
296
297 type Tuple struct{ Vars []*TCVar }
298
299 func NewTuple(vars ...*TCVar) (t *Tuple) {
300 t = (&Tuple{}); t.Vars = vars; return t
301 }
302 func (t *Tuple) Len() (n int32) { return len(t.Vars) }
303 func (t *Tuple) At(i int32) (tv *TCVar) { return t.Vars[i] }
304 func (t *Tuple) Underlying() (tv Type) { return t }
305 func (t *Tuple) String() (s string) {
306 if t == nil || len(t.Vars) == 0 {
307 return "()"
308 }
309 var sb bytes.Buffer
310 sb.WriteByte('(')
311 for i, v := range t.Vars {
312 if i > 0 {
313 sb.WriteString(", ")
314 }
315 sb.WriteString(v.Typ.String())
316 }
317 sb.WriteByte(')')
318 return sb.String()
319 }
320
321 // ----------------------------------------------------------------------------
322 // Signature (function type)
323
324 type Signature struct {
325 Recv *TCVar // nil for plain functions
326 Params *Tuple
327 Results *Tuple
328 Variadic bool
329 }
330
331 func NewSignature(recv *TCVar, params, results *Tuple, variadic bool) (s *Signature) {
332 s = (&Signature{}); s.Recv = recv; s.Params = params; s.Results = results; s.Variadic = variadic; return s
333 }
334 func (t *Signature) Underlying() (tv Type) { return t }
335 func (t *Signature) String() (s string) {
336 var sb bytes.Buffer
337 sb.WriteString("func")
338 if t.Params != nil {
339 writeParams(&sb, t.Params, t.Variadic)
340 } else {
341 sb.WriteString("()")
342 }
343 if t.Results != nil && t.Results.Len() > 0 {
344 sb.WriteByte(' ')
345 if t.Results.Len() == 1 && t.Results.At(0).Name == "" {
346 sb.WriteString(t.Results.At(0).Typ.String())
347 } else {
348 writeParams(&sb, t.Results, false)
349 }
350 }
351 return sb.String()
352 }
353
354 func writeParams(sb *bytes.Buffer, t *Tuple, variadic bool) {
355 sb.WriteByte('(')
356 for i, v := range t.Vars {
357 if i > 0 {
358 sb.WriteString(", ")
359 }
360 if v.Name != "" {
361 sb.WriteString(v.Name)
362 sb.WriteByte(' ')
363 }
364 if variadic && i == len(t.Vars)-1 {
365 if sl, ok := v.Typ.(*Slice); ok {
366 sb.WriteString("...")
367 sb.WriteString(sl.Elem.String())
368 continue
369 }
370 }
371 sb.WriteString(v.Typ.String())
372 }
373 sb.WriteByte(')')
374 }
375
376 // ----------------------------------------------------------------------------
377 // Interface
378
379 // IfaceMethod holds a method signature for an interface.
380 type IfaceMethod struct {
381 Name string
382 Sig *Signature
383 }
384
385 // IfaceMethod constructor used by the bridge package.
386 func NewTCIfaceMethod(name string, sig *Signature) (i *IfaceMethod) {
387 i = (&IfaceMethod{}); i.Name = name; i.Sig = sig; return i
388 }
389
390 type TCInterface struct {
391 XMethods []*IfaceMethod
392 Embeds []Type
393 Completed bool
394 AllMethods []*IfaceMethod
395 }
396
397 func NewTCInterface(methods []*IfaceMethod, embeds []Type) (t *TCInterface) {
398 t = (&TCInterface{}); t.XMethods = methods; t.Embeds = embeds; return t
399 }
400 func (t *TCInterface) NumMethods() (n int32) { return len(t.AllMethods) }
401 func (t *TCInterface) Method(i int32) (i2 *IfaceMethod) { return t.AllMethods[i] }
402 func (t *TCInterface) NumExplicitMethods() (n int32) { return len(t.XMethods) }
403 func (t *TCInterface) ExplicitMethod(i int32) (i2 *IfaceMethod) { return t.XMethods[i] }
404 func (t *TCInterface) NumEmbeddeds() (n int32) { return len(t.Embeds) }
405 func (t *TCInterface) EmbeddedType(i int32) (tv Type) { return t.Embeds[i] }
406 func (t *TCInterface) IsEmpty() (ok bool) { return len(t.AllMethods) == 0 }
407 func (t *TCInterface) Underlying() (tv Type) { return t }
408 func (t *TCInterface) String() (s string) {
409 if t.IsEmpty() {
410 return "interface{}"
411 }
412 var sb bytes.Buffer
413 sb.WriteString("interface{")
414 for i, m := range t.AllMethods {
415 if i > 0 {
416 sb.WriteString("; ")
417 }
418 sb.WriteString(m.Name)
419 sig := m.Sig
420 if sig.Params != nil {
421 writeParams(&sb, sig.Params, sig.Variadic)
422 } else {
423 sb.WriteString("()")
424 }
425 if sig.Results != nil && sig.Results.Len() > 0 {
426 sb.WriteByte(' ')
427 if sig.Results.Len() == 1 {
428 sb.WriteString(sig.Results.At(0).Typ.String())
429 } else {
430 writeParams(&sb, sig.Results, false)
431 }
432 }
433 }
434 sb.WriteByte('}')
435 return sb.String()
436 }
437
438 // Complete fills AllMethods from XMethods + Embeds (called once after all types are resolved).
439 func (t *TCInterface) Complete() {
440 if t.Completed {
441 return
442 }
443 seen := map[string]bool{}
444 t.AllMethods = t.AllMethods | t.XMethods
445 for _, m := range t.XMethods {
446 seen[m.Name] = true
447 }
448 for _, embed := range t.Embeds {
449 if embed == nil {
450 continue
451 }
452 u := SafeUnderlying(embed)
453 if u == nil {
454 continue
455 }
456 if iface, ok := u.(*TCInterface); ok {
457 iface.Complete()
458 for _, m := range iface.AllMethods {
459 if !seen[m.Name] {
460 push(t.AllMethods, m)
461 seen[m.Name] = true
462 }
463 }
464 }
465 }
466 t.Completed = true
467 }
468
469 // ----------------------------------------------------------------------------
470 // TypeParam (generics)
471
472 type TypeParam struct {
473 Id int32
474 Obj *TypeName
475 Constraint Type
476 }
477
478 func NewTypeParam(obj *TypeName, constraint Type) (t *TypeParam) {
479 t = (&TypeParam{}); t.Obj = obj; t.Constraint = constraint; return t
480 }
481 func (t *TypeParam) Underlying() (tv Type) { return t }
482 func (t *TypeParam) String() (s string) {
483 if t.Obj != nil {
484 return t.Obj.Name
485 }
486 return "T" | token.Itoa(t.Id)
487 }
488
489 // ----------------------------------------------------------------------------
490 // Named (named types: type Foo struct{...})
491
492 type Named struct {
493 Obj *TypeName // the type name declaration
494 Under Type // the underlying type
495 Methods []*TCFunc // methods with this type as receiver
496 TParams []*TypeParam
497 TArgs []Type // set when instantiated
498 }
499
500 func NewNamed(obj *TypeName, underlying Type) (n *Named) {
501 n := (&Named{})
502 n.Obj = obj; n.Under = underlying
503 if obj != nil {
504 obj.Typ = n
505 }
506 return n
507 }
508 func (t *Named) NumMethods() (n int32) { return len(t.Methods) }
509 func (t *Named) Method(i int32) (tv *TCFunc) { return t.Methods[i] }
510 func (t *Named) Underlying() (tv Type) {
511 if t == nil {
512 return nil
513 }
514 cur := Type(t)
515 for depth := 0; depth < 20; depth++ {
516 n, ok := cur.(*Named)
517 if !ok || n == nil {
518 return cur
519 }
520 if n.Under == nil || n.Under == n {
521 return n
522 }
523 cur = n.Under
524 }
525 return cur
526 }
527 func (t *Named) String() (s string) {
528 if t == nil {
529 return "<nil Named>"
530 }
531 if t.Obj != nil {
532 if t.Obj.Pkg != nil {
533 return t.Obj.Pkg.Path | "." | t.Obj.Name
534 }
535 return t.Obj.Name
536 }
537 return "<unnamed>"
538 }
539
540 func SafeUnderlying(t Type) (tv Type) {
541 if t == nil {
542 return nil
543 }
544 if n, ok := t.(*Named); ok {
545 if n == nil {
546 return nil
547 }
548 u := n.Underlying()
549 if u != nil && u != Type(n) {
550 return u
551 }
552 if n.Obj != nil && n.Obj.Pkg != nil && ImportRegistry != nil {
553 pkg := ImportRegistry[n.Obj.Pkg.Path]
554 if pkg != nil && pkg.Scope != nil {
555 obj := pkg.Scope.Lookup(n.Obj.Name)
556 if obj != nil {
557 ot := ObjectType(obj)
558 if ot != nil && ot != Type(n) {
559 return SafeUnderlying(ot)
560 }
561 }
562 }
563 }
564 return n
565 }
566 return t.Underlying()
567 }
568