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: a possible inconsistency for promoted methods #34454

Closed
dotaheor opened this issue Sep 22, 2019 · 5 comments
Closed

spec: a possible inconsistency for promoted methods #34454

dotaheor opened this issue Sep 22, 2019 · 5 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@dotaheor
Copy link

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

go version go1.13 linux/amd64

Does this issue reproduce with the latest release?

true

What did you do?

package main

type S struct{}

func (*S) F() {}

type T struct {
	*T
	*S
}

func (*T) M() {}

func main(){
	T{&T{}, &S{}}.F()   // no problem
	T{&T{}, &S{}}.S.F() // no problem
	T{&T{}, &S{}}.M()   // cannot take the address of T literal
	T{&T{}, &S{}}.T.M() // no problem
}

What did you expect to see?

All lines should compile.

What did you see instead?

One line fails to compile.

@dotaheor
Copy link
Author

dotaheor commented Sep 22, 2019

En, it looks the implementation is correct, it is consistent with reflection:

package main

import (
	"fmt"
	"reflect"
)

type S struct{}

func (*S) F() {}

type T struct {
	*T
	*S
}

func (*T) M() {}


func main(){
	T{}.F()   // no problem
	T{}.S.F() // no problem
	//T{}.M()   // cannot take the address of T literal
	T{}.T.M() // no problem
	
	_ = T{}.F   // no problem
	//_ = T{}.M // cannot take the address of T literal
	
	// <invalid reflect.Value>
	fmt.Println(reflect.ValueOf(T{}).MethodByName("M"))
	// {  <nil> <invalid Value> 0} false
	fmt.Println(reflect.TypeOf(T{}).MethodByName("M"))
	// 1
	fmt.Println(reflect.TypeOf(T{}).NumMethod())
	// {F  func(main.T) <func(main.T) Value> 0}
	fmt.Println(reflect.TypeOf(T{}).Method(0))
	
	_, ok := (interface{}(T{})).(interface{M()})
	fmt.Println(ok) // false
}

Maybe, a small adjustment is needed in spec?

If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.

A simpler example with names used in spec:

package main

import (
	"fmt"
	"reflect"
)

type S struct {
	T
}

func (*S) M() {}

type T struct{}

func (T) M() {}

func main(){
	//S{}.M() // cannot take the address of T literal
	
	//_ = S{}.M // cannot take the address of T literal

	fmt.Println(reflect.TypeOf(S{}).NumMethod())  // 0
	fmt.Println(reflect.TypeOf(&S{}).NumMethod()) // 1
}

@ianlancetaylor
Copy link
Contributor

In the final example I think you are suggesting that S should inherit the method M from the embedded field T, even though there is a method M on *S. I think it's clear that the language is not intended to permit that. It's possible that the spec does not clearly state that. I think the place to state it would be https://golang.org/ref/spec#Selectors.

CC @griesemer

@ianlancetaylor ianlancetaylor changed the title cmd/go: a small inconsistency spec: a possible inconsistency for promoted methods Sep 23, 2019
@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Sep 23, 2019
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Sep 23, 2019
@dotaheor
Copy link
Author

@ianlancetaylor Yes, I agree.

It looks the current design views S{}.M as a legal but invalid selector. However I haven't found how the spec distinguishes "legal" from "valid" for selectors.

@griesemer griesemer self-assigned this Sep 23, 2019
@mdempsky
Copy link
Member

I think this is a dup of #15708. In particular, I think this is my first example here.

@dotaheor
Copy link
Author

I agree this is a dup of #15708, so close it.

Maybe it is good to add a complement in the https://golang.org/ref/spec#Selectors section

For a primary expression x (always assume it is addressable) that is not a package name, the selector expression ....

@golang golang locked and limited conversation to collaborators Sep 22, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants