]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.18] cmd/compile: fix expression switches using type parameters
authorKeith Randall <khr@golang.org>
Thu, 10 Mar 2022 18:01:35 +0000 (10:01 -0800)
committerDmitri Shuralyov <dmitshur@golang.org>
Mon, 14 Mar 2022 16:21:37 +0000 (16:21 +0000)
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 <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
(cherry picked from commit 2e46a0a99768408c90cf4eeda3690831693fd8b2)
Reviewed-on: https://go-review.googlesource.com/c/go/+/391795
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ir/stmt.go
src/cmd/compile/internal/noder/stencil.go
test/typeparam/issue51522b.go [new file with mode: 0644]

index e7d0d873b781ef79e43fa81d2447a139a54cdea5..80bd205436c5fa7dfb9bac2f428224a373faf3d9 100644 (file)
@@ -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
index 9d17d5ffd1b61fa6e566e27fca36f5b9f10ee51d..cd586cab78444ed2d96ce366124b488dfd21845a 100644 (file)
@@ -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
        }
diff --git a/test/typeparam/issue51522b.go b/test/typeparam/issue51522b.go
new file mode 100644 (file)
index 0000000..47de578
--- /dev/null
@@ -0,0 +1,62 @@
+// run -gcflags=-G=3
+
+// 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))
+}