]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/api: allow extension of interfaces with unexported methods
authorRuss Cox <rsc@golang.org>
Tue, 18 Sep 2012 19:57:03 +0000 (15:57 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 18 Sep 2012 19:57:03 +0000 (15:57 -0400)
Fixes #4061.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/6525047

api/go1.txt
src/cmd/api/goapi.go
src/cmd/api/testdata/src/pkg/p1/golden.txt
src/cmd/api/testdata/src/pkg/p1/p1.go

index 601c1f39b03d546492210e269e3141bbc8eb4136..70f6feb4410ab7a7adcab3f49be759757f4dadf1 100644 (file)
@@ -2811,7 +2811,7 @@ pkg go/ast, type CompositeLit struct, Elts []Expr
 pkg go/ast, type CompositeLit struct, Lbrace token.Pos
 pkg go/ast, type CompositeLit struct, Rbrace token.Pos
 pkg go/ast, type CompositeLit struct, Type Expr
-pkg go/ast, type Decl interface { End, Pos }
+pkg go/ast, type Decl interface, unexported methods
 pkg go/ast, type Decl interface, End() token.Pos
 pkg go/ast, type Decl interface, Pos() token.Pos
 pkg go/ast, type DeclStmt struct
@@ -2824,7 +2824,7 @@ pkg go/ast, type Ellipsis struct, Ellipsis token.Pos
 pkg go/ast, type Ellipsis struct, Elt Expr
 pkg go/ast, type EmptyStmt struct
 pkg go/ast, type EmptyStmt struct, Semicolon token.Pos
-pkg go/ast, type Expr interface { End, Pos }
+pkg go/ast, type Expr interface, unexported methods
 pkg go/ast, type Expr interface, End() token.Pos
 pkg go/ast, type Expr interface, Pos() token.Pos
 pkg go/ast, type ExprStmt struct
@@ -2971,13 +2971,13 @@ pkg go/ast, type SliceExpr struct, Lbrack token.Pos
 pkg go/ast, type SliceExpr struct, Low Expr
 pkg go/ast, type SliceExpr struct, Rbrack token.Pos
 pkg go/ast, type SliceExpr struct, X Expr
-pkg go/ast, type Spec interface { End, Pos }
+pkg go/ast, type Spec interface, unexported methods
 pkg go/ast, type Spec interface, End() token.Pos
 pkg go/ast, type Spec interface, Pos() token.Pos
 pkg go/ast, type StarExpr struct
 pkg go/ast, type StarExpr struct, Star token.Pos
 pkg go/ast, type StarExpr struct, X Expr
-pkg go/ast, type Stmt interface { End, Pos }
+pkg go/ast, type Stmt interface, unexported methods
 pkg go/ast, type Stmt interface, End() token.Pos
 pkg go/ast, type Stmt interface, Pos() token.Pos
 pkg go/ast, type StructType struct
@@ -5458,7 +5458,7 @@ pkg reflect, type StructField struct, PkgPath string
 pkg reflect, type StructField struct, Tag StructTag
 pkg reflect, type StructField struct, Type Type
 pkg reflect, type StructTag string
-pkg reflect, type Type interface { Align, AssignableTo, Bits, ChanDir, Elem, Field, FieldAlign, FieldByIndex, FieldByName, FieldByNameFunc, Implements, In, IsVariadic, Key, Kind, Len, Method, MethodByName, Name, NumField, NumIn, NumMethod, NumOut, Out, PkgPath, Size, String }
+pkg reflect, type Type interface, unexported methods
 pkg reflect, type Type interface, Align() int
 pkg reflect, type Type interface, AssignableTo(Type) bool
 pkg reflect, type Type interface, Bits() int
@@ -7608,7 +7608,7 @@ pkg syscall (darwin-386), type Rlimit struct, Max uint64
 pkg syscall (darwin-386), type RouteMessage struct
 pkg syscall (darwin-386), type RouteMessage struct, Data []byte
 pkg syscall (darwin-386), type RouteMessage struct, Header RtMsghdr
-pkg syscall (darwin-386), type RoutingMessage interface {}
+pkg syscall (darwin-386), type RoutingMessage interface, unexported methods
 pkg syscall (darwin-386), type RtMetrics struct
 pkg syscall (darwin-386), type RtMetrics struct, Expire int32
 pkg syscall (darwin-386), type RtMetrics struct, Filler [4]uint32
@@ -9427,7 +9427,7 @@ pkg syscall (darwin-386-cgo), type Rlimit struct, Max uint64
 pkg syscall (darwin-386-cgo), type RouteMessage struct
 pkg syscall (darwin-386-cgo), type RouteMessage struct, Data []byte
 pkg syscall (darwin-386-cgo), type RouteMessage struct, Header RtMsghdr
-pkg syscall (darwin-386-cgo), type RoutingMessage interface {}
+pkg syscall (darwin-386-cgo), type RoutingMessage interface, unexported methods
 pkg syscall (darwin-386-cgo), type RtMetrics struct
 pkg syscall (darwin-386-cgo), type RtMetrics struct, Expire int32
 pkg syscall (darwin-386-cgo), type RtMetrics struct, Filler [4]uint32
@@ -11249,7 +11249,7 @@ pkg syscall (darwin-amd64), type Rlimit struct, Max uint64
 pkg syscall (darwin-amd64), type RouteMessage struct
 pkg syscall (darwin-amd64), type RouteMessage struct, Data []byte
 pkg syscall (darwin-amd64), type RouteMessage struct, Header RtMsghdr
-pkg syscall (darwin-amd64), type RoutingMessage interface {}
+pkg syscall (darwin-amd64), type RoutingMessage interface, unexported methods
 pkg syscall (darwin-amd64), type RtMetrics struct
 pkg syscall (darwin-amd64), type RtMetrics struct, Expire int32
 pkg syscall (darwin-amd64), type RtMetrics struct, Filler [4]uint32
@@ -13075,7 +13075,7 @@ pkg syscall (darwin-amd64-cgo), type Rlimit struct, Max uint64
 pkg syscall (darwin-amd64-cgo), type RouteMessage struct
 pkg syscall (darwin-amd64-cgo), type RouteMessage struct, Data []byte
 pkg syscall (darwin-amd64-cgo), type RouteMessage struct, Header RtMsghdr
-pkg syscall (darwin-amd64-cgo), type RoutingMessage interface {}
+pkg syscall (darwin-amd64-cgo), type RoutingMessage interface, unexported methods
 pkg syscall (darwin-amd64-cgo), type RtMetrics struct
 pkg syscall (darwin-amd64-cgo), type RtMetrics struct, Expire int32
 pkg syscall (darwin-amd64-cgo), type RtMetrics struct, Filler [4]uint32
@@ -15046,7 +15046,7 @@ pkg syscall (freebsd-386), type Rlimit struct, Max int64
 pkg syscall (freebsd-386), type RouteMessage struct
 pkg syscall (freebsd-386), type RouteMessage struct, Data []byte
 pkg syscall (freebsd-386), type RouteMessage struct, Header RtMsghdr
-pkg syscall (freebsd-386), type RoutingMessage interface {}
+pkg syscall (freebsd-386), type RoutingMessage interface, unexported methods
 pkg syscall (freebsd-386), type RtMetrics struct
 pkg syscall (freebsd-386), type RtMetrics struct, Expire uint32
 pkg syscall (freebsd-386), type RtMetrics struct, Filler [3]uint32
@@ -17022,7 +17022,7 @@ pkg syscall (freebsd-amd64), type Rlimit struct, Max int64
 pkg syscall (freebsd-amd64), type RouteMessage struct
 pkg syscall (freebsd-amd64), type RouteMessage struct, Data []byte
 pkg syscall (freebsd-amd64), type RouteMessage struct, Header RtMsghdr
-pkg syscall (freebsd-amd64), type RoutingMessage interface {}
+pkg syscall (freebsd-amd64), type RoutingMessage interface, unexported methods
 pkg syscall (freebsd-amd64), type RtMetrics struct
 pkg syscall (freebsd-amd64), type RtMetrics struct, Expire uint64
 pkg syscall (freebsd-amd64), type RtMetrics struct, Filler [3]uint64
@@ -30123,7 +30123,7 @@ pkg syscall, type RawSockaddrInet4 struct, Addr [4]byte
 pkg syscall, type RawSockaddrInet4 struct, Port uint16
 pkg syscall, type Rusage struct
 pkg syscall, type Signal int
-pkg syscall, type Sockaddr interface {}
+pkg syscall, type Sockaddr interface, unexported methods
 pkg syscall, type SockaddrInet4 struct
 pkg syscall, type SockaddrInet4 struct, Addr [4]byte
 pkg syscall, type SockaddrInet4 struct, Port int
index 992762602e560cec1430edc607a3a256f48d21c2..a7485e0447fb9df462091c3243e7579e10ec5745 100644 (file)
@@ -892,15 +892,18 @@ type method struct {
        sig  string // "([]byte) (int, error)", from funcSigString
 }
 
-// interfaceMethods returns the expanded list of methods for an interface.
+// interfaceMethods returns the expanded list of exported methods for an interface.
+// The boolean complete reports whether the list contains all methods (that is, the
+// interface has no unexported methods).
 // pkg is the complete package name ("net/http")
 // iname is the interface name.
-func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
+func (w *Walker) interfaceMethods(pkg, iname string) (methods []method, complete bool) {
        t, ok := w.interfaces[pkgSymbol{pkg, iname}]
        if !ok {
                log.Fatalf("failed to find interface %s.%s", pkg, iname)
        }
 
+       complete = true
        for _, f := range t.Methods.List {
                typ := f.Type
                switch tv := typ.(type) {
@@ -912,6 +915,8 @@ func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
                                                name: mname.Name,
                                                sig:  w.funcSigString(ft),
                                        })
+                               } else {
+                                       complete = false
                                }
                        }
                case *ast.Ident:
@@ -927,7 +932,9 @@ func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
                                log.Fatalf("unexported embedded interface %q in exported interface %s.%s; confused",
                                        embedded, pkg, iname)
                        }
-                       methods = append(methods, w.interfaceMethods(pkg, embedded)...)
+                       m, c := w.interfaceMethods(pkg, embedded)
+                       methods = append(methods, m...)
+                       complete = complete && c
                case *ast.SelectorExpr:
                        lhs := w.nodeString(tv.X)
                        rhs := w.nodeString(tv.Sel)
@@ -935,7 +942,9 @@ func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
                        if !ok {
                                log.Fatalf("can't resolve selector %q in interface %s.%s", lhs, pkg, iname)
                        }
-                       methods = append(methods, w.interfaceMethods(fpkg, rhs)...)
+                       m, c := w.interfaceMethods(fpkg, rhs)
+                       methods = append(methods, m...)
+                       complete = complete && c
                default:
                        log.Fatalf("unknown type %T in interface field", typ)
                }
@@ -945,14 +954,28 @@ func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
 
 func (w *Walker) walkInterfaceType(name string, t *ast.InterfaceType) {
        methNames := []string{}
-
        pop := w.pushScope("type " + name + " interface")
-       for _, m := range w.interfaceMethods(w.curPackageName, name) {
+       methods, complete := w.interfaceMethods(w.curPackageName, name)
+       for _, m := range methods {
                methNames = append(methNames, m.name)
                w.emitFeature(fmt.Sprintf("%s%s", m.name, m.sig))
        }
+       if !complete {
+               // The method set has unexported methods, so all the
+               // implementations are provided by the same package,
+               // so the method set can be extended. Instead of recording
+               // the full set of names (below), record only that there were
+               // unexported methods. (If the interface shrinks, we will notice
+               // because a method signature emitted during the last loop,
+               // will disappear.)
+               w.emitFeature("unexported methods")
+       }
        pop()
 
+       if !complete {
+               return
+       }
+
        sort.Strings(methNames)
        if len(methNames) == 0 {
                w.emitFeature(fmt.Sprintf("type %s interface {}", name))
index e334e5776eea2a780424821cce8e136c4f4f05f9..180c8db4341e396d2193dd2676104a1d1bdff747 100644 (file)
@@ -37,7 +37,7 @@ pkg p1, type Embedded struct
 pkg p1, type Error interface { Error, Temporary }
 pkg p1, type Error interface, Error() string
 pkg p1, type Error interface, Temporary() bool
-pkg p1, type I interface { Get, GetNamed, Name, PackageTwoMeth, Set }
+pkg p1, type I interface, unexported methods
 pkg p1, type I interface, Get(string) int64
 pkg p1, type I interface, GetNamed(string) int64
 pkg p1, type I interface, Name() string
@@ -46,6 +46,11 @@ pkg p1, type I interface, Set(string, int64)
 pkg p1, type MyInt int
 pkg p1, type Namer interface { Name }
 pkg p1, type Namer interface, Name() string
+pkg p1, type Public interface { X, Y }
+pkg p1, type Public interface, X()
+pkg p1, type Public interface, Y()
+pkg p1, type Private interface, unexported methods
+pkg p1, type Private interface, X()
 pkg p1, type S struct
 pkg p1, type S struct, Public *int
 pkg p1, type S struct, PublicTime time.Time
index d965bb75e72b616f418d51e90f3d05976de5d225..412f06b615ea4249ad6b25e963342ab4cf80b7c2 100644 (file)
@@ -78,6 +78,16 @@ type I interface {
        private()
 }
 
+type Public interface {
+       X()
+       Y()
+}
+
+type Private interface {
+       X()
+       y()
+}
+
 type Error interface {
        error
        Temporary() bool