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
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
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>"
}
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
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)
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
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
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
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
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
}
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 {
case *Interface:
for _, m := range t.Methods {
- if identicalNames(name, m.QualifiedName) {
+ if name.IsSame(m.QualifiedName) {
return value, m.Type
}
}
package types
-import "go/ast"
-
func isNamed(typ Type) bool {
if _, ok := typ.(*Basic); ok {
return ok
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 {
// 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()
}
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 {
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
// 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
}
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")