From bee2d5b0ad241bb15ce79d22661a12dd01f8e992 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 30 Sep 2010 14:59:41 -0400 Subject: [PATCH] gc, spec, tests: no auto-indirect of pointer to interface value Implies no embedding of pointer to interface value either. R=gri, iant, ken2, r, r2 CC=golang-dev https://golang.org/cl/2289041 --- doc/go_spec.html | 23 ++++++------- src/cmd/gc/dcl.c | 5 ++- src/cmd/gc/reflect.c | 9 ------ src/cmd/gc/typecheck.c | 2 +- test/hashmap.go | 12 +++---- test/interface/embed.go | 23 +------------ test/interface/embed2.go | 70 ++++++++++++++++++++++++++++++++++++++++ test/method.go | 5 --- test/method2.go | 5 +++ 9 files changed, 97 insertions(+), 57 deletions(-) create mode 100644 test/interface/embed2.go diff --git a/doc/go_spec.html b/doc/go_spec.html index 8e1b45ab966..2373490c249 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -879,9 +879,10 @@ struct {

-A field declared with a type but no explicit field name is an anonymous field. +A field declared with a type but no explicit field name is an anonymous field +(colloquially called an embedded field). Such a field type must be specified as -a type name T or as a pointer to a type name *T, +a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.

@@ -2214,8 +2215,7 @@ x.f

denotes the field or method f of the value denoted by x -(or of *x if -x is of pointer type). The identifier f +(or sometimes *x; see below). The identifier f is called the (field or method) selector; it must not be the blank identifier. The type of the expression is the type of f. @@ -2258,16 +2258,13 @@ In all other cases, x.f is illegal.

-Selectors automatically dereference pointers. -If x is of pointer type, x.y -is shorthand for (*x).y; if y -is also of pointer type, x.y.z is shorthand +Selectors automatically dereference pointers to structs. +If x is a pointer to a struct, x.y +is shorthand for (*x).y; if the field y +is also a pointer to a struct, x.y.z is shorthand for (*(*x).y).z, and so on. -If *x is of pointer type, dereferencing -must be explicit; -only one level of automatic dereferencing is provided. -For an x of type T containing an -anonymous field declared as *A, +If x contains an anonymous field of type *A, +where A is also a struct type, x.f is a shortcut for (*x.A).f.

diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 05eff966f7a..a9a17b236d6 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -729,8 +729,11 @@ stotype(NodeList *l, int et, Type **t) n->right = N; if(n->embedded && n->type != T) { t1 = n->type; - if(t1->sym == S && isptr[t1->etype]) + if(t1->sym == S && isptr[t1->etype]) { t1 = t1->type; + if(t1->etype == TINTER) + yyerror("embedded type cannot be a pointer to interface"); + } if(isptr[t1->etype]) yyerror("embedded type cannot be a pointer"); else if(t1->etype == TFORW && t1->embedlineno == 0) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 18b2a4fc65b..9a24e7b2a0a 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -286,15 +286,6 @@ imethods(Type *t) oldlist = pc; genwrapper(t, f, isym, 0); } - - // Generate wrapper for pointer to interface type. - isym = methodsym(method, ptrto(t), 0); - if(!(isym->flags & SymSiggen)) { - isym->flags |= SymSiggen; - if(oldlist == nil) - oldlist = pc; - genwrapper(ptrto(t), f, isym, 0); - } } if(oldlist) { diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 821d540fa1f..83c5ff72b9f 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -520,7 +520,7 @@ reswitch: ok = Erv; goto ret; } - if(isptr[t->etype]) { + if(isptr[t->etype] && t->type->etype != TINTER) { t = t->type; if(t == T) goto error; diff --git a/test/hashmap.go b/test/hashmap.go index 096ece0a530..0a4d7ab61ee 100755 --- a/test/hashmap.go +++ b/test/hashmap.go @@ -21,7 +21,7 @@ func ASSERT(p bool) { type KeyType interface { Hash() uint32 - Match(other *KeyType) bool + Match(other KeyType) bool } @@ -31,8 +31,8 @@ type ValueType interface { type Entry struct { - key *KeyType - value *ValueType + key KeyType + value ValueType } @@ -68,7 +68,7 @@ func (m *HashMap) Initialize (initial_log2_capacity uint32) { } -func (m *HashMap) Probe (key *KeyType) *Entry { +func (m *HashMap) Probe (key KeyType) *Entry { ASSERT(key != nil) var i uint32 = key.Hash() % m.capacity() @@ -86,7 +86,7 @@ func (m *HashMap) Probe (key *KeyType) *Entry { } -func (m *HashMap) Lookup (key *KeyType, insert bool) *Entry { +func (m *HashMap) Lookup (key KeyType, insert bool) *Entry { // Find a matching entry. var p *Entry = m.Probe(key) if p.key != nil { @@ -145,7 +145,7 @@ func (n *Number) Hash() uint32 { } -func (n *Number) Match(other *KeyType) bool { +func (n *Number) Match(other KeyType) bool { // var y *Number = other // return n.x == y.x return false diff --git a/test/interface/embed.go b/test/interface/embed.go index 4a702398c67..2fddee1905a 100644 --- a/test/interface/embed.go +++ b/test/interface/embed.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Check methods derived from embedded interface and *interface values. +// Check methods derived from embedded interface values. package main @@ -19,18 +19,12 @@ func (t T) M() int64 { return int64(t) } var t = T(Value) var pt = &t var ti Inter = t -var pti = &ti type S struct { Inter } var s = S{ ti } var ps = &s -type SP struct { *Inter } -var sp = SP{ &ti } -var psp = &sp - var i Inter -var pi = &i var ok = true @@ -45,35 +39,20 @@ func main() { check("t.M()", t.M()) check("pt.M()", pt.M()) check("ti.M()", ti.M()) - check("pti.M()", pti.M()) check("s.M()", s.M()) check("ps.M()", ps.M()) - check("sp.M()", sp.M()) - check("psp.M()", psp.M()) i = t check("i = t; i.M()", i.M()) - check("i = t; pi.M()", pi.M()) i = pt check("i = pt; i.M()", i.M()) - check("i = pt; pi.M()", pi.M()) i = s check("i = s; i.M()", i.M()) - check("i = s; pi.M()", pi.M()) i = ps check("i = ps; i.M()", i.M()) - check("i = ps; pi.M()", pi.M()) - - i = sp - check("i = sp; i.M()", i.M()) - check("i = sp; pi.M()", pi.M()) - - i = psp - check("i = psp; i.M()", i.M()) - check("i = psp; pi.M()", pi.M()) if !ok { println("BUG: interface10") diff --git a/test/interface/embed2.go b/test/interface/embed2.go new file mode 100644 index 00000000000..c18a1fecec2 --- /dev/null +++ b/test/interface/embed2.go @@ -0,0 +1,70 @@ +// errchk $G -e $D/$F.go + +// Copyright 2009 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. + +// Check methods derived from embedded interface and *interface values. + +package main + +import "os" + +const Value = 1e12 + +type Inter interface { M() int64 } + +type T int64 +func (t T) M() int64 { return int64(t) } +var t = T(Value) +var pt = &t +var ti Inter = t +var pti = &ti + +type S struct { Inter } +var s = S{ ti } +var ps = &s + +type SP struct { *Inter } // ERROR "interface" + +var i Inter +var pi = &i + +var ok = true + +func check(s string, v int64) { + if v != Value { + println(s, v) + ok = false + } +} + +func main() { + check("t.M()", t.M()) + check("pt.M()", pt.M()) + check("ti.M()", ti.M()) + check("pti.M()", pti.M()) // ERROR "method" + check("s.M()", s.M()) + check("ps.M()", ps.M()) + + i = t + check("i = t; i.M()", i.M()) + check("i = t; pi.M()", pi.M()) // ERROR "method" + + i = pt + check("i = pt; i.M()", i.M()) + check("i = pt; pi.M()", pi.M()) // ERROR "method" + + i = s + check("i = s; i.M()", i.M()) + check("i = s; pi.M()", pi.M()) // ERROR "method" + + i = ps + check("i = ps; i.M()", i.M()) + check("i = ps; pi.M()", pi.M()) // ERROR "method" + + if !ok { + println("BUG: interface10") + os.Exit(1) + } +} diff --git a/test/method.go b/test/method.go index b52d97894cc..b5a02c6873e 100644 --- a/test/method.go +++ b/test/method.go @@ -124,9 +124,4 @@ func main() { println("Val.val(v):", Val.val(v)) panic("fail") } - pv := &v - if pv.val() != 3 { - println("pv.val():", pv.val()) - panic("fail") - } } diff --git a/test/method2.go b/test/method2.go index cda6d9aadf7..a72536e7b33 100644 --- a/test/method2.go +++ b/test/method2.go @@ -20,3 +20,8 @@ type Val interface { } var _ = (*Val).val // ERROR "method" + +var v Val +var pv = &v + +var _ = pv.val() // ERROR "method"