1
0
mirror of https://github.com/golang/go synced 2024-11-18 22:14:56 -07:00

go.tools/go/types: cleanup handling of forward chains of underlying types

- consistently set underlying types of incoming named types in typInternal
- use underlying() helper function to resolve forward chains
- related consistency cleanups

LGTM=adonovan
R=adonovan
CC=golang-codereviews
https://golang.org/cl/53870044
This commit is contained in:
Robert Griesemer 2014-01-29 14:24:54 -08:00
parent c4535ece1b
commit bf4d636dc9
2 changed files with 86 additions and 100 deletions

View File

@ -151,6 +151,26 @@ func (check *checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
check.initVars(lhs, []ast.Expr{init}, token.NoPos) check.initVars(lhs, []ast.Expr{init}, token.NoPos)
} }
// underlying returns the underlying type of typ; possibly by following
// forward chains of named types. Such chains only exist while names types
// are incomplete.
func underlying(typ Type) Type {
for {
n, _ := typ.(*Named)
if n == nil {
break
}
typ = n.underlying
}
return typ
}
func (n *Named) setUnderlying(typ Type) {
if n != nil {
n.underlying = typ
}
}
func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) { func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) {
assert(obj.Type() == nil) assert(obj.Type() == nil)
@ -158,17 +178,14 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
assert(check.iota == nil) assert(check.iota == nil)
named := &Named{obj: obj} named := &Named{obj: obj}
def.setUnderlying(named)
obj.typ = named // make sure recursive type declarations terminate obj.typ = named // make sure recursive type declarations terminate
// If this type (named) defines the type of another (def) type declaration, // determine underlying type of named
// set def's underlying type to this type so that we can resolve the true check.typ(typ, named, cycleOk)
// underlying of def later.
if def != nil {
def.underlying = named
}
// Typecheck typ - it may be a named type that is not yet complete. // The underlying type of named may be itself a named type that is
// For instance, consider: // incomplete:
// //
// type ( // type (
// A B // A B
@ -176,21 +193,11 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
// C A // C A
// ) // )
// //
// When we declare object C, typ is the identifier A which is incomplete. // The type of C is the (named) type of A which is incomplete,
u := check.typ(typ, named, cycleOk) // and which has as its underlying type the named type B.
// Determine the (final, unnamed) underlying type by resolving
// Determine the unnamed underlying type. // any forward chain (they always end in an unnamed type).
// In the above example, the underlying type of A was (temporarily) set named.underlying = underlying(named.underlying)
// to B whose underlying type was set to *C. Such "forward chains" always
// end in an unnamed type (cycles are terminated with an invalid type).
for {
n, _ := u.(*Named)
if n == nil {
break
}
u = n.underlying
}
named.underlying = u
// the underlying type has been determined // the underlying type has been determined
named.complete = true named.complete = true
@ -257,14 +264,14 @@ func (check *checker) funcDecl(obj *Func, info *declInfo) {
// func declarations cannot use iota // func declarations cannot use iota
assert(check.iota == nil) assert(check.iota == nil)
obj.typ = Typ[Invalid] // guard against cycles sig := new(Signature)
obj.typ = sig // guard against cycles
fdecl := info.fdecl fdecl := info.fdecl
sig := check.funcType(fdecl.Recv, fdecl.Type, nil) check.funcType(sig, fdecl.Recv, fdecl.Type)
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values") check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
// ok to continue // ok to continue
} }
obj.typ = sig
// function body must be type-checked after global declarations // function body must be type-checked after global declarations
// (functions implemented elsewhere have no body) // (functions implemented elsewhere have no body)

View File

@ -36,7 +36,7 @@ func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool)
typ := obj.Type() typ := obj.Type()
if typ == nil { if typ == nil {
// object not yet declared // object type not yet determined
if check.objMap == nil { if check.objMap == nil {
check.dump("%s: %s should have been declared (we are inside a function)", e.Pos(), e) check.dump("%s: %s should have been declared (we are inside a function)", e.Pos(), e)
unreachable() unreachable()
@ -82,9 +82,6 @@ func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool)
// maintain x.mode == typexpr despite error // maintain x.mode == typexpr despite error
typ = Typ[Invalid] typ = Typ[Invalid]
} }
if def != nil {
def.underlying = typ
}
case *Var: case *Var:
obj.used = true obj.used = true
@ -141,12 +138,7 @@ func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) (T Type) {
} }
// funcType type-checks a function or method type and returns its signature. // funcType type-checks a function or method type and returns its signature.
func (check *checker) funcType(recv *ast.FieldList, ftyp *ast.FuncType, def *Named) *Signature { func (check *checker) funcType(sig *Signature, recv *ast.FieldList, ftyp *ast.FuncType) *Signature {
sig := new(Signature)
if def != nil {
def.underlying = sig
}
scope := NewScope(check.topScope) scope := NewScope(check.topScope)
check.recordScope(ftyp, scope) check.recordScope(ftyp, scope)
@ -202,7 +194,7 @@ func (check *checker) funcType(recv *ast.FieldList, ftyp *ast.FuncType, def *Nam
return sig return sig
} }
// typInternal contains the core of type checking of types. // typInternal drives type checking of types.
// Must only be called by typ. // Must only be called by typ.
// //
func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type { func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
@ -216,7 +208,9 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
switch x.mode { switch x.mode {
case typexpr: case typexpr:
return x.typ typ := x.typ
def.setUnderlying(typ)
return typ
case invalid: case invalid:
// ignore - error reported before // ignore - error reported before
case novalue: case novalue:
@ -231,7 +225,9 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
switch x.mode { switch x.mode {
case typexpr: case typexpr:
return x.typ typ := x.typ
def.setUnderlying(typ)
return typ
case invalid: case invalid:
// ignore - error reported before // ignore - error reported before
case novalue: case novalue:
@ -246,53 +242,45 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
case *ast.ArrayType: case *ast.ArrayType:
if e.Len != nil { if e.Len != nil {
typ := new(Array) typ := new(Array)
if def != nil { def.setUnderlying(typ)
def.underlying = typ
}
typ.len = check.arrayLength(e.Len) typ.len = check.arrayLength(e.Len)
typ.elem = check.typ(e.Elt, nil, cycleOk) typ.elem = check.typ(e.Elt, nil, cycleOk)
return typ return typ
} else { } else {
typ := new(Slice) typ := new(Slice)
if def != nil { def.setUnderlying(typ)
def.underlying = typ
}
typ.elem = check.typ(e.Elt, nil, true) typ.elem = check.typ(e.Elt, nil, true)
return typ return typ
} }
case *ast.StructType: case *ast.StructType:
typ := new(Struct) typ := new(Struct)
if def != nil { def.setUnderlying(typ)
def.underlying = typ check.structType(typ, e, cycleOk)
}
typ.fields, typ.tags = check.collectFields(e.Fields, cycleOk)
return typ return typ
case *ast.StarExpr: case *ast.StarExpr:
typ := new(Pointer) typ := new(Pointer)
if def != nil { def.setUnderlying(typ)
def.underlying = typ
}
typ.base = check.typ(e.X, nil, true) typ.base = check.typ(e.X, nil, true)
return typ return typ
case *ast.FuncType: case *ast.FuncType:
return check.funcType(nil, e, def) typ := new(Signature)
def.setUnderlying(typ)
check.funcType(typ, nil, e)
return typ
case *ast.InterfaceType: case *ast.InterfaceType:
return check.interfaceType(e, def, cycleOk) typ := new(Interface)
def.setUnderlying(typ)
check.interfaceType(typ, e, def, cycleOk)
return typ
case *ast.MapType: case *ast.MapType:
typ := new(Map) typ := new(Map)
if def != nil { def.setUnderlying(typ)
def.underlying = typ
}
typ.key = check.typ(e.Key, nil, true) typ.key = check.typ(e.Key, nil, true)
typ.elem = check.typ(e.Value, nil, true) typ.elem = check.typ(e.Value, nil, true)
@ -313,9 +301,7 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
case *ast.ChanType: case *ast.ChanType:
typ := new(Chan) typ := new(Chan)
if def != nil { def.setUnderlying(typ)
def.underlying = typ
}
dir := SendRecv dir := SendRecv
switch e.Dir { switch e.Dir {
@ -329,6 +315,7 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir) check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
// ok to continue // ok to continue
} }
typ.dir = dir typ.dir = dir
typ.elem = check.typ(e.Value, nil, true) typ.elem = check.typ(e.Value, nil, true)
return typ return typ
@ -337,7 +324,9 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
check.errorf(e.Pos(), "%s is not a type", e) check.errorf(e.Pos(), "%s is not a type", e)
} }
return Typ[Invalid] typ := Typ[Invalid]
def.setUnderlying(typ)
return typ
} }
// typeOrNil type-checks the type expression (or nil value) e // typeOrNil type-checks the type expression (or nil value) e
@ -438,15 +427,10 @@ func (check *checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool
return true return true
} }
func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk bool) *Interface { func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, cycleOk bool) {
iface := new(Interface)
if def != nil {
def.underlying = iface
}
// empty interface: common case // empty interface: common case
if ityp.Methods == nil { if ityp.Methods == nil {
return iface return
} }
// The parser ensures that field tags are nil and we don't // The parser ensures that field tags are nil and we don't
@ -501,31 +485,21 @@ func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk
for _, e := range embedded { for _, e := range embedded {
pos := e.Pos() pos := e.Pos()
typ := check.typ(e, nil, cycleOk) typ := check.typ(e, nil, cycleOk)
if typ == Typ[Invalid] {
continue
}
named, _ := typ.(*Named) named, _ := typ.(*Named)
if named == nil { if named == nil {
check.invalidAST(pos, "%s is not named type", typ) if typ != Typ[Invalid] {
check.invalidAST(pos, "%s is not named type", typ)
}
continue continue
} }
// determine underlying (possibly incomplete) type // determine underlying (possibly incomplete) type
// by following its forward chain // by following its forward chain
// TODO(gri) should this be part of Underlying()? u := underlying(named)
u := named.underlying
for {
n, _ := u.(*Named)
if n == nil {
break
}
u = n.underlying
}
if u == Typ[Invalid] {
continue
}
embed, _ := u.(*Interface) embed, _ := u.(*Interface)
if embed == nil { if embed == nil {
check.errorf(pos, "%s is not an interface", named) if u != Typ[Invalid] {
check.errorf(pos, "%s is not an interface", named)
}
continue continue
} }
iface.embeddeds = append(iface.embeddeds, named) iface.embeddeds = append(iface.embeddeds, named)
@ -553,12 +527,11 @@ func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk
for i, m := range iface.methods { for i, m := range iface.methods {
expr := signatures[i] expr := signatures[i]
typ := check.typ(expr, nil, true) typ := check.typ(expr, nil, true)
if typ == Typ[Invalid] {
continue // keep method with empty method signature
}
sig, _ := typ.(*Signature) sig, _ := typ.(*Signature)
if sig == nil { if sig == nil {
check.invalidAST(expr.Pos(), "%s is not a method signature", typ) if typ != Typ[Invalid] {
check.invalidAST(expr.Pos(), "%s is not a method signature", typ)
}
continue // keep method with empty method signature continue // keep method with empty method signature
} }
sig.recv = NewVar(m.pos, check.pkg, "", recv) sig.recv = NewVar(m.pos, check.pkg, "", recv)
@ -576,8 +549,6 @@ func (check *checker) interfaceType(ityp *ast.InterfaceType, def *Named, cycleOk
sort.Sort(byUniqueTypeName(iface.embeddeds)) sort.Sort(byUniqueTypeName(iface.embeddeds))
sort.Sort(byUniqueMethodName(iface.allMethods)) sort.Sort(byUniqueMethodName(iface.allMethods))
return iface
} }
// byUniqueTypeName named type lists can be sorted by their unique type names. // byUniqueTypeName named type lists can be sorted by their unique type names.
@ -606,15 +577,22 @@ func (check *checker) tag(t *ast.BasicLit) string {
return "" return ""
} }
func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Var, tags []string) { func (check *checker) structType(styp *Struct, e *ast.StructType, cycleOk bool) {
list := e.Fields
if list == nil { if list == nil {
return return
} }
// struct fields and tags
var fields []*Var
var tags []string
// for double-declaration checks
var fset objset var fset objset
var typ Type // current field typ // current field typ and tag
var tag string // current field tag var typ Type
var tag string
add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) { add := func(field *ast.Field, ident *ast.Ident, name string, anonymous bool, pos token.Pos) {
if tag != "" && tags == nil { if tag != "" && tags == nil {
tags = make([]string, len(fields)) tags = make([]string, len(fields))
@ -662,7 +640,7 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
// spec: "An embedded type must be specified as a type name // spec: "An embedded type must be specified as a type name
// T or as a pointer to a non-interface type name *T, and T // T or as a pointer to a non-interface type name *T, and T
// itself may not be a pointer type." // itself may not be a pointer type."
switch u := t.Underlying().(type) { switch u := t.underlying.(type) {
case *Basic: case *Basic:
// unsafe.Pointer is treated like a regular pointer // unsafe.Pointer is treated like a regular pointer
if u.kind == UnsafePointer { if u.kind == UnsafePointer {
@ -686,5 +664,6 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
} }
} }
return styp.fields = fields
styp.tags = tags
} }