1
0
mirror of https://github.com/golang/go synced 2024-11-25 09:17:57 -07:00

gc: correct handling of unexported method names in embedded interfaces

go/types: update for export data format change
reflect: require package qualifiers to match during interface check
runtime: require package qualifiers to match during interface check
test: fixed bug324, adapt to be silent

Fixes #1550.
Issue 1536 remains open.

R=gri, ken2, r
CC=golang-dev
https://golang.org/cl/4442071
This commit is contained in:
Russ Cox 2011-04-21 08:14:50 -04:00
parent 5aad514674
commit 5ff3336490
12 changed files with 84 additions and 58 deletions

View File

@ -315,6 +315,7 @@ struct Pkg
{ {
char* name; char* name;
Strlit* path; Strlit* path;
Sym* pathsym;
char* prefix; char* prefix;
Pkg* link; Pkg* link;
char exported; // import line written in export data char exported; // import line written in export data

View File

@ -1853,6 +1853,10 @@ hidden_interfacedcl:
{ {
$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
} }
| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
{
$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
}
ohidden_funres: ohidden_funres:
{ {

View File

@ -182,6 +182,11 @@ methods(Type *t)
a = b; a = b;
a->name = method->name; a->name = method->name;
if(!exportname(method->name)) {
if(method->pkg == nil)
fatal("methods: missing package");
a->pkg = method->pkg;
}
a->isym = methodsym(method, it, 1); a->isym = methodsym(method, it, 1);
a->tsym = methodsym(method, t, 0); a->tsym = methodsym(method, t, 0);
a->type = methodfunc(f->type, t); a->type = methodfunc(f->type, t);
@ -253,8 +258,11 @@ imethods(Type *t)
method = f->sym; method = f->sym;
a = mal(sizeof(*a)); a = mal(sizeof(*a));
a->name = method->name; a->name = method->name;
if(!exportname(method->name)) if(!exportname(method->name)) {
if(method->pkg == nil)
fatal("imethods: missing package");
a->pkg = method->pkg; a->pkg = method->pkg;
}
a->mtype = f->type; a->mtype = f->type;
a->offset = 0; a->offset = 0;
a->type = methodfunc(f->type, nil); a->type = methodfunc(f->type, nil);
@ -297,6 +305,33 @@ imethods(Type *t)
return all; return all;
} }
static void
dimportpath(Pkg *p)
{
static Pkg *gopkg;
char *nam;
Node *n;
if(p->pathsym != S)
return;
if(gopkg == nil) {
gopkg = mkpkg(strlit("go"));
gopkg->name = "go";
}
nam = smprint("importpath.%s.", p->prefix);
n = nod(ONAME, N, N);
n->sym = pkglookup(nam, gopkg);
free(nam);
n->class = PEXTERN;
n->xoffset = 0;
p->pathsym = n->sym;
gdatastring(n, p->path);
ggloblsym(n->sym, types[TSTRING]->width, 1);
}
static int static int
dgopkgpath(Sym *s, int ot, Pkg *pkg) dgopkgpath(Sym *s, int ot, Pkg *pkg)
{ {
@ -314,30 +349,8 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg)
return dsymptr(s, ot, ns, 0); return dsymptr(s, ot, ns, 0);
} }
return dgostringptr(s, ot, pkg->name); dimportpath(pkg);
} return dsymptr(s, ot, pkg->pathsym, 0);
static void
dimportpath(Pkg *p)
{
static Pkg *gopkg;
char *nam;
Node *n;
if(gopkg == nil) {
gopkg = mkpkg(strlit("go"));
gopkg->name = "go";
}
nam = smprint("importpath.%s.", p->prefix);
n = nod(ONAME, N, N);
n->sym = pkglookup(nam, gopkg);
free(nam);
n->class = PEXTERN;
n->xoffset = 0;
gdatastring(n, p->path);
ggloblsym(n->sym, types[TSTRING]->width, 1);
} }
/* /*

View File

@ -1264,7 +1264,12 @@ Tpretty(Fmt *fp, Type *t)
case TINTER: case TINTER:
fmtprint(fp, "interface {"); fmtprint(fp, "interface {");
for(t1=t->type; t1!=T; t1=t1->down) { for(t1=t->type; t1!=T; t1=t1->down) {
fmtprint(fp, " %hS%hhT", t1->sym, t1->type); fmtprint(fp, " ");
if(exportname(t1->sym->name))
fmtprint(fp, "%hS", t1->sym);
else
fmtprint(fp, "%S", t1->sym);
fmtprint(fp, "%hhT", t1->type);
if(t1->down) if(t1->down)
fmtprint(fp, ";"); fmtprint(fp, ";");
} }

View File

@ -461,7 +461,13 @@ func (p *gcParser) parseFuncType() Type {
// MethodSpec = identifier Signature . // MethodSpec = identifier Signature .
// //
func (p *gcParser) parseMethodSpec(scope *ast.Scope) { func (p *gcParser) parseMethodSpec(scope *ast.Scope) {
p.expect(scanner.Ident) if p.tok == scanner.Ident {
p.expect(scanner.Ident)
} else {
p.parsePkgId()
p.expect('.')
p.parseDotIdent()
}
isVariadic := false isVariadic := false
p.parseSignature(scope, &isVariadic) p.parseSignature(scope, &isVariadic)
} }

View File

@ -152,7 +152,7 @@ var typeTests = []pair{
b() b()
}) })
}{}, }{},
"interface { a(func(func(int) int) func(func(int)) int); b() }", "interface { reflect_test.a(func(func(int) int) func(func(int)) int); reflect_test.b() }",
}, },
} }
@ -1300,40 +1300,40 @@ func TestNestedMethods(t *testing.T) {
} }
} }
type innerInt struct { type InnerInt struct {
x int X int
} }
type outerInt struct { type OuterInt struct {
y int Y int
innerInt InnerInt
} }
func (i *innerInt) m() int { func (i *InnerInt) M() int {
return i.x return i.X
} }
func TestEmbeddedMethods(t *testing.T) { func TestEmbeddedMethods(t *testing.T) {
typ := Typeof((*outerInt)(nil)) typ := Typeof((*OuterInt)(nil))
if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != NewValue((*outerInt).m).Pointer() { if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != NewValue((*OuterInt).M).Pointer() {
t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m) t.Errorf("Wrong method table for OuterInt: (m=%p)", (*OuterInt).M)
for i := 0; i < typ.NumMethod(); i++ { for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i) m := typ.Method(i)
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer()) t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
} }
} }
i := &innerInt{3} i := &InnerInt{3}
if v := NewValue(i).Method(0).Call(nil)[0].Int(); v != 3 { if v := NewValue(i).Method(0).Call(nil)[0].Int(); v != 3 {
t.Errorf("i.m() = %d, want 3", v) t.Errorf("i.M() = %d, want 3", v)
} }
o := &outerInt{1, innerInt{2}} o := &OuterInt{1, InnerInt{2}}
if v := NewValue(o).Method(0).Call(nil)[0].Int(); v != 2 { if v := NewValue(o).Method(0).Call(nil)[0].Int(); v != 2 {
t.Errorf("i.m() = %d, want 2", v) t.Errorf("i.M() = %d, want 2", v)
} }
f := (*outerInt).m f := (*OuterInt).M
if v := f(o); v != 2 { if v := f(o); v != 2 {
t.Errorf("f(o) = %d, want 2", v) t.Errorf("f(o) = %d, want 2", v)
} }

View File

@ -941,9 +941,7 @@ func implements(T, V *commonType) bool {
for j := 0; j < len(v.methods); j++ { for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i] tm := &t.methods[i]
vm := &v.methods[j] vm := &v.methods[j]
// TODO(rsc): && vm.pkgPath == tm.pkgPath should be here if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
// but it breaks the *ast.Ident vs ast.Expr test.
if vm.name == tm.name && vm.typ == tm.typ {
if i++; i >= len(t.methods) { if i++; i >= len(t.methods) {
return true return true
} }
@ -960,9 +958,7 @@ func implements(T, V *commonType) bool {
for j := 0; j < len(v.methods); j++ { for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i] tm := &t.methods[i]
vm := &v.methods[j] vm := &v.methods[j]
// TODO(rsc): && vm.pkgPath == tm.pkgPath should be here if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
// but it breaks the *ast.Ident vs ast.Expr test.
if vm.name == tm.name && vm.mtyp == tm.typ {
if i++; i >= len(t.methods) { if i++; i >= len(t.methods) {
return true return true
} }

View File

@ -50,7 +50,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
Method *t, *et; Method *t, *et;
IMethod *i, *ei; IMethod *i, *ei;
uint32 h; uint32 h;
String *iname; String *iname, *ipkgPath;
Itab *m; Itab *m;
UncommonType *x; UncommonType *x;
Type *itype; Type *itype;
@ -120,6 +120,7 @@ search:
for(; i < ei; i++) { for(; i < ei; i++) {
itype = i->type; itype = i->type;
iname = i->name; iname = i->name;
ipkgPath = i->pkgPath;
for(;; t++) { for(;; t++) {
if(t >= et) { if(t >= et) {
if(!canfail) { if(!canfail) {
@ -136,7 +137,7 @@ search:
m->bad = 1; m->bad = 1;
goto out; goto out;
} }
if(t->mtyp == itype && t->name == iname) if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
break; break;
} }
if(m) if(m)

View File

@ -14,7 +14,7 @@ type Exported interface {
type Implementation struct{} type Implementation struct{}
func (p *Implementation) private() { println("main.Implementation.private()") } func (p *Implementation) private() {}
func main() { func main() {
@ -40,8 +40,13 @@ func main() {
// x = px // x = px
// this assignment unexpectedly compiles and then executes // this assignment unexpectedly compiles and then executes
defer func() {
recover()
}()
x = px.(Exported) x = px.(Exported)
println("should not get this far")
// this is a legitimate call, but because of the previous assignment, // this is a legitimate call, but because of the previous assignment,
// it invokes the method private in p! // it invokes the method private in p!
x.private() // p.Implementation.private() x.private() // p.Implementation.private()

View File

@ -1,4 +1,4 @@
// $G $D/$F.dir/p.go && $G $D/$F.dir/main.go && $L main.$A && ! ./$A.out || echo BUG: should fail // $G $D/$F.dir/p.go && $G $D/$F.dir/main.go && $L main.$A && ./$A.out
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

View File

@ -166,8 +166,3 @@ panic: interface conversion: interface is main.T, not main.T
bugs/bug322.dir/main.go:19: implicit assignment of unexported field 'x' of lib.T in method receiver bugs/bug322.dir/main.go:19: implicit assignment of unexported field 'x' of lib.T in method receiver
bugs/bug322.dir/main.go:32: implicit assignment of unexported field 'x' of lib.T in method receiver bugs/bug322.dir/main.go:32: implicit assignment of unexported field 'x' of lib.T in method receiver
BUG: fails incorrectly BUG: fails incorrectly
=========== bugs/bug324.go
main.Implementation.private()
p.Implementation.private()
BUG: should fail