Commit 33eaf75a authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: cleanup method expression type checking

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: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 950a5689
...@@ -406,12 +406,7 @@ func methods(t *types.Type) []*Sig { ...@@ -406,12 +406,7 @@ func methods(t *types.Type) []*Sig {
// if pointer receiver but non-pointer t and // if pointer receiver but non-pointer t and
// this is not an embedded pointer inside a struct, // this is not an embedded pointer inside a struct,
// method does not apply. // method does not apply.
this := f.Type.Recv().Type if !isMethodApplicable(t, f) {
if this.IsPtr() && this.Elem() == t {
continue
}
if this.IsPtr() && !t.IsPtr() && f.Embedded != 2 && !isifacemethod(f.Type) {
continue continue
} }
...@@ -431,6 +426,8 @@ func methods(t *types.Type) []*Sig { ...@@ -431,6 +426,8 @@ func methods(t *types.Type) []*Sig {
sig.type_ = methodfunc(f.Type, t) sig.type_ = methodfunc(f.Type, t)
sig.mtype = methodfunc(f.Type, nil) sig.mtype = methodfunc(f.Type, nil)
this := f.Type.Recv().Type
if !sig.isym.Siggen() { if !sig.isym.Siggen() {
sig.isym.SetSiggen(true) sig.isym.SetSiggen(true)
if !eqtype(this, it) { if !eqtype(this, it) {
......
...@@ -847,30 +847,10 @@ func typecheck1(n *Node, top int) *Node { ...@@ -847,30 +847,10 @@ func typecheck1(n *Node, top int) *Node {
s := n.Sym s := n.Sym
if n.Left.Op == OTYPE { if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) { n = typecheckMethodExpr(n)
if looktypedot(n, t, 1) { if n.Type == nil {
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
return n 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 ok = Erv
break break
} }
...@@ -2343,56 +2323,73 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost ...@@ -2343,56 +2323,73 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost
return r return r
} }
func looktypedot(n *Node, t *types.Type, dostrcmp int) bool { // typecheckMethodExpr checks selector expressions (ODOT) where the
s := n.Sym // 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() { if t.IsInterface() {
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp) ms = t.Fields()
if f1 == nil { } else {
return false
}
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) mt := methtype(t)
if mt == nil { if mt == nil {
return false yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
n.Type = nil
return n
} }
expandmeth(mt) expandmeth(mt)
f2 := lookdot1(n, s, mt, mt.AllMethods(), dostrcmp) ms = mt.AllMethods()
if f2 == 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)
}
} }
// disallow T.m if m requires *T receiver s := n.Sym
if f2.Type.Recv().Type.IsPtr() && !t.IsPtr() && f2.Embedded != 2 && !isifacemethod(f2.Type) { m := lookdot1(n, s, t, ms, 0)
yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, f2.Sym) if m == nil {
return false 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
} }
// The method expression T.m requires a wrapper when T is if !isMethodApplicable(t, m) {
// different from m's declared receiver type. We normally yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s)
// generate these wrappers while writing out runtime type n.Type = nil
// descriptors, which is always done for types declared at return n
// 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.Sym = methodSym(t, n.Sym)
n.Xoffset = f2.Offset n.Type = methodfunc(m.Type, n.Left.Type)
n.Type = f2.Type n.Xoffset = 0
n.Op = ODOTMETH n.SetClass(PFUNC)
return true 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 { func derefall(t *types.Type) *types.Type {
......
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