Skip to content

Commit 2c6a889

Browse files
randall77dmitshur
authored andcommitted
[release-branch.go1.18] cmd/compile: fix expression switches using type parameters
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]> (cherry picked from commit 2e46a0a) Reviewed-on: https://go-review.googlesource.com/c/go/+/391795 Trust: Dmitri Shuralyov <[email protected]> Run-TryBot: Dmitri Shuralyov <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 1edc1cc commit 2c6a889

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

src/cmd/compile/internal/ir/stmt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
362362
return n
363363
}
364364

365-
// A SwitchStmt is a switch statement: switch Init; Expr { Cases }.
365+
// A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
366366
type SwitchStmt struct {
367367
miniStmt
368368
Tag Node

src/cmd/compile/internal/noder/stencil.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
11791179
subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
11801180
m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
11811181

1182+
case ir.OSWITCH:
1183+
m := m.(*ir.SwitchStmt)
1184+
if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
1185+
break // Nothing to do here for type switches.
1186+
}
1187+
if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() {
1188+
// To implement a switch on a value that is or has a type parameter, we first convert
1189+
// that thing we're switching on to an interface{}.
1190+
m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
1191+
}
1192+
for _, c := range m.Cases {
1193+
for i, x := range c.List {
1194+
// If we have a case that is or has a type parameter, convert that case
1195+
// to an interface{}.
1196+
if !x.Type().IsInterface() && x.Type().HasShape() {
1197+
c.List[i] = assignconvfn(x, types.Types[types.TINTER])
1198+
}
1199+
}
1200+
}
1201+
11821202
}
11831203
return m
11841204
}

test/typeparam/issue51522b.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func f[T comparable](i any) {
10+
var t T
11+
12+
switch i {
13+
case t:
14+
// ok
15+
default:
16+
println("FAIL: switch i")
17+
}
18+
19+
switch t {
20+
case i:
21+
// ok
22+
default:
23+
println("FAIL: switch t")
24+
}
25+
}
26+
27+
type myint int
28+
29+
func (m myint) foo() {
30+
}
31+
32+
type fooer interface {
33+
foo()
34+
}
35+
36+
type comparableFoo interface {
37+
comparable
38+
foo()
39+
}
40+
41+
func g[T comparableFoo](i fooer) {
42+
var t T
43+
44+
switch i {
45+
case t:
46+
// ok
47+
default:
48+
println("FAIL: switch i")
49+
}
50+
51+
switch t {
52+
case i:
53+
// ok
54+
default:
55+
println("FAIL: switch t")
56+
}
57+
}
58+
59+
func main() {
60+
f[int](0)
61+
g[myint](myint(0))
62+
}

0 commit comments

Comments
 (0)