]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: use dictionary to convert type to shaped interface type
authorWayne Zuo <wdvxdr@golangcn.org>
Tue, 19 Apr 2022 13:24:33 +0000 (21:24 +0800)
committerGopher Robot <gobot@golang.org>
Tue, 3 May 2022 21:36:22 +0000 (21:36 +0000)
When we convert a type to a shaped interface type, we are not able
to recognize the itab. So passing the itab by dictionary as the
workaround.

Fixes #52026.

Change-Id: I75c23c7dd215daf9761dc24116a8af2c28c6d948
Reviewed-on: https://go-review.googlesource.com/c/go/+/401034
Run-TryBot: Wayne Zuo <wdvxdr@golangcn.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/noder/stencil.go
test/typeparam/issue52026.go [new file with mode: 0644]

index 51ef6b1ff1b3b6d87d376d0f38d0064ee1cbd8ca..c57a8760c75ee6c98266bf9932344b2786d15fe1 100644 (file)
@@ -1325,8 +1325,8 @@ func (g *genInst) dictPass(info *instInfo) {
                        mce := m.(*ir.ConvExpr)
                        // Note: x's argument is still typed as a type parameter.
                        // m's argument now has an instantiated type.
-                       if mce.X.Type().HasShape() || (mce.X.Type().IsInterface() && m.Type().HasShape()) {
-                               m = convertUsingDictionary(info, info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, m, m.Type())
+                       if mce.X.Type().HasShape() || m.Type().HasShape() {
+                               m = convertUsingDictionary(info, info.dictParam, m.Pos(), mce.X, m, m.Type())
                        }
                case ir.ODOTTYPE, ir.ODOTTYPE2:
                        if !m.Type().HasShape() {
@@ -1420,7 +1420,7 @@ func findDictType(info *instInfo, t *types.Type) int {
 // instantiated node of the CONVIFACE node or XDOT node (for a bound method call) that is causing the
 // conversion.
 func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type) ir.Node {
-       assert(v.Type().HasShape() || v.Type().IsInterface() && in.Type().HasShape())
+       assert(v.Type().HasShape() || in.Type().HasShape())
        assert(dst.IsInterface())
 
        if v.Type().IsInterface() {
@@ -1799,6 +1799,7 @@ func (g *genInst) finalizeSyms() {
                                g.instantiateMethods()
                                itabLsym := reflectdata.ITabLsym(srctype, dsttype)
                                d.off = objw.SymPtr(lsym, d.off, itabLsym, 0)
+                               markTypeUsed(srctype, lsym)
                                infoPrint(" + Itab for (%v,%v)\n", srctype, dsttype)
                        }
                }
@@ -1974,7 +1975,7 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI
                        }
                case ir.OCONVIFACE:
                        if n.Type().IsInterface() && !n.Type().IsEmptyInterface() &&
-                               n.(*ir.ConvExpr).X.Type().HasShape() {
+                               (n.Type().HasShape() || n.(*ir.ConvExpr).X.Type().HasShape()) {
                                infoPrint("  Itab for interface conv: %v\n", n)
                                info.itabConvs = append(info.itabConvs, n)
                        }
diff --git a/test/typeparam/issue52026.go b/test/typeparam/issue52026.go
new file mode 100644 (file)
index 0000000..db8999a
--- /dev/null
@@ -0,0 +1,50 @@
+// 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 returnOption[T any](n int) Option[T] {
+       if n == 1 {
+               return Some[T]{}
+       } else {
+               return None{}
+       }
+}
+
+type Option[T any] interface {
+       sealedOption()
+}
+
+type Some[T any] struct {
+       val T
+}
+
+func (s Some[T]) Value() T {
+       return s.val
+}
+
+func (s Some[T]) sealedOption() {}
+
+type None struct{}
+
+func (s None) sealedOption() {}
+
+func main() {
+       s := returnOption[int](1)
+       _ = s.(Some[int])
+
+       s = returnOption[int](0)
+       _ = s.(None)
+
+       switch (any)(s).(type) {
+       case Some[int]:
+               panic("s is a Some[int]")
+       case None:
+               // ok
+       default:
+               panic("oops")
+       }
+}