1
0
mirror of https://github.com/golang/go synced 2024-10-01 03:28:32 -06:00

go/types: export QualifiedName.IsSame and NamedType.AstObj

R=adonovan
CC=golang-dev
https://golang.org/cl/7103047
This commit is contained in:
Robert Griesemer 2013-01-11 14:55:49 -08:00
parent 20130f141f
commit 8b62f54eb7
7 changed files with 54 additions and 42 deletions

View File

@ -163,7 +163,7 @@ func (check *checker) object(obj *ast.Object, cycleOk bool) {
check.valueSpec(spec.Pos(), obj, spec.Names, init.Type, init.Values, iota)
case ast.Typ:
typ := &NamedType{obj: obj}
typ := &NamedType{AstObj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
// typecheck associated method signatures
@ -194,7 +194,7 @@ func (check *checker) object(obj *ast.Object, cycleOk bool) {
params, _ := check.collectParams(mdecl.Recv, false)
sig.Recv = params[0] // the parser/assocMethod ensure there is exactly one parameter
obj.Type = sig
methods = append(methods, &Method{QualifiedName{check.pkg, obj.Name}, sig})
methods = append(methods, &Method{QualifiedName{nil, obj.Name}, sig})
check.later(obj, sig, mdecl.Body)
}
typ.Methods = methods

View File

@ -313,10 +313,10 @@ func writeType(buf *bytes.Buffer, typ Type) {
case *NamedType:
var s string
switch {
case t.obj != nil:
s = t.obj.Name
case t.Obj != nil:
s = t.Obj.GetName()
case t.AstObj != nil:
s = t.AstObj.Name
default:
s = "<NamedType w/o object>"
}

View File

@ -84,7 +84,7 @@ func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) {
continue
}
for _, name := range f.Names {
methods = append(methods, &Method{QualifiedName{check.pkg, name.Name}, sig})
methods = append(methods, &Method{QualifiedName{nil, name.Name}, sig})
}
} else {
// embedded interface
@ -137,24 +137,24 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
if len(f.Names) > 0 {
// named fields
for _, name := range f.Names {
fields = append(fields, &Field{QualifiedName{check.pkg, name.Name}, typ, tag, false})
fields = append(fields, &Field{QualifiedName{nil, name.Name}, typ, tag, false})
}
} else {
// anonymous field
switch t := deref(typ).(type) {
case *Basic:
fields = append(fields, &Field{QualifiedName{check.pkg, t.Name}, typ, tag, true})
fields = append(fields, &Field{QualifiedName{nil, t.Name}, typ, tag, true})
case *NamedType:
var name string
switch {
case t.obj != nil:
name = t.obj.Name
case t.Obj != nil:
name = t.Obj.GetName()
case t.AstObj != nil:
name = t.AstObj.Name
default:
unreachable()
}
fields = append(fields, &Field{QualifiedName{check.pkg, name}, typ, tag, true})
fields = append(fields, &Field{QualifiedName{nil, name}, typ, tag, true})
default:
if typ != Typ[Invalid] {
check.invalidAST(f.Type.Pos(), "anonymous field type %s must be named", typ)
@ -913,7 +913,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
if x.mode == invalid {
goto Error
}
mode, typ := lookupField(x.typ, QualifiedName{check.pkg, sel})
mode, typ := lookupField(x.typ, QualifiedName{nil, sel})
if mode == invalid {
check.invalidOp(e.Pos(), "%s has no single field or method %s", x, sel)
goto Error

View File

@ -265,11 +265,11 @@ func lookupFieldBreadthFirst(list []embeddedType, name QualifiedName) (res looku
visited[typ] = true
// look for a matching attached method
if typ.obj != nil {
assert(typ.obj.Data == nil) // methods must have been moved to typ.Methods
if typ.AstObj != nil {
assert(typ.AstObj.Data == nil) // methods must have been moved to typ.Methods
}
for _, m := range typ.Methods {
if identicalNames(name, m.QualifiedName) {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
if !potentialMatch(e.multiples, value, m.Type) {
return // name collision
@ -281,7 +281,7 @@ func lookupFieldBreadthFirst(list []embeddedType, name QualifiedName) (res looku
case *Struct:
// look for a matching field and collect embedded types
for _, f := range t.Fields {
if identicalNames(name, f.QualifiedName) {
if name.IsSame(f.QualifiedName) {
assert(f.Type != nil)
if !potentialMatch(e.multiples, variable, f.Type) {
return // name collision
@ -305,7 +305,7 @@ func lookupFieldBreadthFirst(list []embeddedType, name QualifiedName) (res looku
case *Interface:
// look for a matching method
for _, m := range t.Methods {
if identicalNames(name, m.QualifiedName) {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
if !potentialMatch(e.multiples, value, m.Type) {
return // name collision
@ -355,11 +355,11 @@ func lookupField(typ Type, name QualifiedName) (operandMode, Type) {
typ = deref(typ)
if t, ok := typ.(*NamedType); ok {
if t.obj != nil {
assert(t.obj.Data == nil) // methods must have been moved to t.Methods
if t.AstObj != nil {
assert(t.AstObj.Data == nil) // methods must have been moved to t.Methods
}
for _, m := range t.Methods {
if identicalNames(name, m.QualifiedName) {
if name.IsSame(m.QualifiedName) {
assert(m.Type != nil)
return value, m.Type
}
@ -371,7 +371,7 @@ func lookupField(typ Type, name QualifiedName) (operandMode, Type) {
case *Struct:
var next []embeddedType
for _, f := range t.Fields {
if identicalNames(name, f.QualifiedName) {
if name.IsSame(f.QualifiedName) {
return variable, f.Type
}
if f.IsAnonymous {
@ -388,7 +388,7 @@ func lookupField(typ Type, name QualifiedName) (operandMode, Type) {
case *Interface:
for _, m := range t.Methods {
if identicalNames(name, m.QualifiedName) {
if name.IsSame(m.QualifiedName) {
return value, m.Type
}
}

View File

@ -6,8 +6,6 @@
package types
import "go/ast"
func isNamed(typ Type) bool {
if _, ok := typ.(*Basic); ok {
return ok
@ -131,7 +129,7 @@ func isIdentical(x, y Type) bool {
if len(x.Fields) == len(y.Fields) {
for i, f := range x.Fields {
g := y.Fields[i]
if !identicalNames(f.QualifiedName, g.QualifiedName) ||
if !f.QualifiedName.IsSame(g.QualifiedName) ||
!isIdentical(f.Type, g.Type) ||
f.Tag != g.Tag ||
f.IsAnonymous != g.IsAnonymous {
@ -185,10 +183,10 @@ func isIdentical(x, y Type) bool {
// in the same type declaration.
if y, ok := y.(*NamedType); ok {
switch {
case x.obj != nil:
return x.obj == y.obj
case x.Obj != nil:
return x.Obj == y.Obj
case x.AstObj != nil:
return x.AstObj == y.AstObj
default:
unreachable()
}
@ -198,17 +196,6 @@ func isIdentical(x, y Type) bool {
return false
}
// identicalNames returns true if the names a and b are equal.
func identicalNames(a, b QualifiedName) bool {
if a.Name != b.Name {
return false
}
// a.Name == b.Name
// TODO(gri) Guarantee that packages are canonicalized
// and then we can compare p == q directly.
return ast.IsExported(a.Name) || a.Pkg.Path == b.Pkg.Path
}
// identicalTypes returns true if both lists a and b have the
// same length and corresponding objects have identical types.
func identicalTypes(a, b []*Var) bool {

View File

@ -91,12 +91,37 @@ type Slice struct {
Elt Type
}
// A QualifiedName is a name qualified with the package the declared the name.
// A QualifiedName is a name qualified with the package that declared the name.
type QualifiedName struct {
Pkg *Package // Pkg.Path == "" for current (non-imported) package
Pkg *Package // nil for current (non-imported) package
Name string // unqualified type name for anonymous fields
}
// IsSame reports whether p and q are the same.
func (p QualifiedName) IsSame(q QualifiedName) bool {
// spec:
// "Two identifiers are different if they are spelled differently,
// or if they appear in different packages and are not exported.
// Otherwise, they are the same."
if p.Name != q.Name {
return false
}
// p.Name == q.Name
if !ast.IsExported(p.Name) {
// TODO(gri) just compare packages once we guarantee that they are canonicalized
pp := ""
if p.Pkg != nil {
pp = p.Pkg.Path
}
qp := ""
if q.Pkg != nil {
qp = q.Pkg.Path
}
return pp == qp
}
return true
}
// A Field represents a field of a struct.
type Field struct {
QualifiedName
@ -211,9 +236,9 @@ type Chan struct {
// A NamedType represents a named type as declared in a type declaration.
type NamedType struct {
implementsType
// TODO(gri) remove obj once we have moved away from ast.Objects
obj *ast.Object // corresponding declared object (current package)
// TODO(gri) remove AstObj once we have moved away from ast.Objects
Obj Object // corresponding declared object (imported package)
AstObj *ast.Object // corresponding declared object (current package)
Underlying Type // nil if not fully declared yet; never a *NamedType
Methods []*Method // TODO(gri) consider keeping them in sorted order
}

View File

@ -159,7 +159,7 @@ func def(kind ast.ObjKind, name string, typ Type) *ast.Object {
obj.Decl = Universe
obj.Type = typ
if typ, ok := typ.(*NamedType); ok {
typ.obj = obj
typ.AstObj = obj
}
if Universe.Insert(obj) != nil {
panic("internal error: double declaration")