Go version

go version devel go1.23-619b419a4b Sun May 5 00:26:04 2024 +0000 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/tmp/go-build'
GOENV='/home/hugo/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/hugo/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/hugo/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/hugo/k/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/home/hugo/k/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='devel go1.23-619b419a4b Sun May 5 00:26:04 2024 +0000'
GODEBUG=''
GCCGO='/usr/bin/gccgo'
GOAMD64='v3'
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 -ffile-prefix-map=/tmp/go-build988502288=/tmp/go-build -gno-record-gcc-switches'

What did you do?

@LeaBit on discord gophers report this behavior:

package main

import "fmt"

func main() {
    ch1 := make(chan struct{})

    var ch2 <-chan struct{} = ch1

    switch ch1 {
    case ch2:
        fmt.Println("Narrow case: Same!")
    default:
        fmt.Println("Narrow case: Not same!")
    }

    switch ch2 {
    case ch1:
        fmt.Println("Narrow switch: Same!")
    default:
        fmt.Println("Narrow switch: Not same!")
    }

    fmt.Println("Equal:", ch1 == ch2)
}

What did you see happen?

Narrow case: Not same!
Narrow switch: Same!
Equal: true

What did you expect to see?

Narrow case: Same!
Narrow switch: Same!
Equal: true

Comment From: Jorropo

cc @golang/compiler

Comment From: randall77

The behavior changed from 1.19 to 1.20. A bisect would be helpful to track down the cause.

Comment From: Jorropo

I'll send a fix

Comment From: Jorropo

Bisect results: - 833367e98af838a2511ee7e4e19dc8f1da7b8ed7 - rebisecting with -gcflags=-d=unified gives a4c5198a3c8befa2f126fd365de4dc09c32b7886

Comment From: Jorropo

Ok so the bug, this code assumes that the type of the case can't be assigned to the type of the tag it needs to compared with any and comparing with any first compare using the exact type tag (which is wrong because you can't assign <-chan T to chan T but you can == them).

ch1 := make(chan struct{})
var ch2 <-chan struct{} = ch1
fmt.Println("Equal:", ch1 == ch2)
fmt.Println("any Equal:", any(ch1) == any(ch2))

prints true and false, I don't know if this is a bug or intended.

Comment From: Jorropo

It looks like the any compare behavior is correct:

Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

so TIL a == b has different semantics as any(a) == any(b)

https://gophers.slack.com/archives/C1C1YSQBT/p1714960380488909

Comment From: cuonglm

Possibly duplicate of https://github.com/golang/go/issues/44051

Comment From: Jorropo

I don't think so, here I'm assuming the behavior seen in #44051 is correct and not a bug yet this is still broken.

Comment From: gopherbot

Change https://go.dev/cl/583395 mentions this issue: Revert "[dev.unified] cmd/compile/internal/noder: better switch statements"

Comment From: Jorropo

Needs more changes in cmd/walk/switch.go to achieve what I want, it's tricky, someone else should make sure to do it right.

Comment From: gopherbot

Change https://go.dev/cl/594575 mentions this issue: cmd/compile: fix mis-compilation when switching over channels

Comment From: gopherbot

Change https://go.dev/cl/596575 mentions this issue: cmd/compile: fix mis-compilation when switching over channels