]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix conversions from TypeParam to interface
authorkorzhao <korzhao95@gmail.com>
Mon, 16 Aug 2021 14:25:47 +0000 (22:25 +0800)
committerRobert Griesemer <gri@golang.org>
Wed, 1 Sep 2021 16:45:26 +0000 (16:45 +0000)
If the TypeParam has all the methods of an interface, allow conversions from TypeParam to interface

Fixes #47708

Change-Id: I40a82a31f6ea9354130dbe3bcfc83537094bf12c
Reviewed-on: https://go-review.googlesource.com/c/go/+/342509
Reviewed-by: Dan Scales <danscales@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Dan Scales <danscales@google.com>
Trust: Keith Randall <khr@golang.org>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>

src/cmd/compile/internal/typecheck/subr.go
test/typeparam/issue47708.go [new file with mode: 0644]

index 541e1907c03a71f557c07e30bf53a561dcace979..4696b62cd2b863c5cf1b0d69a9bbc8921894e900 100644 (file)
@@ -740,9 +740,16 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
 
        if t.IsInterface() || t.IsTypeParam() {
                if t.IsTypeParam() {
-                       // A typeparam satisfies an interface if its type bound
-                       // has all the methods of that interface.
-                       t = t.Bound()
+                       // If t is a simple type parameter T, its type and underlying is the same.
+                       // If t is a type definition:'type P[T any] T', its type is P[T] and its
+                       // underlying is T. Therefore we use 't.Underlying() != t' to distinguish them.
+                       if t.Underlying() != t {
+                               CalcMethods(t)
+                       } else {
+                               // A typeparam satisfies an interface if its type bound
+                               // has all the methods of that interface.
+                               t = t.Bound()
+                       }
                }
                i := 0
                tms := t.AllMethods().Slice()
diff --git a/test/typeparam/issue47708.go b/test/typeparam/issue47708.go
new file mode 100644 (file)
index 0000000..261d6ef
--- /dev/null
@@ -0,0 +1,40 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 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
+
+import (
+       "fmt"
+)
+
+type FooType[T any] interface {
+       Foo(BarType[T])string
+}
+type BarType[T any] interface {
+       Bar(FooType[T])string
+}
+
+type Baz[T any] T
+func (l Baz[T]) Foo(v BarType[T]) string {
+       return v.Bar(l)
+}
+type Bob[T any] T
+func (l Bob[T]) Bar(v FooType[T]) string {
+       if v,ok := v.(Baz[T]);ok{
+               return fmt.Sprintf("%v%v",v,l)
+       }
+       return ""
+}
+
+
+func main() {
+       var baz Baz[int] = 123
+       var bob Bob[int] = 456
+
+       if got, want := baz.Foo(bob), "123456"; got != want {
+               panic(fmt.Sprintf("got %s want %s", got, want))
+       }
+}