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