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