package main // resolveTypeExpr resolves a type expression to a Type. // This is the core of the type system - translating AST type nodes to Type values. func (c *Checker) resolveTypeExpr(e Expr) Type { if e == nil { return nil } switch e := e.(type) { case *Name: return c.resolveTypeName(e) case *SelectorExpr: return c.resolveQualifiedTypeName(e) case *Operation: // *T (pointer) if e.Y == nil && e.Op == Mul { base := c.resolveTypeExpr(e.X) if base == nil { return nil } return NewPointer(base) } // ~T (approximation element in type constraints) - treat as T for B1 if e.Y == nil && e.Op == Tilde { return c.resolveTypeExpr(e.X) } // T | U (union element in type constraints) - return first operand for B1 if e.Y != nil && e.Op == Or { c.resolveTypeExpr(e.Y) // resolve both sides to catch undefined errors return c.resolveTypeExpr(e.X) } case *SliceType: elem := c.resolveTypeExpr(e.Elem) if elem == nil { return nil } if b, ok := elem.(*Basic); ok && b.kind == Uint8 { return Typ[TCString] } return NewSlice(elem) case *ArrayType: elem := c.resolveTypeExpr(e.Elem) if elem == nil { return nil } if e.Len == nil { // [...]T - length inferred from composite literal return NewArray(elem, -1) } n := c.evalArrayLen(e.Len) return NewArray(elem, n) case *MapType: key := c.resolveTypeExpr(e.Key) val := c.resolveTypeExpr(e.Value) if key == nil || val == nil { return nil } return NewTCMap(key, val) case *ChanType: elem := c.resolveTypeExpr(e.Elem) if elem == nil { return nil } var dir TCChanDir switch e.Dir { case SendOnly: dir = TCSendOnly case RecvOnly: dir = TCRecvOnly default: dir = TCSendRecv } return NewTCChan(dir, elem) case *StructType: return c.resolveStructType(e) case *InterfaceType: return c.resolveInterfaceType(e) case *FuncType: return c.resolveFuncType(e, nil) case *IndexExpr: // generic instantiation T[A, B, ...] return c.resolveGenericInst(e) case *DotsType: elem := c.resolveTypeExpr(e.Elem) if elem == nil { return nil } if b, ok := elem.(*Basic); ok && b.kind == Uint8 { return Typ[TCString] } return NewSlice(elem) } c.errorf(e.Pos(), "cannot resolve type expression") return nil } func (c *Checker) resolveTypeName(e *Name) Type { _, obj := c.lookupType(e.Value) if obj == nil { c.errorf(e.Pos(), "undefined: %s", e.Value) return nil } if tn, ok := obj.(*TypeName); ok { if c.info != nil { c.info.Uses[e] = tn } return tn.typ } c.errorf(e.Pos(), "%s is not a type", e.Value) return nil } func (c *Checker) resolveQualifiedTypeName(e *SelectorExpr) Type { pkgName, ok := e.X.(*Name) if !ok { c.errorf(e.Pos(), "invalid type expression") return nil } _, obj := c.lookup(pkgName.Value, c.pkg.scope) if obj == nil { c.errorf(e.Pos(), "undefined: %s", pkgName.Value) return nil } pkgObj, ok := obj.(*PkgName) if !ok { c.errorf(e.Pos(), "%s is not a package", pkgName.Value) return nil } imported := pkgObj.imported if imported == nil { return nil } typeObj := imported.scope.Lookup(e.Sel.Value) if typeObj == nil { c.errorf(e.Sel.Pos(), "undefined: %s.%s", pkgName.Value, e.Sel.Value) return nil } if tn, ok := typeObj.(*TypeName); ok { return tn.typ } c.errorf(e.Sel.Pos(), "%s.%s is not a type", pkgName.Value, e.Sel.Value) return nil } func (c *Checker) resolveStructType(e *StructType) *TCStruct { var fields []*TCVar var tags []string for i, f := range e.FieldList { typ := c.resolveTypeExpr(f.Type) if f.Name != nil { fields = append(fields, NewTCField(c.pkg, f.Name.Value, typ, false)) } else { // anonymous/embedded name := typeBaseName(typ) fields = append(fields, NewTCField(c.pkg, name, typ, true)) } tag := "" if i < len(e.TagList) && e.TagList[i] != nil { tag = e.TagList[i].Value } tags = append(tags, tag) } return NewTCStruct(fields, tags) } func (c *Checker) resolveInterfaceType(e *InterfaceType) *TCInterface { var methods []*IfaceMethod var embeds []Type for _, f := range e.MethodList { if f.Name == nil { // embedded type typ := c.resolveTypeExpr(f.Type) if typ != nil { embeds = append(embeds, typ) } continue } ft, ok := f.Type.(*FuncType) if !ok { continue } sig := c.resolveFuncType(ft, nil) if sig != nil { methods = append(methods, &IfaceMethod{name: f.Name.Value, sig: sig}) } } iface := NewTCInterface(methods, embeds) iface.Complete() return iface } // resolveFuncType converts a FuncType AST node to a Signature. // recv is optional (non-nil only for method declarations). func (c *Checker) resolveFuncType(ft *FuncType, recv *Field) *Signature { if ft == nil { return nil } var recvVar *TCVar if recv != nil { recvTyp := c.resolveTypeExpr(recv.Type) recvName := "" if recv.Name != nil { recvName = recv.Name.Value } recvVar = NewTCVar(c.pkg, recvName, recvTyp) } params := c.resolveFieldList(ft.ParamList) results := c.resolveFieldList(ft.ResultList) variadic := false if len(ft.ParamList) > 0 { last := ft.ParamList[len(ft.ParamList)-1] if _, ok := last.Type.(*DotsType); ok { variadic = true // unwrap: the slice type is already resolved in resolveFieldList } } return NewSignature(recvVar, params, results, variadic) } func (c *Checker) resolveFieldList(fields []*Field) *Tuple { if len(fields) == 0 { return nil } var vars []*TCVar for _, f := range fields { typ := c.resolveTypeExpr(f.Type) name := "" if f.Name != nil { name = f.Name.Value } vars = append(vars, NewTCVar(c.pkg, name, typ)) } return NewTuple(vars...) } func (c *Checker) resolveGenericInst(e *IndexExpr) Type { // TODO: full generic instantiation return c.resolveTypeExpr(e.X) } // typeBaseName returns the name of the base type for an anonymous field. func typeBaseName(t Type) string { if t == nil { return "" } switch t := t.(type) { case *Named: if t.obj != nil { return t.obj.name } case *Pointer: return typeBaseName(t.base) case *Basic: return t.name } return "" }