Commit e7bd71c8 authored by Gary Burd's avatar Gary Burd Committed by Robert Griesemer

go/doc: Handle recursive embedded types.

R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5645053
parent 025c9a94
......@@ -543,7 +543,8 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int)
// collectEmbeddedMethods collects the embedded methods of typ in mset.
//
func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int) {
func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited map[*namedType]bool) {
visited[typ] = true
for embedded, isPtr := range typ.embedded {
// Once an embedded type is embedded as a pointer type
// all embedded types in those types are treated like
......@@ -557,8 +558,11 @@ func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvType
mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
}
}
r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1)
if !visited[embedded] {
r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
}
}
delete(visited, typ)
}
// computeMethodSets determines the actual method sets for each type encountered.
......@@ -568,7 +572,7 @@ func (r *reader) computeMethodSets() {
// collect embedded methods for t
if t.isStruct {
// struct
r.collectEmbeddedMethods(t.methods, t, t.name, false, 1)
r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(map[*namedType]bool))
} else {
// interface
// TODO(gri) fix this
......
......@@ -40,3 +40,70 @@ TYPES
T4
}
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
//
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
// contains filtered or unexported fields
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
//
type V2 struct {
*V3
}
//
type V3 struct {
*V4
}
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
......@@ -42,6 +42,73 @@ TYPES
T4
}
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
//
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
*u5
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
//
type V2 struct {
*V3
}
//
type V3 struct {
*V4
}
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
//
type t1 struct{}
......@@ -70,3 +137,8 @@ TYPES
// t2.M should not appear as method in a Tx type.
func (t2e) M()
//
type u5 struct {
*U4
}
......@@ -43,3 +43,88 @@ TYPES
// T4.M should appear as method of T5 only if AllMethods is set.
func (*T5) M()
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
// U3.N should appear as method of U3 and as method of U2 only if ...
func (U2) N()
//
type U3 struct {
*U2
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (U3) M()
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
// contains filtered or unexported fields
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (V1) M()
//
type V2 struct {
*V3
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (V2) M()
//
type V3 struct {
*V4
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (V3) M()
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (V5) M()
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
......@@ -77,3 +77,71 @@ func (*T4) M() {}
type T5 struct {
T4
}
// ----------------------------------------------------------------------------
// Recursive type declarations must not lead to endless recursion.
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M() {}
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if AllMethods is set.
func (*U2) M() {}
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if AllMethods is set.
func (*U3) N() {}
type U4 struct {
*u5
}
// U4.M should appear as method of U4.
func (*U4) M() {}
type u5 struct {
*U4
}
// ----------------------------------------------------------------------------
// A higher-level embedded type (and its methods) wins over the same type (and
// its methods) embedded at a lower level.
type V1 struct {
*V2
*V5
}
type V2 struct {
*V3
}
type V3 struct {
*V4
}
type V4 struct {
*V5
}
type V5 struct {
*V6
}
type V6 struct{}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M() {}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M() {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment