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

go/types: errors when declaring methods with type alias receivers #23042

Closed
mdempsky opened this issue Dec 7, 2017 · 5 comments
Closed

go/types: errors when declaring methods with type alias receivers #23042

mdempsky opened this issue Dec 7, 2017 · 5 comments

Comments

@mdempsky
Copy link
Member

@mdempsky mdempsky commented Dec 7, 2017

cmd/compile accepts this package:

package p

type T struct{}

var _ = T.m
var _ = T{}.m
var _ interface{m()} = T{}

type U = T
func (U) m()

but go/types rejects it with:

r.go:5:9: invalid operation: T (type) has no field or method m
r.go:6:9: invalid operation: (T literal) (value of type T) has no field or method m
r.go:7:24: cannot use (T literal) (value of type T) as interface{m()} value in variable declaration: missing method m

Notably, if you move the type alias and method declaration above the variable declarations, go/types accepts it.

It's worth noting that gccgo actually crashes on the method declaration with

go1: internal compiler error: in add_method_declaration, at go/gofrontend/types.cc:9759

It makes me wonder a little if we should just require that methods be directly associated with the actual receiver type. Rationale:

  1. The spec says "The type denoted by T is called the receiver base type; it must not be a pointer or interface type and it must be defined in the same package as the method." It links to "defined type", which is disjoint from type aliases, so arguably the spec doesn't allow methods declared on type aliases anyway.

  2. Since we can only declare methods on types declared in the same package anyway, there's not much to be gained by allowed method declarations on type aliases.

/cc @griesemer @ianlancetaylor

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Dec 8, 2017

The alias proposal at https://github.com/golang/proposal/blob/master/design/18130-type-alias.md specifically permits declaring methods using either type.

Since T1 is just another way to write T2, it does not have its own set of method declarations. Instead, T1’s method set is the same as T2’s. At least for the initial trial, there is no restriction against method declarations using T1 as a receiver type, provided using T2 in the same declaration would be valid. Note that if T1 is an alias for a type T2 defined in an imported package, method declarations using T1 as a receiver type are invalid, just as method declarations using T2 as a receiver type are invalid.

Loading

@griesemer griesemer self-assigned this Dec 8, 2017
@griesemer griesemer added this to the Go1.11 milestone Dec 8, 2017
@griesemer
Copy link
Contributor

@griesemer griesemer commented Dec 8, 2017

I think the original intent for alias type names was that this should work. Since cmd/compile accepts it, I would say this is a go/types bug (and perhaps the spec could be clearer).

Loading

@griesemer
Copy link
Contributor

@griesemer griesemer commented Dec 13, 2017

@mdempsky Regarding the spec's prose: "The type denoted by T is called the receiver base type; it must not be a pointer or interface type and it must be defined in the same package as the method."
"Defined" refers to the type, not the type name. An alias (type name) may still denote a defined type. So I think the spec is correct here.

Loading

@mdempsky
Copy link
Member Author

@mdempsky mdempsky commented Dec 13, 2017

@griesemer I suppose these sentences are where my confusion really come from:

That parameter section must declare a single non-variadic parameter, the receiver. Its type must be of the form T or *T (possibly using parentheses) where T is a type name.

The "possibly using parentheses" phrasing suggests to me the "form" we're talking about is syntactic, not structural. And so "T" appears to refer to the literal type name appearing in the method declaration's receiver parameter type.

Loading

@gopherbot
Copy link

@gopherbot gopherbot commented Dec 14, 2017

Change https://golang.org/cl/83996 mentions this issue: go/types: don't associate methods with alias type names

Loading

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants