Skip to content

Commit cea7a71

Browse files
committed
cmd/compile: fix generic type handling in crawler
There are a bunch of nodes beside ONAME and OTYPE, (such as OSTRUCTLIT and OCOMPLIT) which can introduce a generic type that we need to mark. So, just mark any generic type on any node in markInlBody. In this particular issue, the type is introduced by an OSTRUCTLIT node. Updates #48337 Change-Id: I271932518f0c1fb54d91a603e01a855c69df631d Reviewed-on: https://go-review.googlesource.com/c/go/+/349909 Trust: Dan Scales <[email protected]> Trust: Carlos Amedee <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 74e384f commit cea7a71

File tree

5 files changed

+73
-24
lines changed

5 files changed

+73
-24
lines changed

src/cmd/compile/internal/typecheck/crawler.go

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ func (p *crawler) markObject(n *ir.Name) {
4444
p.markType(n.Type())
4545
}
4646

47-
// markType recursively visits types reachable from t to identify
48-
// functions whose inline bodies may be needed.
47+
// markType recursively visits types reachable from t to identify functions whose
48+
// inline bodies may be needed. For instantiated generic types, it visits the base
49+
// generic type, which has the relevant methods.
4950
func (p *crawler) markType(t *types.Type) {
50-
if t.IsInstantiatedGeneric() {
51-
// Re-instantiated types don't add anything new, so don't follow them.
52-
return
51+
if t.OrigSym() != nil {
52+
// Convert to the base generic type.
53+
t = t.OrigSym().Def.Type()
5354
}
5455
if p.marked[t] {
5556
return
@@ -92,6 +93,9 @@ func (p *crawler) markType(t *types.Type) {
9293
p.markType(t.Elem())
9394

9495
case types.TSTRUCT:
96+
if t.IsFuncArgStruct() {
97+
break
98+
}
9599
for _, f := range t.FieldSlice() {
96100
if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
97101
p.markType(f.Type)
@@ -129,9 +133,9 @@ func (p *crawler) markEmbed(t *types.Type) {
129133
t = t.Elem()
130134
}
131135

132-
if t.IsInstantiatedGeneric() {
133-
// Re-instantiated types don't add anything new, so don't follow them.
134-
return
136+
if t.OrigSym() != nil {
137+
// Convert to the base generic type.
138+
t = t.OrigSym().Def.Type()
135139
}
136140

137141
if p.embedded[t] {
@@ -185,6 +189,15 @@ func (p *crawler) markInlBody(n *ir.Name) {
185189

186190
var doFlood func(n ir.Node)
187191
doFlood = func(n ir.Node) {
192+
t := n.Type()
193+
if t != nil && (t.HasTParam() || t.IsFullyInstantiated()) {
194+
// Ensure that we call markType() on any base generic type
195+
// that is written to the export file (even if not explicitly
196+
// marked for export), so we will call markInlBody on its
197+
// methods, and the methods will be available for
198+
// instantiation if needed.
199+
p.markType(t)
200+
}
188201
switch n.Op() {
189202
case ir.OMETHEXPR, ir.ODOTMETH:
190203
p.markInlBody(ir.MethodExprName(n))
@@ -198,9 +211,6 @@ func (p *crawler) markInlBody(n *ir.Name) {
198211
case ir.PEXTERN:
199212
Export(n)
200213
}
201-
p.checkGenericType(n.Type())
202-
case ir.OTYPE:
203-
p.checkGenericType(n.Type())
204214
case ir.OMETHVALUE:
205215
// Okay, because we don't yet inline indirect
206216
// calls to method values.
@@ -216,16 +226,3 @@ func (p *crawler) markInlBody(n *ir.Name) {
216226
// because after inlining they might be callable.
217227
ir.VisitList(fn.Inl.Body, doFlood)
218228
}
219-
220-
// checkGenerictype ensures that we call markType() on any base generic type that
221-
// is written to the export file (even if not explicitly marked
222-
// for export), so its methods will be available for inlining if needed.
223-
func (p *crawler) checkGenericType(t *types.Type) {
224-
if t != nil && t.HasTParam() {
225-
if t.OrigSym() != nil {
226-
// Convert to the base generic type.
227-
t = t.OrigSym().Def.Type()
228-
}
229-
p.markType(t)
230-
}
231-
}

test/typeparam/issue48337a.dir/a.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package a
6+
7+
import (
8+
"fmt"
9+
"sync"
10+
)
11+
12+
type WrapperWithLock[T any] interface {
13+
PrintWithLock()
14+
}
15+
16+
func NewWrapperWithLock[T any](value T) WrapperWithLock[T] {
17+
return &wrapperWithLock[T]{
18+
Object: value,
19+
}
20+
}
21+
22+
type wrapperWithLock[T any] struct {
23+
Lock sync.Mutex
24+
Object T
25+
}
26+
27+
func (w *wrapperWithLock[T]) PrintWithLock() {
28+
w.Lock.Lock()
29+
defer w.Lock.Unlock()
30+
31+
fmt.Println(w.Object)
32+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "a"
8+
9+
func main() {
10+
obj := a.NewWrapperWithLock("this file does import sync")
11+
obj.PrintWithLock()
12+
}

test/typeparam/issue48337a.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// rundir -G=3
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package ignored

test/typeparam/issue48337a.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
this file does import sync

0 commit comments

Comments
 (0)