]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: cleanup method expression type checking
authorMatthew Dempsky <mdempsky@google.com>
Fri, 6 Apr 2018 07:54:20 +0000 (00:54 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 6 Apr 2018 15:40:13 +0000 (15:40 +0000)
Passes toolstash-check.

Change-Id: I804e73447b6fdbb75af6235c193c4ee7cbcf8d3a
Reviewed-on: https://go-review.googlesource.com/105045
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/typecheck.go

index 053e3cb031c571dcabc6494143761dbd8492ce48..f350d514e5f508eecb906b96b4b4e3cad53148fd 100644 (file)
@@ -406,12 +406,7 @@ func methods(t *types.Type) []*Sig {
                // if pointer receiver but non-pointer t and
                // this is not an embedded pointer inside a struct,
                // method does not apply.
-               this := f.Type.Recv().Type
-
-               if this.IsPtr() && this.Elem() == t {
-                       continue
-               }
-               if this.IsPtr() && !t.IsPtr() && f.Embedded != 2 && !isifacemethod(f.Type) {
+               if !isMethodApplicable(t, f) {
                        continue
                }
 
@@ -431,6 +426,8 @@ func methods(t *types.Type) []*Sig {
                sig.type_ = methodfunc(f.Type, t)
                sig.mtype = methodfunc(f.Type, nil)
 
+               this := f.Type.Recv().Type
+
                if !sig.isym.Siggen() {
                        sig.isym.SetSiggen(true)
                        if !eqtype(this, it) {
index 4254d5655d705c038597738573c5f0629d225568..a30c9ca4ff9d4847649b0850c07094fd2592f2db 100644 (file)
@@ -847,30 +847,10 @@ func typecheck1(n *Node, top int) *Node {
                s := n.Sym
 
                if n.Left.Op == OTYPE {
-                       if !looktypedot(n, t, 0) {
-                               if looktypedot(n, t, 1) {
-                                       yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
-                               } else {
-                                       yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
-                               }
-                               n.Type = nil
-                               return n
-                       }
-
-                       if n.Type.Etype != TFUNC || !n.IsMethod() {
-                               yyerror("type %v has no method %S", n.Left.Type, n.Sym)
-                               n.Type = nil
+                       n = typecheckMethodExpr(n)
+                       if n.Type == nil {
                                return n
                        }
-
-                       n.Op = ONAME
-                       if n.Name == nil {
-                               n.Name = new(Name)
-                       }
-                       n.Right = newname(n.Sym)
-                       n.Type = methodfunc(n.Type, n.Left.Type)
-                       n.Xoffset = 0
-                       n.SetClass(PFUNC)
                        ok = Erv
                        break
                }
@@ -2343,56 +2323,73 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost
        return r
 }
 
-func looktypedot(n *Node, t *types.Type, dostrcmp int) bool {
-       s := n.Sym
+// typecheckMethodExpr checks selector expressions (ODOT) where the
+// base expression is a type expression (OTYPE).
+func typecheckMethodExpr(n *Node) *Node {
+       t := n.Left.Type
 
+       // Compute the method set for t.
+       var ms *types.Fields
        if t.IsInterface() {
-               f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
-               if f1 == nil {
-                       return false
+               ms = t.Fields()
+       } else {
+               mt := methtype(t)
+               if mt == nil {
+                       yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
+                       n.Type = nil
+                       return n
                }
+               expandmeth(mt)
+               ms = mt.AllMethods()
 
-               n.Sym = methodSym(t, n.Sym)
-               n.Xoffset = f1.Offset
-               n.Type = f1.Type
-               n.Op = ODOTINTER
-               return true
-       }
-
-       // Find the base type: methtype will fail if t
-       // is not of the form T or *T.
-       mt := methtype(t)
-       if mt == nil {
-               return false
+               // The method expression T.m requires a wrapper when T
+               // is different from m's declared receiver type. We
+               // normally generate these wrappers while writing out
+               // runtime type descriptors, which is always done for
+               // types declared at package scope. However, we need
+               // to make sure to generate wrappers for anonymous
+               // receiver types too.
+               if mt.Sym == nil {
+                       addsignat(t)
+               }
        }
 
-       expandmeth(mt)
-       f2 := lookdot1(n, s, mt, mt.AllMethods(), dostrcmp)
-       if f2 == nil {
-               return false
+       s := n.Sym
+       m := lookdot1(n, s, t, ms, 0)
+       if m == nil {
+               if lookdot1(n, s, t, ms, 1) != nil {
+                       yyerror("%v undefined (cannot refer to unexported method %v)", n, s)
+               } else {
+                       yyerror("%v undefined (type %v has no method %v)", n, t, s)
+               }
+               n.Type = nil
+               return n
        }
 
-       // disallow T.m if m requires *T receiver
-       if f2.Type.Recv().Type.IsPtr() && !t.IsPtr() && f2.Embedded != 2 && !isifacemethod(f2.Type) {
-               yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, f2.Sym)
-               return false
+       if !isMethodApplicable(t, m) {
+               yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s)
+               n.Type = nil
+               return n
        }
 
-       // The method expression T.m requires a wrapper when T is
-       // different from m's declared receiver type. We normally
-       // generate these wrappers while writing out runtime type
-       // descriptors, which is always done for types declared at
-       // package scope. However, we need to make sure to generate
-       // wrappers for anonymous receiver types too.
-       if mt.Sym == nil {
-               addsignat(t)
+       n.Op = ONAME
+       if n.Name == nil {
+               n.Name = new(Name)
        }
-
+       n.Right = newname(n.Sym)
        n.Sym = methodSym(t, n.Sym)
-       n.Xoffset = f2.Offset
-       n.Type = f2.Type
-       n.Op = ODOTMETH
-       return true
+       n.Type = methodfunc(m.Type, n.Left.Type)
+       n.Xoffset = 0
+       n.SetClass(PFUNC)
+       return n
+}
+
+// isMethodApplicable reports whether method m can be called on a
+// value of type t. This is necessary because we compute a single
+// method set for both T and *T, but some *T methods are not
+// applicable to T receivers.
+func isMethodApplicable(t *types.Type, m *types.Field) bool {
+       return t.IsPtr() || !m.Type.Recv().Type.IsPtr() || isifacemethod(m.Type) || m.Embedded == 2
 }
 
 func derefall(t *types.Type) *types.Type {