resolve.go raw

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