mirror of
https://github.com/golang/go
synced 2024-11-26 18:26:48 -07:00
spec: method selectors don't auto-deref named pointer types
Language clarification. The existing rules for selector expressions imply automatic dereferencing of pointers to struct fields. They also implied automatic dereferencing of selectors denoting methods. In almost all cases, such automatic dereferencing does indeed take place for methods but the reason is not the selector rules but the fact that method sets include both methods with T and *T receivers; so for a *T actual receiver, a method expecting a formal T receiver, also accepts a *T (and the invocation or method value expression is the reason for the auto-derefering). However, the rules as stated so far implied that even in case of a variable p of named pointer type P, a selector expression p.f would always be shorthand for (*p).f. This is true for field selectors f, but cannot be true for method selectors since a named pointer type always has an empty method set. Named pointer types may never appear as anonymous field types (and method receivers, for that matter), so this only applies to variables declared of a named pointer type. This is exceedingly rare and perhaps shouldn't be permitted in the first place (but we cannot change that). Amended the selector rules to make auto-deref of values of named pointer types an exception to the general rules and added corresponding examples with explanations. Both gc and gccgo have a bug where they do auto-deref pointers of named types in method selectors where they should not: See http://play.golang.org/p/c6VhjcIVdM , line 45. Fixes #5769. Fixes #8989. LGTM=r, rsc R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/168790043
This commit is contained in:
parent
0f8cd1438d
commit
40818cfe1c
@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of October 27, 2014",
|
||||
"Subtitle": "Version of November 11, 2014",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@ -2521,30 +2521,40 @@ The following rules apply to selectors:
|
||||
<ol>
|
||||
<li>
|
||||
For a value <code>x</code> of type <code>T</code> or <code>*T</code>
|
||||
where <code>T</code> is not an interface type,
|
||||
where <code>T</code> is not a pointer or interface type,
|
||||
<code>x.f</code> denotes the field or method at the shallowest depth
|
||||
in <code>T</code> where there
|
||||
is such an <code>f</code>.
|
||||
If there is not exactly <a href="#Uniqueness_of_identifiers">one <code>f</code></a>
|
||||
with shallowest depth, the selector expression is illegal.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
For a variable <code>x</code> of type <code>I</code> where <code>I</code>
|
||||
For a value <code>x</code> of type <code>I</code> where <code>I</code>
|
||||
is an interface type, <code>x.f</code> denotes the actual method with name
|
||||
<code>f</code> of the value assigned to <code>x</code>.
|
||||
<code>f</code> of the dynamic value of <code>x</code>.
|
||||
If there is no method with name <code>f</code> in the
|
||||
<a href="#Method_sets">method set</a> of <code>I</code>, the selector
|
||||
expression is illegal.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
As an exception, if the type of <code>x</code> is a named pointer type
|
||||
and <code>(*x).f</code> is a valid selector expression denoting a field
|
||||
(but not a method), <code>x.f</code> is shorthand for <code>(*x).f</code>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
In all other cases, <code>x.f</code> is illegal.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
If <code>x</code> is of pointer type and has the value
|
||||
<code>nil</code> and <code>x.f</code> denotes a struct field,
|
||||
assigning to or evaluating <code>x.f</code>
|
||||
causes a <a href="#Run_time_panics">run-time panic</a>.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
If <code>x</code> is of interface type and has the value
|
||||
<code>nil</code>, <a href="#Calls">calling</a> or
|
||||
@ -2553,18 +2563,6 @@ causes a <a href="#Run_time_panics">run-time panic</a>.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
Selectors automatically <a href="#Address_operators">dereference</a>
|
||||
pointers to structs.
|
||||
If <code>x</code> is a pointer to a struct, <code>x.y</code>
|
||||
is shorthand for <code>(*x).y</code>; if the field <code>y</code>
|
||||
is also a pointer to a struct, <code>x.y.z</code> is shorthand
|
||||
for <code>(*(*x).y).z</code>, and so on.
|
||||
If <code>x</code> contains an anonymous field of type <code>*A</code>,
|
||||
where <code>A</code> is also a struct type,
|
||||
<code>x.f</code> is shorthand for <code>(*x.A).f</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, given the declarations:
|
||||
</p>
|
||||
@ -2574,13 +2572,13 @@ type T0 struct {
|
||||
x int
|
||||
}
|
||||
|
||||
func (recv *T0) M0()
|
||||
func (*T0) M0()
|
||||
|
||||
type T1 struct {
|
||||
y int
|
||||
}
|
||||
|
||||
func (recv T1) M1()
|
||||
func (T1) M1()
|
||||
|
||||
type T2 struct {
|
||||
z int
|
||||
@ -2588,9 +2586,13 @@ type T2 struct {
|
||||
*T0
|
||||
}
|
||||
|
||||
func (recv *T2) M2()
|
||||
func (*T2) M2()
|
||||
|
||||
var p *T2 // with p != nil and p.T0 != nil
|
||||
type Q *T2
|
||||
|
||||
var t T2 // with t.T0 != nil
|
||||
var p *T2 // with p != nil and (*p).T0 != nil
|
||||
var q Q = p
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@ -2598,13 +2600,27 @@ one may write:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
p.z // (*p).z
|
||||
p.y // ((*p).T1).y
|
||||
p.x // (*(*p).T0).x
|
||||
t.z // t.z
|
||||
t.y // t.T1.y
|
||||
t.x // (*t.TO).x
|
||||
|
||||
p.M2() // (*p).M2()
|
||||
p.M1() // ((*p).T1).M1()
|
||||
p.M0() // ((*p).T0).M0()
|
||||
p.z // (*p).z
|
||||
p.y // (*p).T1.y
|
||||
p.x // (*(*p).T0).x
|
||||
|
||||
q.x // (*(*q).T0).x (*q).x is a valid field selector
|
||||
|
||||
p.M2() // p.M2() M2 expects *T2 receiver
|
||||
p.M1() // ((*p).T1).M1() M1 expects T1 receiver
|
||||
p.M0() // ((&(*p).T0)).M0() M0 expects *T0 receiver, see section on Calls
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
but the following is invalid:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
q.M0() // (*q).M0 is valid but not a field selector
|
||||
</pre>
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user