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

gc: incorrect error message #1324

Closed
gopherbot opened this Issue Dec 5, 2010 · 9 comments

Comments

Projects
None yet
5 participants
@gopherbot

gopherbot commented Dec 5, 2010

by rulERR911:

What steps will reproduce the problem?
1. Compile attached test.go file (8g test.go)

What is the expected output?
p.Meth undefined (type P has no field or method Meth)

What do you see instead?
p.Meth undefined (type T has no field or method Meth)

Which compiler are you using (5g, 6g, 8g, gccgo)?
8g

Which operating system are you using?
Ubuntu 10.04 LTS

Which revision are you using?  (hg identify)
f7e692dc29b0 release.2010-12-02/release

Please provide any additional information below.
I'm not quite sure about expected output, but existing output is surely wrong (type T
has method Meth)

Attachments:

  1. test.go (179 bytes)
@peterGo

This comment has been minimized.

Contributor

peterGo commented Dec 5, 2010

Comment 1:

package main
import "fmt"
type T struct{}
type P *T
type Q T
func (t *T) TMethod() {
}
func main() {
    var t *T = new(T)
    t.TMethod()
    // p.TMethod undefined (type T has no field or method TMethod)
    var p = P(t)
    p.TMethod()
    // q.TMethod undefined (type Q has no field or method TMethod)
    var q = Q(*t)
    q.TMethod()
    // t: *main.T, &{}; p: main.P, &{}; q: main.Q, {}
    fmt.Printf("t: %T, %v; p: %T, %v; q: %T, %v\n", t, t, p, p, q, q)
}
Your issue summary, "wrong 8g compiler error message", states that the issue is specific
to the 8g compiler; the issue also occurs for 6g and possibly other compilers.
"A type may have a method set associated with it (§Interface types, §Method
declarations). The method set of an interface type is its interface. The method set of
any other named type T consists of all methods with receiver type T. The method set of
the corresponding pointer type *T is the set of all methods with receiver *T or T (that
is, it also contains the method set of T). Any other type has an empty method set. In a
method set, each method must have a unique name."
http://golang.org/doc/go_spec.html#Types
"The receiver type must be of the form T or *T where T is a type name. T is called the
receiver base type or just base type. The base type must not be a pointer or interface
type and must be declared in the same package as the method. The method is said to be
bound to the base type and is visible only within selectors for that type (§Type
declarations, §Selectors)." http://golang.org/doc/go_spec.html#Method_declarations
The type of p is P with an underlying type of *T. Since T is a pointer, it can't be a
receiver base type. The type of q is Q with an underlying type of T, it may be a
receiver base type. Types P, Q, and T are distinct.
The error message "p.TMethod undefined (type T has no field or method TMethod)" refers
to the underlying type T instead of the base type P. The error message "q.TMethod
undefined (type Q has no field or method TMethod)" refers to the base type Q.
My complaint is that the error message "p.TMethod undefined (type T has no field or
method TMethod)" should read "p.TMethod undefined (type P has no field or method
TMethod)."
@adg

This comment has been minimized.

Contributor

adg commented Dec 6, 2010

Comment 2:

Labels changed: added compilerbug.

Owner changed to r...@golang.org.

Status changed to Accepted.

@rsc

This comment has been minimized.

Contributor

rsc commented Dec 9, 2010

Comment 3:

Here is a simpler case
package main
type T int
func (t T) Meth()
var t *T
type P *T
var p P
func main() {
    t.Meth()
    p.Meth()
}
The error printed is definitely wrong but I don't
know whether it is the error message wording
or the fact that there is an error at all that is 
the wrong part.
+gri
@griesemer

This comment has been minimized.

Contributor

griesemer commented Dec 9, 2010

Comment 4:

Here's a slightly modified case (removed *'s):
package main
type T int
func (t T) Meth()
var t T
type P T
var p P
func main() {
       t.Meth()
       p.Meth()
}
6g issue1324.go 
issue1324.go:12: p.Meth undefined (type P has no field or method Meth)
gccgo issue1324.go 
issue1324.go:12:9: error: reference to undefined field or method ‘Meth’
This is consistent with the spec: http://golang.org/doc/go_spec.html#Type_declarations
a) "The declared type does not inherit any methods bound to the existing type, but the
method set of an interface type or of elements of a composite type remains unchanged"
We don't have an interface type nor a composite type in this case.
In the original example we have
type P *T
and P is a composite type according to http://golang.org/doc/go_spec.html#Types .
b) "The method set of the corresponding pointer type *T is the set of all methods with
receiver *T or T" according to the spec (same section).
Thus in this case, the method set of *T is the method Meth, and it remains unchanged
according to a).
So I am led to believe that the method set of P contains the method Meth. That said, one
might argue that a) is not correct (and perhaps shouldn't allow pointer types).
@rsc

This comment has been minimized.

Contributor

rsc commented Dec 9, 2010

Comment 5:

I think that (a) is correct, especially when you 
consider that there is no possible way to add
methods to type P, so it might as well look at *T's.
So the bug here is that the program does not
compile cleanly, not that it prints a misworded error.
@rsc

This comment has been minimized.

Contributor

rsc commented Jan 6, 2011

Comment 6:

I am not sure about this anymore.
  
Lorenzo Stoakes points out that the interpretation
of the spec that Robert and I took in comments 4-5
disagrees with test/fixedbugs/bug117.go. 
So this would be a language change in the sense
of tested behavior even if not a change in the spec.
If we keep bug117 as is, then we need to make the
spec exclude pointers from the relevant rule.
 
At this point I think we can reasonably decide to go
either way, but we need to decide.  Robert, can you
talk to Rob and Ian?  I don't care much either way.
@griesemer

This comment has been minimized.

Contributor

griesemer commented Feb 7, 2011

Comment 7:

After re-reading the spec a bit more closely, and discussing this with Rob and Ian, I am
inclined to say that the original submission is correct about the misleading compiler
error message and that the pointer type (P) should not "inherit" the method. For the
program:
package main
type T struct{}
func (t T) m()
type P *T
func main() {
    var t T 
    t.m()
    
    var p P
    p.m()        // p.m undefined (line 13)
    (*p).m()    // legal and accepted (line 14)
}
Again, according to the spec: http://golang.org/doc/go_spec.html#Type_declarations
a) "The declared type does not inherit any methods bound to the existing type, but the
method set of an interface type or of elements of a composite type remains unchanged"
and P is a composite type according to http://golang.org/doc/go_spec.html#Types (P is a
pointer type _composed_ of an other element type T).
So: P does not inherit any methods bound to T, but the method set of an element of the
composite type P remains unchanged. So, certainly, for a p of type P, (*p).m() is legal
since the type of *p is T and those methods remain unchanged (line 14).
According to http://golang.org/doc/go_spec.html#Types:
b) "The method set of any other named type T consists of all methods with receiver type
T. The method set of the corresponding pointer type *T is the set of all methods with
receiver *T or T (that is, it also contains the method set of T). Any other type has an
empty method set."
For P there are no methods with receiver type P (and they cannot be declared either, see
method declarations) and thus p.m() is illegal (line 13). Note that rule b talks about
the "method set of the _corresponding_ pointer type *T" where "corresponding" refers to
a "named type T" (which is P in our case, not *T!). We have a new type P and thus the
corresponding pointer type would be *P. I think my original interpretation was incorrect
(rule b was considered out of context).
To summarize:
1) bug117.go is a correct test case
2) The program above correctly reports an error, but the error message is wrong:
6g test.go
test.go:13: p.m undefined (type T has no field or method m)
It should say:
test.go:13: p.m undefined (type P has no field or method m)
3) The spec does not need to be adjusted; but it may benefit from clearer
explanations/examples.
@gopherbot

This comment has been minimized.

gopherbot commented Feb 8, 2011

Comment 8 by lstoakes:

Thanks for the clarification - I have updated my CL to correct this error message.
@rsc

This comment has been minimized.

Contributor

rsc commented Feb 11, 2011

Comment 9:

This issue was closed by revision b57ac97.

Status changed to Fixed.

@golang golang locked and limited conversation to collaborators Jun 24, 2016

This issue was closed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.