From 500d75a5557c156808ad7afb78c0fa7c85b5832d Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 19 Apr 2022 21:24:33 +0800 Subject: [PATCH] [release-branch.go1.18] cmd/compile: use dictionary to convert type to shaped interface type 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 #52691. Change-Id: I75c23c7dd215daf9761dc24116a8af2c28c6d948 Reviewed-on: https://go-review.googlesource.com/c/go/+/401034 Run-TryBot: Wayne Zuo TryBot-Result: Gopher Robot Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: David Chase Reviewed-by: Keith Randall Reviewed-on: https://go-review.googlesource.com/c/go/+/403934 Reviewed-by: Than McIntosh Run-TryBot: Keith Randall --- src/cmd/compile/internal/noder/stencil.go | 10 +++-- test/typeparam/issue52026.go | 50 +++++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 test/typeparam/issue52026.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 4ba69469a6..39185ad7f4 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1288,8 +1288,9 @@ 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(), false) + + if mce.X.Type().HasShape() || m.Type().HasShape() { + m = convertUsingDictionary(info, info.dictParam, m.Pos(), mce.X, m, m.Type(), false) } case ir.ODOTTYPE, ir.ODOTTYPE2: if !m.Type().HasShape() { @@ -1385,7 +1386,7 @@ func findDictType(info *instInfo, t *types.Type) int { // If nonEscaping is true, the caller guarantees that the backing store needed for the interface data // word will not escape. func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type, nonEscaping bool) 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() { @@ -1764,6 +1765,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) } } @@ -1914,7 +1916,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 index 0000000000..946924bcbe --- /dev/null +++ b/test/typeparam/issue52026.go @@ -0,0 +1,50 @@ +// 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 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") + } +} -- 2.50.0