[dev.typealias] cmd/compile: declare methods after resolving receiver type

For #18130.
Fixes #18655.

Change-Id: I58e2f076b9d8273f128cc033bba9edcd06c81567
Reviewed-on: https://go-review.googlesource.com/35575
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2017-01-23 14:24:24 -08:00
parent 9259f3073a
commit de2e5459ae
7 changed files with 53 additions and 32 deletions

View file

@ -466,14 +466,7 @@ func (p *importer) typ() *Type {
result := p.paramList()
nointerface := p.bool()
base := recv[0].Type
star := false
if base.IsPtr() {
base = base.Elem()
star = true
}
n := methodname0(sym, star, base.Sym)
n := newfuncname(methodname(sym, recv[0].Type))
n.Type = functypefield(recv[0], params, result)
checkwidth(n.Type)
addmethod(sym, n.Type, false, nointerface)

View file

@ -519,10 +519,6 @@ func funchdr(n *Node) {
Fatalf("funchdr: dclcontext = %d", dclcontext)
}
if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
makefuncsym(n.Func.Nname.Sym)
}
dclcontext = PAUTO
funcstart(n)
@ -1163,19 +1159,19 @@ bad:
return nil
}
func methodname(s *Sym, recv *Node) *Node {
// methodname is a misnomer because this now returns a Sym, rather
// than an ONAME.
// TODO(mdempsky): Reconcile with methodsym.
func methodname(s *Sym, recv *Type) *Sym {
star := false
if recv.Op == OIND {
if recv.IsPtr() {
star = true
recv = recv.Left
recv = recv.Elem()
}
return methodname0(s, star, recv.Sym)
}
func methodname0(s *Sym, star bool, tsym *Sym) *Node {
tsym := recv.Sym
if tsym == nil || isblanksym(s) {
return newfuncname(s)
return s
}
var p string
@ -1191,7 +1187,7 @@ func methodname0(s *Sym, star bool, tsym *Sym) *Node {
s = Pkglookup(p, tsym.Pkg)
}
return newfuncname(s)
return s
}
// Add a method, declared as a function.
@ -1335,6 +1331,9 @@ func makefuncsym(s *Sym) {
return
}
s1 := funcsym(s)
if s1.Def != nil {
return
}
s1.Def = newfuncname(s1)
s1.Def.Func.Shortname = s
funcsyms = append(funcsyms, s1.Def)

View file

@ -83,7 +83,7 @@ func autoexport(n *Node, ctxt Class) {
if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
return
}
if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
return
}

View file

@ -247,19 +247,19 @@ func (p *noder) funcHeader(fun *syntax.FuncDecl) *Node {
yyerror("func main must have no arguments and no return values")
}
}
f.Func.Nname = newfuncname(name)
} else {
// Receiver MethodName Signature
f.Func.Shortname = name
f.Func.Nname = methodname(f.Func.Shortname, t.Left.Right)
name = nblank.Sym // filled in by typecheckfunc
}
f.Func.Nname = newfuncname(name)
f.Func.Nname.Name.Defn = f
f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
declare(f.Func.Nname, PFUNC)
if fun.Recv == nil {
declare(f.Func.Nname, PFUNC)
}
funchdr(f)
return f
}

View file

@ -3436,8 +3436,15 @@ func typecheckfunc(n *Node) {
t.SetNname(n.Func.Nname)
rcvr := t.Recv()
if rcvr != nil && n.Func.Shortname != nil {
n.Func.Nname.Sym = methodname(n.Func.Shortname, rcvr.Type)
declare(n.Func.Nname, PFUNC)
addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
}
if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
makefuncsym(n.Func.Nname.Sym)
}
}
// The result of stringtoarraylit MUST be assigned back to n, e.g.

View file

@ -37,8 +37,8 @@ type (
// Methods can be declared on the original named type and the alias.
func (T0) m1() {} // GCCGO_ERROR "previous"
func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
func (A0) m1() {} // TODO(gri) this should be an error // GCCGO_ERROR "redefinition of .m1."
func (A0) m1() {} // ERROR "A0\.m1 redeclared in this block|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
func (A0) m1() {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
func (A0) m2() {}
// Type aliases and the original type name can be used interchangeably.
@ -95,10 +95,10 @@ type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
func (A2) m() {} // ERROR "invalid receiver type"
func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
func (A4) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
func (A4) m() {} // ERROR "reflect.Value.m redeclared in this block" "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
type B1 = struct{}
func (B1) m() {} // ERROR "invalid receiver type"
func (B1) m() {} // ERROR "m redeclared in this block" "invalid receiver type"
// TODO(gri) expand

View file

@ -0,0 +1,22 @@
// errorcheck
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type T struct{}
type A = T
type B = T
func (T) m() {}
func (T) m() {} // ERROR "redeclared"
func (A) m() {} // ERROR "redeclared"
func (A) m() {} // ERROR "redeclared"
func (B) m() {} // ERROR "redeclared"
func (B) m() {} // ERROR "redeclared"
func (*T) m() {} // ERROR "redeclared"
func (*A) m() {} // ERROR "redeclared"
func (*B) m() {} // ERROR "redeclared"