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