]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: prevent importReader reading type parameter twice
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 10 Sep 2021 00:44:02 +0000 (07:44 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Tue, 14 Sep 2021 02:52:21 +0000 (02:52 +0000)
The importReader always reads type parameter before declaring type stub
declaration. Thus, for recursive type, the type parameter is going to be
read twice, cause the bound more than once error.

To fix this, only read the type parameter after declaring stub obj, thus
r.doDecl can see the type was already inserted and terminate the
recursive call earlier.

Fixes #48280

Change-Id: I272e2f214f739fb8ec71a8628ba297477e1b7755
Reviewed-on: https://go-review.googlesource.com/c/go/+/349009
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
src/cmd/compile/internal/importer/iimport.go
test/typeparam/issue48280.dir/a.go [new file with mode: 0644]
test/typeparam/issue48280.dir/main.go [new file with mode: 0644]
test/typeparam/issue48280.go [new file with mode: 0644]

index b61b1e97fb7cf3f028fbb231c3957afaf66d5ce9..7f7143dcfe7bd34145e8f88fa5e4eab302b08c81 100644 (file)
@@ -318,17 +318,17 @@ func (r *importReader) obj(name string) {
                r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
 
        case 'T', 'U':
-               var tparams []*types2.TypeParam
-               if tag == 'U' {
-                       tparams = r.tparamList()
-               }
-
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
                obj := types2.NewTypeName(pos, r.currPkg, name, nil)
                named := types2.NewNamed(obj, nil, nil)
-               named.SetTypeParams(tparams)
+               // Declare obj before calling r.tparamList, so the new type name is recognized
+               // if used in the constraint of one of its own typeparams (see #48280).
                r.declare(obj)
+               if tag == 'U' {
+                       tparams := r.tparamList()
+                       named.SetTypeParams(tparams)
+               }
 
                underlying := r.p.typAt(r.uint64(), named).Underlying()
                named.SetUnderlying(underlying)
diff --git a/test/typeparam/issue48280.dir/a.go b/test/typeparam/issue48280.dir/a.go
new file mode 100644 (file)
index 0000000..17859e6
--- /dev/null
@@ -0,0 +1,11 @@
+// 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 a
+
+type I[T I[T]] interface {
+       F() T
+}
+
+type S struct{}
diff --git a/test/typeparam/issue48280.dir/main.go b/test/typeparam/issue48280.dir/main.go
new file mode 100644 (file)
index 0000000..b9981c6
--- /dev/null
@@ -0,0 +1,11 @@
+// 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 "a"
+
+func main() {
+       _ = a.S{}
+}
diff --git a/test/typeparam/issue48280.go b/test/typeparam/issue48280.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -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 ignored