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