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