mirror of
https://github.com/golang/go
synced 2024-11-17 04:44:46 -07:00
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: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
950a56899a
commit
33eaf75a03
@ -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 {
|
|||||||
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 {
|
|||||||
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
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|||||||
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
|
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)
|
// The method expression T.m requires a wrapper when T
|
||||||
n.Xoffset = f1.Offset
|
// is different from m's declared receiver type. We
|
||||||
n.Type = f1.Type
|
// normally generate these wrappers while writing out
|
||||||
n.Op = ODOTINTER
|
// runtime type descriptors, which is always done for
|
||||||
return true
|
// 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the base type: methtype will fail if t
|
s := n.Sym
|
||||||
// is not of the form T or *T.
|
m := lookdot1(n, s, t, ms, 0)
|
||||||
mt := methtype(t)
|
if m == nil {
|
||||||
if mt == nil {
|
if lookdot1(n, s, t, ms, 1) != nil {
|
||||||
return false
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
expandmeth(mt)
|
if !isMethodApplicable(t, m) {
|
||||||
f2 := lookdot1(n, s, mt, mt.AllMethods(), dostrcmp)
|
yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s)
|
||||||
if f2 == nil {
|
n.Type = nil
|
||||||
return false
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// disallow T.m if m requires *T receiver
|
n.Op = ONAME
|
||||||
if f2.Type.Recv().Type.IsPtr() && !t.IsPtr() && f2.Embedded != 2 && !isifacemethod(f2.Type) {
|
if n.Name == nil {
|
||||||
yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, f2.Sym)
|
n.Name = new(Name)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
n.Right = newname(n.Sym)
|
||||||
// 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.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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user