What version of Go are you using (go version
)?
go version devel +68c7cb25a7 Wed Apr 4 12:18:29 2018 +0100 darwin/amd64
Does this issue reproduce with the latest release?
Yes (go version go1.10.1 darwin/amd64).
What did you do?
Compiled https://play.golang.org/p/jzbFN6k7Jhk
What did you expect to see?
./const.go:10:7: const initializer I((*T)(nil)) is not a constant
What did you see instead?
./const.go:10:12: cannot convert (*T)(nil) (type *T) to type I:
*T does not implement I (missing F method)
*T
does implement I
so this error message is wrong. The real issue is that the RHS is not a valid constant.
Note that the correct error message is shown if the declaration of F()
is moved to be above the assertion in the file (i.e. https://play.golang.org/p/9f2SQfBfteA). If the const
is changed to var
then the program compiles correctly regardless of where F is declared.
Comment From: mvdan
go/types
gets this right, which further confirms your thinking:
f.go:10:11: I((*T)(nil)) (value of type I) is not constant
Comment From: odeke-em
Thank you for reporting this @mundaym
/cc @mdempsky @griesemer
Comment From: mvdan
Smaller repro:
package p
type I interface{ F() }
type T struct{}
const _ = I(T{})
func (T) F() {}
Comment From: mvdan
The issue seems to stem from how gc is designed. Reading main.go
, I see how it typechecks nodes in phases:
// Phase 1: const, type, and names and types of funcs.
[...]
// Phase 2: Variable assignments.
So it seems to me like a possible fix would be to insert an extra phase before "variable assignments" called "constant declarations". That way, in our example above, func (T) F()
would always be typechecked before const _ = I(T{})
.
@griesemer @mdempsky thoughts? Is there a better way to fix this issue? (Edit: ended up sending this as a CL - see below)
Comment From: mvdan
I guess that another potential fix would be to detect if we're in phase 1 in the typechecker, and avoid giving errors like missing F method
. After all, there is no guarantee that all methods have been typechecked and added to their respective types until we're past that phase. But it seems like special-casing all these errors would be a game of whack-a-mole.
Comment From: gopherbot
Change https://golang.org/cl/115096 mentions this issue: cmd/compile: typecheck types and funcs before consts
Comment From: griesemer
Let's leave this alone for 1.11. It's more subtle that it seems (see my comments on the issue) and it's definitively not urgent.
Comment From: mdempsky
Sorry I missed this issue and CL until now.
I'm not convinced the committed fix fully addresses this. Typechecking package-scope declarations can't really be split into phases; there's always a way to construct code that depends on any particular kind of declaration being typechecked before any other.
E.g., this test case still repros the issue:
package p
import "unsafe"
type x [unsafe.Sizeof(w)]int
type I interface{ F() }
type T struct{}
const w = I(T{})
func (T) F() {}
(And as a more superficial issue, there are now two phase "3"s in main.go.)
Comment From: griesemer
@mdempsky Agreed, I have also mentioned this in the CL (but the quick test case I tried to create didn't produce an error - see my CL feedback).
Comment From: griesemer
Simpler repro (no need for "unsafe"), same error besides otherwise being incorrect:
package p
type x [w]int
type I interface{ F() }
type T struct{}
const w = I(T{})
func (T) F() {}
I'm going to roll back the change.
Comment From: gopherbot
Change https://golang.org/cl/145617 mentions this issue: cmd/compile: revert "typecheck types and funcs before consts"
Comment From: mdempsky
For what it's worth, while simply typechecking var/type/func declarations separately from const declarations doesn't work, I think the idea I sketched in #13890 to separate package-scope typechecking into "type resolution" and "constant evaluation" phases would work here.
Comment From: mvdan
Thanks for the follow-up - looking forward to seeing what a better fix would be like :)
Comment From: griesemer
Too late for 1.12.
Comment From: mundaym
Not sure when this got fixed but the Go playground example now gives the correct error message. Closing this.
Comment From: mdempsky
I don't think it does? I'm still seeing the wrong error message ("does not implement") at https://play.golang.org/p/jzbFN6k7Jhk.
Comment From: mundaym
Sorry, yes you're right, I looked at the wrong link.
Comment From: gopherbot
Change https://go.dev/cl/613115 mentions this issue: test: add test for issue 24755