types.go 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 typecheck
12
13 import (
14 "fmt"
15 "strings"
16
17 "moxie/syntax"
18 )
19
20 // Type is an alias for syntax.Type. All concrete types in this package
21 // implement it, so they can be stored directly in syntax.TypeAndValue without
22 // wrapping. Type assertions on syntax.TypeAndValue.Type to *Basic, *Struct,
23 // etc. work transparently.
24 type Type = syntax.Type
25
26 // ----------------------------------------------------------------------------
27 // BasicKind
28
29 type BasicKind int
30
31 const (
32 Invalid BasicKind = iota
33
34 // boolean
35 Bool
36
37 // integer
38 Int8
39 Int16
40 Int32
41 Int64
42 Uint8
43 Uint16
44 Uint32
45 Uint64
46
47 // float
48 Float32
49 Float64
50
51 // text — string and []byte are the same underlying kind in Moxie
52 String
53
54 // unsafe
55 UnsafePointer
56
57 // untyped constants
58 UntypedBool
59 UntypedInt
60 UntypedRune
61 UntypedFloat
62 UntypedString
63 UntypedNil
64 )
65
66 // BasicInfo is a bitmask of type properties.
67 type BasicInfo uint
68
69 const (
70 IsBoolean BasicInfo = 1 << iota
71 IsInteger // includes unsigned
72 IsUnsigned // only for unsigned integer kinds
73 IsFloat
74 IsString
75 IsUntyped
76 IsOrdered // ordered by < (integers, floats, strings)
77 IsNumeric // integers + floats
78 )
79
80 // Basic is an elementary type (bool, int32, string, etc.).
81 type Basic struct {
82 kind BasicKind
83 info BasicInfo
84 name string
85 }
86
87 func (t *Basic) Kind() BasicKind { return t.kind }
88 func (t *Basic) Info() BasicInfo { return t.info }
89 func (t *Basic) Name() string { return t.name }
90 func (t *Basic) Underlying() Type { return t }
91 func (t *Basic) String() string { return t.name }
92
93 // ----------------------------------------------------------------------------
94 // Array
95
96 type Array struct {
97 len int64
98 elem Type
99 }
100
101 func NewArray(elem Type, n int64) *Array { return &Array{len: n, elem: elem} }
102 func (t *Array) Len() int64 { return t.len }
103 func (t *Array) Elem() Type { return t.elem }
104 func (t *Array) Underlying() Type { return t }
105 func (t *Array) String() string { return fmt.Sprintf("[%d]%s", t.len, t.elem) }
106
107 // ----------------------------------------------------------------------------
108 // Slice
109
110 type Slice struct{ elem Type }
111
112 func NewSlice(elem Type) *Slice { return &Slice{elem: elem} }
113 func (t *Slice) Elem() Type { return t.elem }
114 func (t *Slice) Underlying() Type { return t }
115 func (t *Slice) String() string { return "[]" + t.elem.String() }
116
117 // ----------------------------------------------------------------------------
118 // Pointer
119
120 type Pointer struct{ base Type }
121
122 func NewPointer(base Type) *Pointer { return &Pointer{base: base} }
123 func (t *Pointer) Elem() Type { return t.base }
124 func (t *Pointer) Underlying() Type { return t }
125 func (t *Pointer) String() string { return "*" + t.base.String() }
126
127 // ----------------------------------------------------------------------------
128 // Map
129
130 type Map struct{ key, elem Type }
131
132 func NewMap(key, elem Type) *Map { return &Map{key: key, elem: elem} }
133 func (t *Map) Key() Type { return t.key }
134 func (t *Map) Elem() Type { return t.elem }
135 func (t *Map) Underlying() Type { return t }
136 func (t *Map) String() string { return fmt.Sprintf("map[%s]%s", t.key, t.elem) }
137
138 // ----------------------------------------------------------------------------
139 // Chan
140
141 type ChanDir int
142
143 const (
144 SendRecv ChanDir = iota
145 SendOnly
146 RecvOnly
147 )
148
149 type Chan struct {
150 dir ChanDir
151 elem Type
152 }
153
154 func NewChan(dir ChanDir, elem Type) *Chan { return &Chan{dir: dir, elem: elem} }
155 func (t *Chan) Dir() ChanDir { return t.dir }
156 func (t *Chan) Elem() Type { return t.elem }
157 func (t *Chan) Underlying() Type { return t }
158 func (t *Chan) String() string {
159 switch t.dir {
160 case SendOnly:
161 return "chan<- " + t.elem.String()
162 case RecvOnly:
163 return "<-chan " + t.elem.String()
164 }
165 return "chan " + t.elem.String()
166 }
167
168 // ----------------------------------------------------------------------------
169 // Var (a field or variable, used in Struct/Signature/Tuple)
170
171 type Var struct {
172 pkg *Package
173 name string
174 typ Type
175 anonymous bool // embedded field (no explicit name)
176 used bool
177 pos interface{} // syntax.Pos — stored as interface to avoid import cycle
178 }
179
180 func NewVar(pkg *Package, name string, typ Type) *Var {
181 return &Var{pkg: pkg, name: name, typ: typ}
182 }
183 func NewField(pkg *Package, name string, typ Type, anonymous bool) *Var {
184 return &Var{pkg: pkg, name: name, typ: typ, anonymous: anonymous}
185 }
186 func (v *Var) Name() string { return v.name }
187 func (v *Var) Type() Type { return v.typ }
188 func (v *Var) Anonymous() bool { return v.anonymous }
189 func (v *Var) Pkg() *Package { return v.pkg }
190 func (v *Var) Exported() bool { return len(v.name) > 0 && v.name[0] >= 'A' && v.name[0] <= 'Z' }
191 func (v *Var) objectTag() {}
192 func (v *Var) String() string { return v.name }
193
194 // ----------------------------------------------------------------------------
195 // Struct
196
197 type Struct struct {
198 fields []*Var
199 tags []string
200 }
201
202 func NewStruct(fields []*Var, tags []string) *Struct {
203 return &Struct{fields: fields, tags: tags}
204 }
205 func (t *Struct) NumFields() int { return len(t.fields) }
206 func (t *Struct) Field(i int) *Var { return t.fields[i] }
207 func (t *Struct) Tag(i int) string {
208 if i < len(t.tags) {
209 return t.tags[i]
210 }
211 return ""
212 }
213 func (t *Struct) Underlying() Type { return t }
214 func (t *Struct) String() string {
215 var sb strings.Builder
216 sb.WriteString("struct{")
217 for i, f := range t.fields {
218 if i > 0 {
219 sb.WriteString("; ")
220 }
221 if !f.anonymous {
222 sb.WriteString(f.name)
223 sb.WriteByte(' ')
224 }
225 sb.WriteString(f.typ.String())
226 if tag := t.Tag(i); tag != "" {
227 fmt.Fprintf(&sb, " %q", tag)
228 }
229 }
230 sb.WriteByte('}')
231 return sb.String()
232 }
233
234 // ----------------------------------------------------------------------------
235 // Tuple (multi-return, parameter list)
236
237 type Tuple struct{ vars []*Var }
238
239 func NewTuple(vars ...*Var) *Tuple { return &Tuple{vars: vars} }
240 func (t *Tuple) Len() int { return len(t.vars) }
241 func (t *Tuple) At(i int) *Var { return t.vars[i] }
242 func (t *Tuple) Underlying() Type { return t }
243 func (t *Tuple) String() string {
244 if t == nil || len(t.vars) == 0 {
245 return "()"
246 }
247 var parts []string
248 for _, v := range t.vars {
249 parts = append(parts, v.typ.String())
250 }
251 return "(" + strings.Join(parts, ", ") + ")"
252 }
253
254 // ----------------------------------------------------------------------------
255 // Signature (function type)
256
257 type Signature struct {
258 recv *Var // nil for plain functions
259 params *Tuple
260 results *Tuple
261 variadic bool
262 }
263
264 func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
265 return &Signature{recv: recv, params: params, results: results, variadic: variadic}
266 }
267 func (t *Signature) Recv() *Var { 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 strings.Builder
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 *strings.Builder, 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 NewIfaceMethod(name string, sig *Signature) *IfaceMethod {
327 return &IfaceMethod{name: name, sig: sig}
328 }
329
330 type Interface struct {
331 methods []*IfaceMethod
332 embeds []Type
333 complete bool
334 allMethods []*IfaceMethod
335 }
336
337 func NewInterface(methods []*IfaceMethod, embeds []Type) *Interface {
338 return &Interface{methods: methods, embeds: embeds}
339 }
340 func (t *Interface) NumMethods() int { return len(t.allMethods) }
341 func (t *Interface) Method(i int) *IfaceMethod { return t.allMethods[i] }
342 func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
343 func (t *Interface) ExplicitMethod(i int) *IfaceMethod { return t.methods[i] }
344 func (t *Interface) NumEmbeddeds() int { return len(t.embeds) }
345 func (t *Interface) EmbeddedType(i int) Type { return t.embeds[i] }
346 func (t *Interface) IsEmpty() bool { return len(t.allMethods) == 0 }
347 func (t *Interface) Underlying() Type { return t }
348 func (t *Interface) String() string {
349 if t.IsEmpty() {
350 return "interface{}"
351 }
352 var sb strings.Builder
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 *Interface) 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.(*Interface); 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 int
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 []*Func // 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() int { return len(t.methods) }
452 func (t *Named) Method(i int) *Func { return t.methods[i] }
453 func (t *Named) AddMethod(m *Func) { 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.underlying != nil {
458 return t.underlying.Underlying()
459 }
460 return t
461 }
462 func (t *Named) String() string {
463 if t.obj != nil {
464 if t.obj.pkg != nil {
465 return t.obj.pkg.path + "." + t.obj.name
466 }
467 return t.obj.name
468 }
469 return "<unnamed>"
470 }
471
472 // SetUnderlying sets the underlying type (used during type resolution).
473 func (t *Named) SetUnderlying(u Type) { t.underlying = u }
474
475 // safeUnderlying returns t.Underlying(), or nil if t is nil or its concrete
476 // value is a typed nil (interface with type descriptor but nil data pointer —
477 // common for unresolved Named types during B1 before all imports are loaded).
478 func safeUnderlying(t Type) (u Type) {
479 if t == nil {
480 return nil
481 }
482 defer func() {
483 if recover() != nil {
484 u = nil
485 }
486 }()
487 return t.Underlying()
488 }
489