]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: ignore receiver parameters in Eqtype
authorMatthew Dempsky <mdempsky@google.com>
Fri, 11 Mar 2016 22:38:16 +0000 (14:38 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 17 Mar 2016 00:38:15 +0000 (00:38 +0000)
Receiver parameters generally aren't relevant to the function
signature type. In particular:

  1. When checking whether a type's method implements an interface's
     method, we specifically want to ignore the receiver parameters,
     because they'll be different.

  2. When checking interface type equality, interface methods always
     use the same "fakethis" *struct{} type as their receiver.

  3. Finally, method expressions and method values degenerate into
     receiver-less function types.

The only case where we care about receiver types matching is in
addmethod, which is easily handled by adding an extra Eqtype check of
the receiver parameters. Also, added a test for this, since
(surprisingly) there weren't any.

As precedence, go/types.Identical ignores receiver parameters when
comparing go/types.Signature values.

Notably, this allows us to slightly simplify the "implements"
function, which is used for checking whether type/interface t
implements interface iface. Currently, cmd/compile actually works
around Eqtype's receiver parameter checking by creating new throwaway
TFUNC Types without the receiver parameter.

(Worse, the compiler currently only provides APIs to build TFUNC Types
from Nod syntax trees, so building those throwaway types also involves
first building throwaway syntax trees.)

Passes toolstash -cmp.

Change-Id: Ib07289c66feacee284e016bc312e8c5ff674714f
Reviewed-on: https://go-review.googlesource.com/20602
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/dcl.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/type.go
test/method1.go

index 4336f8e6d9a21017074336205b172796cab7bc86..973016f97c034f1b67ff278cace97fc245b2fb70 100644 (file)
@@ -1275,7 +1275,9 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
                if msym.Name != f.Sym.Name {
                        continue
                }
-               if !Eqtype(t, f.Type) {
+               // Eqtype only checks that incoming and result parameters match,
+               // so explicitly check that the receiver parameters match too.
+               if !Eqtype(t, f.Type) || !Eqtype(t.Recvs(), f.Type.Recvs()) {
                        Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", pa, msym, f.Type, t)
                }
                return
index 88ca06903ca010933ad0f8f1d9bf8d9c2fa8ac0e..31efa6269e6007f894992b28a87cda0a431c5b50 100644 (file)
@@ -726,9 +726,11 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
                }
                return false
 
-               // Loop over structs: receiver, in, out.
        case TFUNC:
-               for _, f := range recvsParamsResults {
+               // Check parameters and result parameters for type equality.
+               // We intentionally ignore receiver parameters for type
+               // equality, because they're never relevant.
+               for _, f := range paramsResults {
                        // Loop over fields in structs, ignoring argument names.
                        ta, ia := IterFields(f(t1))
                        tb, ib := IterFields(f(t2))
@@ -2127,10 +2129,9 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
                if im.Broke {
                        continue
                }
-               imtype := methodfunc(im.Type, nil)
                var followptr bool
                tm := ifacelookdot(im.Sym, t, &followptr, false)
-               if tm == nil || tm.Nointerface || !Eqtype(methodfunc(tm.Type, nil), imtype) {
+               if tm == nil || tm.Nointerface || !Eqtype(tm.Type, im.Type) {
                        if tm == nil {
                                tm = ifacelookdot(im.Sym, t, &followptr, true)
                        }
index 2f05f4e5c596d70267bb78a283c82512ccca34f7..9d0207d476a1e6d95022e43142defd142da601b9 100644 (file)
@@ -300,6 +300,11 @@ var recvsParamsResults = [3]func(*Type) *Type{
        (*Type).Recvs, (*Type).Params, (*Type).Results,
 }
 
+// paramsResults is like recvsParamsResults, but omits receiver parameters.
+var paramsResults = [2]func(*Type) *Type{
+       (*Type).Params, (*Type).Results,
+}
+
 // Key returns the key type of map type t.
 func (t *Type) Key() *Type {
        t.wantEtype(TMAP)
index 365b8ca553dafe8490611fc56ca91acd3c4f7564..bb8c81d7461865d6107f9d1556e8b4d4325b2861 100644 (file)
@@ -9,12 +9,16 @@
 
 package main
 
-type T struct { }
-func (t *T) M(int, string)     // GCCGO_ERROR "previous"
-func (t *T) M(int, float64) { }   // ERROR "redeclared|redefinition"
+type T struct{}
 
-func f(int, string)    // GCCGO_ERROR "previous"
-func f(int, float64) { }  // ERROR "redeclared|redefinition"
+func (t *T) M(int, string)  // GCCGO_ERROR "previous"
+func (t *T) M(int, float64) {} // ERROR "redeclared|redefinition"
 
-func g(a int, b string)  // GCCGO_ERROR "previous"
-func g(a int, c string)  // ERROR "redeclared|redefinition"
+func (t T) H()  // GCCGO_ERROR "previous"
+func (t *T) H() {} // ERROR "redeclared|redefinition"
+
+func f(int, string)  // GCCGO_ERROR "previous"
+func f(int, float64) {} // ERROR "redeclared|redefinition"
+
+func g(a int, b string) // GCCGO_ERROR "previous"
+func g(a int, c string) // ERROR "redeclared|redefinition"