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

cmd/compile: incorrect error message for types check in generic functions #59312

Closed
Dmitriy-Kulagin opened this issue Mar 29, 2023 · 3 comments
Closed
Assignees
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@Dmitriy-Kulagin
Copy link

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

$ go version
go version go1.20.2 linux/amd64

Does this issue reproduce with the latest release?

Yes, at lest in go.1.18

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build674946051=/tmp/go-build -gno-record-gcc-switches"

What did you do?

GO code:
package main

import "fmt"

type values interface {
string | int | bool
}

func checkValue[T values](v T, check func(value T) bool) bool {
return check(v)
}

func main() {
v := 0.1 // float
f := func(value string) bool { return true }
fmt.Print(checkValue(v, f))
}

// the same code in playground: https://go.dev/play/p/DHjAFwEoEnn?v=goprev

What did you expect to see?

Error message about wrong type of the first argument v as float64 is not a part of type values.

What did you see instead?

Compile error:

go build
# demo
./main.go:16:26: type func(value string) bool of f does not match inferred type func(value float64) bool for func(value T) bool

It is wrong and very confusing error message as function has correct type. Type of its parameter compared with the first parameter type instead of comparison to type values.

In opposite: the v argument has incorrect type (according to type values definition) but this is not reported as error.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Mar 29, 2023
@ianlancetaylor
Copy link
Contributor

CC @griesemer

The error message is correct, but perhaps we can produce a better message in this case. It seems that we are reporting an argument type mismatch before we report a constraint failure.

@mknyszek mknyszek added this to the Backlog milestone Mar 29, 2023
@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Mar 29, 2023
@Dmitriy-Kulagin
Copy link
Author

@ianlancetaylor I can't agree that the error message is correct. It made me little bit crazy and burned about half an hour of my work time to understand what is exactly wrong and how to fix it. Just imagine little bit more difficult code. And try to explain how I should understand the real reason of issue with code having such miss-pointing error message.

For generic functions the type constraints have to be performed before or in additional to check of argument type mismatch. Other way there is no way to produce the correct error message.

@griesemer
Copy link
Contributor

@Dmitriy-Kulagin In general, we cannot check constraints before we have all type arguments (because constraints may be parameterized with type parameters). This order is explicitly specified in the spec:

Instantiation proceeds in two steps:

  1. Each type argument is substituted for its corresponding type parameter in the generic declaration. This substitution happens across the entire function or type declaration, including the type parameter list itself and any types in that list.

  2. After substitution, each type argument must satisfy the constraint (instantiated, if necessary) of the corresponding type parameter. Otherwise instantiation fails.

That is, step 1 happens first. For that to happen, we first need to determine all type arguments.

The error happens when we determine the type arguments, and the error is correct. It's also fairly easy to read:

type func(value string) bool of f does not match inferred type func(value float64) bool for func(value T) bool

The inferred type for func(value T) bool is explicitly given as type func(value float64) bool. It's easy to see that this type was inferred from the 1st argument to checkValue, that argument has type float64. And clearly, the two function types don't match.

You are (implicitly) saying that the error should be something like:

cannot use v (of type float64) as type argument, v doesn't satisfy constraint

This may be easier to understand for you in this case, but it would require special-case handling (need to check if the constraints are parameterized). This may be possible but will slow down the usual (correct) case. Going forward, as we make type inference more powerful, it will become more and more difficult (type parameters may also appear on the argument side) for little benefit. It may also introduce subtle bugs because we are deviating from the spec (which is directly guided by what the type theory behind generics says is correct).

Most importantly, the code is incorrect either way. From the current message it's easy to see that the float64 value parameter doesn't match the string value parameter. So make that string and things will work.

Closing as working as intended.

@golang golang locked and limited conversation to collaborators Mar 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. 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