Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: clarify rule 3 for selector expressions #21738

Open
go101 opened this issue Sep 2, 2017 · 10 comments
Open

spec: clarify rule 3 for selector expressions #21738

go101 opened this issue Sep 2, 2017 · 10 comments
Labels
Documentation NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@go101
Copy link

go101 commented Sep 2, 2017

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.9 linux/amd64

Does this issue reproduce with the latest release?

yes

What did you do?

package main

type T struct {
	x int
}
type P *T
type PP *P

func main() {
	var t T
	var p P = &t
	var pp PP = &p
	
	t.x = 123 // ok
	
	(*p).x = 123 // ok
	p.x = 123 // ok
	
	(*pp).x = 123 // ok
	pp.x = 123 // not ok
}

What did you expect to see?

compile okay.

Go spec says

As an exception, if the type of x is a named pointer type and (*x).f is a valid selector expression denoting a field (but not a method), x.f is shorthand for (*x).f.

so as (*pp).x is valid, pp.x should be also valid.

What did you see instead?

compile failed

@odeke-em
Copy link
Member

odeke-em commented Sep 2, 2017

/cc @griesemer @mdempsky

@go101
Copy link
Author

go101 commented Sep 2, 2017

btw, maybe here named pointer type in spec should be replaced with defined pointer type.

@go101
Copy link
Author

go101 commented Sep 2, 2017

btw2, there is a line is spec:

Named instances of the boolean, numeric, and string types are predeclared. Other named types are introduced with type declarations.

I looks here the named type is the only occurrence in spec now. I don't know whether it should be defined type or type alias can also be called named types.

@cznic
Copy link
Contributor

cznic commented Sep 2, 2017

IMO: That (*pp).x works does not make it a 'valid selector expression' per se. Actually, it works only after applying the quoted spec rule. IOW, I believe this is working as intended, because I don't think the intention ever was to automatically dereference recursivelly with no limits. And if there has to be a finite limit, only 0 and 1 make sense, with later being the design decision and what the specs mean.

@mdempsky
Copy link
Member

mdempsky commented Sep 5, 2017

I think this is working as intended, but perhaps the spec could be made clearer. I believe the intent is that p.f can be used as shorthand for (*p).f, but not (**p).f, (***p).f, or so on.

cmd/compile and go/types both allow p.f only as shorthand for (*p).f.

gccgo also allows it as shorthand for (**p).f, but I believe that's a bug. (Probably another form of #6366.)

/cc @griesemer @ianlancetaylor

@mdempsky mdempsky changed the title cmd/compile: can't use selector for values of name point types spec: can't use selector for values of named pointer types Sep 6, 2017
@mdempsky
Copy link
Member

mdempsky commented Sep 6, 2017

The crux of the issue appears to be that the spec recursively predicating on whether (*x).f is a valid selector expression, whereas I think rule 3 is just meant to be a slight variation on rule 1.

The simplest solution I see at the moment is to merge rule 3 into rule 1 by adding "underlying" as a qualifier at the beginning:

For a value x of underlying type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f.

Edit: Actually, no, that doesn't work. It needs to be phrased to disallow selecting a method.

@mdempsky
Copy link
Member

mdempsky commented Sep 6, 2017

Here's a related test case:

package p

type U struct { f int }
type T struct { U }
func (*T) f() {}

type P *T

func f() {
    var x P
    x.f = 0 // ERROR?
}

In this case, (*x).f resolves to the method (*T).f, so rule 3 should not apply.

Consistent with this interpretation, go/types rejects the expression x.f with "invalid operation: x (variable of type P) has no field or method f".

cmd/compile and gccgo both accept it, however.

@griesemer
Copy link
Contributor

This (original example) is working as intended. It is definitively not the intent of the spec to permit arbitrarily deep automatic dereferencing.

@go101 It probably should say defined rather than named pointer type in rule 3 otherwise the rule overlaps partly with the first one and generally becomes somewhat meaningless. (Somewhat unrelated, even though we now have defined and alias types, we still have named types: all the types that have a name). Thus the spec needs to be clarified.

Regarding @mdempsky's 2nd example, go/types is correct and the compilers are wrong. Per rule 3 in https://tip.golang.org/ref/spec#Selectors, x.f is valid if the type of x is a named (defined) pointer type (which it is, namely P), and (*x).f is a valid expression denoting a field (not a method). Thus, x.f = 0 is valid only if (*x).f = 0 is valid and f is a field. go/types correctly rejects both versions because x.f denotes a method which rule 3 explicitly disallows. cmd/compile rejects (*x).f = 0 with "cannot assign to (*x).f" (presumably because f is correctly resolved to a method now); so it should also reject x.f = 0. It's definitively inconsistent to resolve x.f to the field and (*x).f to the method.

(Named (defined) pointer types with methods are painful and complicated. This has been discussed in the past and I proposed that perhaps named (defined) pointer types should be outlawed. See #8590 for more examples.)

@griesemer
Copy link
Contributor

Filed #21934 compiler issue.

@griesemer griesemer added this to the Go1.10 milestone Sep 19, 2017
@griesemer griesemer changed the title spec: can't use selector for values of named pointer types spec: clarify rule 3 for selector expressions Sep 19, 2017
@rsc rsc modified the milestones: Go1.10, Go1.11 Dec 14, 2017
@ianlancetaylor ianlancetaylor added the NeedsFix The path to resolution is known, but the work has not been done. label Jun 28, 2018
@ianlancetaylor ianlancetaylor modified the milestones: Go1.11, Unplanned Jun 28, 2018
@gopherbot
Copy link

Change https://golang.org/cl/197561 mentions this issue: cmd/compile: lookup methods of base type for named pointer type

gopherbot pushed a commit that referenced this issue Oct 4, 2019
Passed toolstash-check.

Updates #21738
Fixes #21934

Change-Id: I59f0b2c9890146565ff913b04aeeeff7dc7a4499
Reviewed-on: https://go-review.googlesource.com/c/go/+/197561
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

9 participants