mirror of
https://github.com/golang/go
synced 2024-11-18 19:24:39 -07:00
go.tools/go/types: handle p.x with p of type P *S
R=adonovan CC=golang-dev https://golang.org/cl/10459044
This commit is contained in:
parent
cf8ec1591f
commit
bd55eef6ec
@ -32,6 +32,48 @@ import "go/ast"
|
||||
// index sequence points to an ambiguous entry if it exists, or it is nil.
|
||||
//
|
||||
func LookupFieldOrMethod(typ Type, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||
obj, index, indirect = lookupFieldOrMethod(typ, pkg, name)
|
||||
if obj != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) The code below is not needed if we are looking for methods only,
|
||||
// and it can be done always if we look for fields only. Consider
|
||||
// providing LookupField and LookupMethod as well.
|
||||
|
||||
// If we didn't find anything, we still might have a field p.x as in:
|
||||
//
|
||||
// type S struct{ x int }
|
||||
// func (*S) m() {}
|
||||
// type P *S
|
||||
// var p P
|
||||
//
|
||||
// which requires that we start the search with the underlying type
|
||||
// of P (i.e., *S). We cannot do this always because we might find
|
||||
// methods that don't exist for P but for S (e.g., m). Thus, if the
|
||||
// result is a method we need to discard it.
|
||||
//
|
||||
// TODO(gri) WTF? There isn't a more direct way? Perhaps we should
|
||||
// outlaw named types to pointer types - they are almost
|
||||
// never what one wants, anyway.
|
||||
if t, _ := typ.(*Named); t != nil {
|
||||
u := t.underlying
|
||||
if _, ok := u.(*Pointer); ok {
|
||||
// typ is a named type with an underlying type of the form *T,
|
||||
// start the search with the underlying type *T
|
||||
if obj2, index2, indirect2 := lookupFieldOrMethod(u, pkg, name); obj2 != nil {
|
||||
// only if the result is a field can we keep it
|
||||
if _, ok := obj2.(*Field); ok {
|
||||
return obj2, index2, indirect2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func lookupFieldOrMethod(typ Type, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||
if name == "_" {
|
||||
return // empty fields/methods are never found
|
||||
}
|
||||
|
17
go/types/testdata/decls3.src
vendored
17
go/types/testdata/decls3.src
vendored
@ -104,6 +104,23 @@ func _() {
|
||||
}
|
||||
}
|
||||
|
||||
// Named types that are pointers.
|
||||
|
||||
type S struct{ x int }
|
||||
func (*S) m() {}
|
||||
type P *S
|
||||
|
||||
func _() {
|
||||
var s *S
|
||||
_ = s.x
|
||||
_ = s.m
|
||||
|
||||
var p P
|
||||
_ = p.x
|
||||
_ = p /* ERROR "no field or method" */ .m
|
||||
_ = P /* ERROR "no field or method" */ .m
|
||||
}
|
||||
|
||||
// Borrowed from the FieldByName test cases in reflect/all_test.go.
|
||||
|
||||
type D1 struct {
|
||||
|
Loading…
Reference in New Issue
Block a user