]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix crawler for unexported fields with instantiated types
authorDan Scales <danscales@google.com>
Sun, 19 Sep 2021 03:02:08 +0000 (20:02 -0700)
committerDan Scales <danscales@google.com>
Fri, 24 Sep 2021 18:21:14 +0000 (18:21 +0000)
In markType() in crawler.go, mark the type of a unexported field if it
is a fully-instantiated type, since we create and instantiate the
methods of any fully-instantiated type that we see during import. As
before, we still do not mark the type of an unexported field if that
type is not generic. Fixes #48454 and most recent issue described in
48337. The included test is similar to the case in 48454.

Fixes #48454
Fixes #48337

Change-Id: I77a2a62b9e2647876facfa6f004201e8f699c905
Reviewed-on: https://go-review.googlesource.com/c/go/+/351315
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/typecheck/crawler.go
test/typeparam/issue48454.dir/a.go [new file with mode: 0644]
test/typeparam/issue48454.dir/b.go [new file with mode: 0644]
test/typeparam/issue48454.dir/main.go [new file with mode: 0644]
test/typeparam/issue48454.go [new file with mode: 0644]

index 3f212aa805a4a8e50db46f34803ec503acd35fc5..667e76e1305d924813b806f402cc7a628bbcd9de 100644 (file)
@@ -10,10 +10,12 @@ import (
        "cmd/compile/internal/types"
 )
 
-// crawlExports crawls the type/object graph rooted at the given list
-// of exported objects. Any functions that are found to be potentially
-// callable by importers are marked with ExportInline so that
-// iexport.go knows to re-export their inline body.
+// crawlExports crawls the type/object graph rooted at the given list of exported
+// objects. It descends through all parts of types and follows any methods on defined
+// types. Any functions that are found to be potentially callable by importers are
+// marked with ExportInline, so that iexport.go knows to re-export their inline body.
+// Also, any function or global referenced by a function marked by ExportInline() is
+// marked for export (whether its name is exported or not).
 func crawlExports(exports []*ir.Name) {
        p := crawler{
                marked:   make(map[*types.Type]bool),
@@ -29,7 +31,7 @@ type crawler struct {
        embedded map[*types.Type]bool // types already seen by markEmbed
 }
 
-// markObject visits a reachable object.
+// markObject visits a reachable object (function, method, global type, or global variable)
 func (p *crawler) markObject(n *ir.Name) {
        if n.Op() == ir.ONAME && n.Class == ir.PFUNC {
                p.markInlBody(n)
@@ -97,7 +99,12 @@ func (p *crawler) markType(t *types.Type) {
                        break
                }
                for _, f := range t.FieldSlice() {
-                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
+                       // Mark the type of a unexported field if it is a
+                       // fully-instantiated type, since we create and instantiate
+                       // the methods of any fully-instantiated type that we see
+                       // during import (see end of typecheck.substInstType).
+                       if types.IsExported(f.Sym.Name) || f.Embedded != 0 ||
+                               isPtrFullyInstantiated(f.Type) {
                                p.markType(f.Type)
                        }
                }
@@ -108,8 +115,6 @@ func (p *crawler) markType(t *types.Type) {
                }
 
        case types.TINTER:
-               // TODO(danscales) - will have to deal with the types in interface
-               // elements here when implemented in types2 and represented in types1.
                for _, f := range t.AllMethods().Slice() {
                        if types.IsExported(f.Sym.Name) {
                                p.markType(f.Type)
@@ -226,3 +231,10 @@ func (p *crawler) markInlBody(n *ir.Name) {
        // because after inlining they might be callable.
        ir.VisitList(fn.Inl.Body, doFlood)
 }
+
+// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a
+// pointer to a fully-instantiated type.
+func isPtrFullyInstantiated(t *types.Type) bool {
+       return t.IsPtr() && t.Elem().IsFullyInstantiated() ||
+               t.IsFullyInstantiated()
+}
diff --git a/test/typeparam/issue48454.dir/a.go b/test/typeparam/issue48454.dir/a.go
new file mode 100644 (file)
index 0000000..9613916
--- /dev/null
@@ -0,0 +1,16 @@
+// 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
+
+import "sync"
+
+type Val[T any] struct {
+       mu  sync.RWMutex
+       val T
+}
+
+func (v *Val[T]) Has() {
+       v.mu.RLock()
+}
diff --git a/test/typeparam/issue48454.dir/b.go b/test/typeparam/issue48454.dir/b.go
new file mode 100644 (file)
index 0000000..2b59b71
--- /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 b
+
+import "a"
+
+type Session struct {
+       privateField a.Val[string]
+}
diff --git a/test/typeparam/issue48454.dir/main.go b/test/typeparam/issue48454.dir/main.go
new file mode 100644 (file)
index 0000000..becb5f3
--- /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 "b"
+
+func main() {
+       var _ b.Session
+}
diff --git a/test/typeparam/issue48454.go b/test/typeparam/issue48454.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