tc_resolve.mx raw

   1  package types
   2  
   3  import (
   4  	"git.smesh.lol/moxie/pkg/syntax"
   5  	"git.smesh.lol/moxie/pkg/token"
   6  )
   7  
   8  // resolveTypeExpr resolves a type expression to a Type.
   9  // This is the core of the type system - translating AST type nodes to Type values.
  10  func (c *Checker) resolveTypeExpr(e syntax.Expr) (t Type) {
  11  	if e == nil {
  12  		return nil
  13  	}
  14  	switch ev := e.(type) {
  15  	case *syntax.Name:
  16  		return c.resolveTypeName(ev)
  17  	case *syntax.SelectorExpr:
  18  		return c.resolveQualifiedTypeName(ev)
  19  	case *syntax.Operation:
  20  		// *T (pointer)
  21  		if ev.Y == nil && ev.Op == token.Mul {
  22  			base := c.resolveTypeExpr(ev.X)
  23  			if base == nil {
  24  				return nil
  25  			}
  26  			return NewPointer(base)
  27  		}
  28  		// ~T (approximation element in type constraints) - treat as T for B1
  29  		if ev.Y == nil && ev.Op == token.Tilde {
  30  			return c.resolveTypeExpr(ev.X)
  31  		}
  32  		// T | U (union element in type constraints) - return first operand for B1
  33  		if ev.Y != nil && ev.Op == token.Or {
  34  			c.resolveTypeExpr(ev.Y) // resolve both sides to catch undefined errors
  35  			return c.resolveTypeExpr(ev.X)
  36  		}
  37  	case *syntax.SliceType:
  38  		elem := c.resolveTypeExpr(ev.Elem)
  39  		if elem == nil {
  40  			return nil
  41  		}
  42  		if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
  43  			return Typ[TCString]
  44  		}
  45  		return NewSlice(elem)
  46  	case *syntax.ArrayType:
  47  		elem := c.resolveTypeExpr(ev.Elem)
  48  		if elem == nil {
  49  			return nil
  50  		}
  51  		if ev.Len == nil {
  52  			return NewArray(elem, -1)
  53  		}
  54  		n := c.evalArrayLen(ev.Len)
  55  		return NewArray(elem, n)
  56  	case *syntax.MapType:
  57  		key := c.resolveTypeExpr(ev.Key)
  58  		val := c.resolveTypeExpr(ev.Value)
  59  		if key == nil || val == nil {
  60  			return nil
  61  		}
  62  		return NewTCMap(key, val)
  63  	case *syntax.ChanType:
  64  		elem := c.resolveTypeExpr(ev.Elem)
  65  		if elem == nil {
  66  			return nil
  67  		}
  68  		var dir TCChanDir
  69  		switch ev.Dir {
  70  		case syntax.SendOnly:
  71  			dir = TCSendOnly
  72  		case syntax.RecvOnly:
  73  			dir = TCRecvOnly
  74  		default:
  75  			dir = TCSendRecv
  76  		}
  77  		return NewTCChan(dir, elem)
  78  	case *syntax.StructType:
  79  		return c.resolveStructType(ev)
  80  	case *syntax.InterfaceType:
  81  		return c.resolveInterfaceType(ev)
  82  	case *syntax.FuncType:
  83  		return c.resolveFuncType(ev, nil)
  84  	case *syntax.IndexExpr:
  85  		// generic instantiation T[A, B, ...]
  86  		return c.resolveGenericInst(ev)
  87  	case *syntax.DotsType:
  88  		elem := c.resolveTypeExpr(ev.Elem)
  89  		if elem == nil {
  90  			return nil
  91  		}
  92  		if b, ok := elem.(*Basic); ok && b.Kind == Uint8 {
  93  			return Typ[TCString]
  94  		}
  95  		return NewSlice(elem)
  96  	}
  97  	c.errorf(e.Pos(), "cannot resolve type expression")
  98  	return nil
  99  }
 100  
 101  func (c *Checker) resolveTypeName(e *syntax.Name) (t Type) {
 102  	_, obj := c.lookupType(e.Value)
 103  	if obj == nil {
 104  		c.errorf(e.Pos(), "undefined: " | e.Value)
 105  		return nil
 106  	}
 107  	if tn, ok := obj.(*TypeName); ok {
 108  		if c.info != nil {
 109  			c.info.Uses[e] = tn
 110  		}
 111  		return tn.Typ
 112  	}
 113  	c.errorf(e.Pos(), e.Value | " is not a type")
 114  	return nil
 115  }
 116  
 117  func (c *Checker) resolveQualifiedTypeName(e *syntax.SelectorExpr) (t Type) {
 118  	pkgName, ok := e.X.(*syntax.Name)
 119  	if !ok {
 120  		c.errorf(e.Pos(), "invalid type expression")
 121  		return nil
 122  	}
 123  	// lookupType walks localScope -> fileScope -> pkg scope so the file's
 124  	// own import binding wins over a same-named import in another file.
 125  	_, obj := c.lookupType(pkgName.Value)
 126  	if obj == nil {
 127  		c.errorf(e.Pos(), "undefined: " | pkgName.Value)
 128  		return nil
 129  	}
 130  	pkgObj, ok2 := obj.(*PkgName)
 131  	if !ok2 {
 132  		c.errorf(e.Pos(), pkgName.Value | " is not a package")
 133  		return nil
 134  	}
 135  	imported := pkgObj.Imported
 136  	if imported == nil {
 137  		return nil
 138  	}
 139  	typeObj := imported.Scope.Lookup(e.Sel.Value)
 140  	if typeObj == nil {
 141  		c.errorf(e.Sel.Pos(), "undefined: " | pkgName.Value | "." | e.Sel.Value)
 142  		return nil
 143  	}
 144  	if tn, ok3 := typeObj.(*TypeName); ok3 {
 145  		return tn.Typ
 146  	}
 147  	c.errorf(e.Sel.Pos(), pkgName.Value | "." | e.Sel.Value | " is not a type")
 148  	return nil
 149  }
 150  
 151  func (c *Checker) resolveStructType(e *syntax.StructType) (t *TCStruct) {
 152  	var fields []*TCVar
 153  	var tags []string
 154  	for i, f := range e.FieldList {
 155  		typ := c.resolveTypeExpr(f.Type)
 156  		if f.Name != nil {
 157  			push(fields, NewTCField(c.pkg, f.Name.Value, typ, false))
 158  		} else {
 159  			// anonymous/embedded
 160  			name := TypeBaseName(typ)
 161  			push(fields, NewTCField(c.pkg, name, typ, true))
 162  		}
 163  		tag := ""
 164  		if i < len(e.TagList) && e.TagList[i] != nil {
 165  			tag = e.TagList[i].Value
 166  		}
 167  		push(tags, tag)
 168  	}
 169  	return NewTCStruct(fields, tags)
 170  }
 171  
 172  func (c *Checker) resolveInterfaceType(e *syntax.InterfaceType) (t *TCInterface) {
 173  	var methods []*IfaceMethod
 174  	var embeds []Type
 175  	for _, f := range e.MethodList {
 176  		if f.Name == nil {
 177  			// embedded type
 178  			typ := c.resolveTypeExpr(f.Type)
 179  			if typ != nil {
 180  				push(embeds, typ)
 181  			}
 182  			continue
 183  		}
 184  		ft, ok := f.Type.(*syntax.FuncType)
 185  		if !ok {
 186  			continue
 187  		}
 188  		sig := c.resolveFuncType(ft, nil)
 189  		if sig != nil {
 190  			push(methods, &IfaceMethod{Name: f.Name.Value, Sig: sig})
 191  		}
 192  	}
 193  	iface := NewTCInterface(methods, embeds)
 194  	iface.Complete()
 195  	return iface
 196  }
 197  
 198  // resolveFuncType converts a FuncType AST node to a Signature.
 199  // recv is optional (non-nil only for method declarations).
 200  func (c *Checker) resolveFuncType(ft *syntax.FuncType, recv *syntax.Field) (s *Signature) {
 201  	if ft == nil {
 202  		return nil
 203  	}
 204  	var recvVar *TCVar
 205  	if recv != nil {
 206  		recvTyp := c.resolveTypeExpr(recv.Type)
 207  		recvName := ""
 208  		if recv.Name != nil {
 209  			recvName = recv.Name.Value
 210  		}
 211  		recvVar = NewTCVar(c.pkg, recvName, recvTyp)
 212  	}
 213  
 214  	params := c.resolveFieldList(ft.ParamList)
 215  	results := c.resolveFieldList(ft.ResultList)
 216  
 217  	variadic := false
 218  	if len(ft.ParamList) > 0 {
 219  		last := ft.ParamList[len(ft.ParamList)-1]
 220  		if _, ok := last.Type.(*syntax.DotsType); ok {
 221  			variadic = true
 222  			// unwrap: the slice type is already resolved in resolveFieldList
 223  		}
 224  	}
 225  
 226  	return NewSignature(recvVar, params, results, variadic)
 227  }
 228  
 229  func (c *Checker) resolveFieldList(fields []*syntax.Field) (t *Tuple) {
 230  	if len(fields) == 0 {
 231  		return nil
 232  	}
 233  	var vars []*TCVar
 234  	for _, f := range fields {
 235  		typ := c.resolveTypeExpr(f.Type)
 236  		name := ""
 237  		if f.Name != nil {
 238  			name = f.Name.Value
 239  		}
 240  		push(vars, NewTCVar(c.pkg, name, typ))
 241  	}
 242  	return NewTuple(vars...)
 243  }
 244  
 245  func (c *Checker) resolveGenericInst(e *syntax.IndexExpr) (t Type) {
 246  	// TODO: full generic instantiation
 247  	return c.resolveTypeExpr(e.X)
 248  }
 249  
 250  // TypeBaseName returns the name of the base type for an anonymous field.
 251  func TypeBaseName(t Type) (s string) {
 252  	if t == nil {
 253  		return ""
 254  	}
 255  	switch tt := t.(type) {
 256  	case *Named:
 257  		if tt.Obj != nil {
 258  			return tt.Obj.Name
 259  		}
 260  	case *Pointer:
 261  		return TypeBaseName(tt.Base)
 262  	case *Basic:
 263  		return tt.Name
 264  	}
 265  	return ""
 266  }
 267