Skip to content

Commit

Permalink
cmd/compile: fix expression switches using type parameters
Browse files Browse the repository at this point in the history
Both the thing we're switching on, as well as the cases we're switching for.
Convert anything containing a type parameter to interface{} before the
comparison happens.

Fixes #51522

Change-Id: I97ba9429ed332cb7d4240cb60f46d42226dcfa5f
Reviewed-on: https://go-review.googlesource.com/c/go/+/391594
Trust: Keith Randall <[email protected]>
Run-TryBot: Keith Randall <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
Reviewed-by: Matthew Dempsky <[email protected]>
  • Loading branch information
randall77 committed Mar 10, 2022
1 parent 8cf1169 commit 2e46a0a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/ir/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
return n
}

// A SwitchStmt is a switch statement: switch Init; Expr { Cases }.
// A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
type SwitchStmt struct {
miniStmt
Tag Node
Expand Down
20 changes: 20 additions & 0 deletions src/cmd/compile/internal/noder/stencil.go
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))

case ir.OSWITCH:
m := m.(*ir.SwitchStmt)
if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
break // Nothing to do here for type switches.
}
if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() {
// To implement a switch on a value that is or has a type parameter, we first convert
// that thing we're switching on to an interface{}.
m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
}
for _, c := range m.Cases {
for i, x := range c.List {
// If we have a case that is or has a type parameter, convert that case
// to an interface{}.
if !x.Type().IsInterface() && x.Type().HasShape() {
c.List[i] = assignconvfn(x, types.Types[types.TINTER])
}
}
}

}
return m
}
Expand Down
62 changes: 62 additions & 0 deletions test/typeparam/issue51522b.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// run

// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func f[T comparable](i any) {
var t T

switch i {
case t:
// ok
default:
println("FAIL: switch i")
}

switch t {
case i:
// ok
default:
println("FAIL: switch t")
}
}

type myint int

func (m myint) foo() {
}

type fooer interface {
foo()
}

type comparableFoo interface {
comparable
foo()
}

func g[T comparableFoo](i fooer) {
var t T

switch i {
case t:
// ok
default:
println("FAIL: switch i")
}

switch t {
case i:
// ok
default:
println("FAIL: switch t")
}
}

func main() {
f[int](0)
g[myint](myint(0))
}

0 comments on commit 2e46a0a

Please sign in to comment.