]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix case where g.curDecl should be saved/restored
authorDan Scales <danscales@google.com>
Wed, 1 Dec 2021 18:53:17 +0000 (10:53 -0800)
committerDan Scales <danscales@google.com>
Thu, 2 Dec 2021 07:04:05 +0000 (07:04 +0000)
When we set g.curDecl for the type params created during fillinMethods
for an instantiated type, we need to save/restore its value, because
fillinMethods() may be called while processing a typeDecl. We want the
value of g.curDecl to continue to be correct for type params created in
the typeDecl. Because of ordering issues, not restoring g.curDecl
happens to cause problems (which don't always show up visibly) exactly
when a type param is not actually used in a type declaration.

Cleared g.curDecl to "" at the later points in typeDecl() and
funcDecl(). This allows adding asserts that g.curDecl is always empty
("") when we set it in typeDecl() and funcDecl(), and always non-empty
when we use it in typ0().

Fixes #49893

Change-Id: Ic2fb1df791585bd257f2b86ffaae0453c31705c5
Reviewed-on: https://go-review.googlesource.com/c/go/+/368454
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/noder/decl.go
src/cmd/compile/internal/noder/types.go
test/typeparam/issue49893.dir/a.go [new file with mode: 0644]
test/typeparam/issue49893.dir/b.go [new file with mode: 0644]
test/typeparam/issue49893.dir/main.go [new file with mode: 0644]
test/typeparam/issue49893.go [new file with mode: 0644]

index 0143fd3d457b6cc84037b85111819c743733dad6..027c8598fd57f118b3bc3a25c8ef3266966864b6 100644 (file)
@@ -86,6 +86,7 @@ func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
 }
 
 func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
+       assert(g.curDecl == "")
        // Set g.curDecl to the function name, as context for the type params declared
        // during types2-to-types1 translation if this is a generic function.
        g.curDecl = decl.Name.Value
@@ -133,6 +134,7 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
        }
 
        haveEmbed := g.haveEmbed
+       g.curDecl = ""
        g.later(func() {
                defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
 
@@ -158,6 +160,7 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
 }
 
 func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
+       assert(g.curDecl == "")
        // Set g.curDecl to the type name, as context for the type params declared
        // during types2-to-types1 translation if this is a generic type.
        g.curDecl = decl.Name.Value
@@ -167,6 +170,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
                assert(name.Alias()) // should be set by irgen.obj
 
                out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
+               g.curDecl = ""
                return
        }
 
@@ -219,6 +223,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
        }
        types.ResumeCheckSize()
 
+       g.curDecl = ""
        if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
                methods := make([]*types.Field, otyp.NumMethods())
                for i := range methods {
@@ -229,6 +234,7 @@ func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
                        meth := g.obj(m)
                        methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
                        methods[i].Nname = meth
+                       g.curDecl = ""
                }
                ntyp.Methods().Set(methods)
        }
index fa24ab18442011ac568b5e3f800ac6ab7ce3ed6e..4f6d8287201d4b685c3a8822b57e6b6f6b3f7ab8 100644 (file)
@@ -229,6 +229,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                pkg := g.tpkg(typ)
                // Create the unique types1 name for a type param, using its context with a
                // function, type, or method declaration.
+               assert(g.curDecl != "")
                nm := g.curDecl + "." + typ.Obj().Name()
                sym := pkg.Lookup(nm)
                if sym.Def != nil {
@@ -331,11 +332,15 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
                                tparams := make([]*types.Type, rparams.Len())
                                // Set g.curDecl to be the method context, so type
                                // params in the receiver of the method that we are
-                               // translating gets the right unique name.
+                               // translating gets the right unique name. We could
+                               // be in a top-level typeDecl, so save and restore
+                               // the current contents of g.curDecl.
+                               savedCurDecl := g.curDecl
                                g.curDecl = typ.Obj().Name() + "." + m.Name()
                                for i := range tparams {
                                        tparams[i] = g.typ1(rparams.At(i))
                                }
+                               g.curDecl = savedCurDecl
                                assert(len(tparams) == len(targs))
                                ts := typecheck.Tsubster{
                                        Tparams: tparams,
diff --git a/test/typeparam/issue49893.dir/a.go b/test/typeparam/issue49893.dir/a.go
new file mode 100644 (file)
index 0000000..bc810cd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 Option[T any] interface {
+       ToSeq() Seq[T]
+}
+
+type Seq[T any] []T
+
+func (r Seq[T]) Find(p func(v T) bool) Option[T] {
+       panic("")
+}
diff --git a/test/typeparam/issue49893.dir/b.go b/test/typeparam/issue49893.dir/b.go
new file mode 100644 (file)
index 0000000..b36f6bd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 b
+
+import "a"
+
+type Ap1[A, B any] struct {
+       opt a.Option[A]
+}
+
+type Ap2[A, B any] struct {
+       opt a.Option[A]
+}
diff --git a/test/typeparam/issue49893.dir/main.go b/test/typeparam/issue49893.dir/main.go
new file mode 100644 (file)
index 0000000..8b5b3bd
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 (
+       "b"
+       "fmt"
+)
+
+func main() {
+       opt := b.Ap1[string, string]{}
+       fmt.Println(opt)
+}
diff --git a/test/typeparam/issue49893.go b/test/typeparam/issue49893.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -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