@@ -146,15 +146,15 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) {
146
146
func checkCopyLocksFunc (pass * analysis.Pass , name string , recv * ast.FieldList , typ * ast.FuncType ) {
147
147
if recv != nil && len (recv .List ) > 0 {
148
148
expr := recv .List [0 ].Type
149
- if path := lockPath (pass .Pkg , pass .TypesInfo .Types [expr ].Type ); path != nil {
149
+ if path := lockPath (pass .Pkg , pass .TypesInfo .Types [expr ].Type , nil ); path != nil {
150
150
pass .ReportRangef (expr , "%s passes lock by value: %v" , name , path )
151
151
}
152
152
}
153
153
154
154
if typ .Params != nil {
155
155
for _ , field := range typ .Params .List {
156
156
expr := field .Type
157
- if path := lockPath (pass .Pkg , pass .TypesInfo .Types [expr ].Type ); path != nil {
157
+ if path := lockPath (pass .Pkg , pass .TypesInfo .Types [expr ].Type , nil ); path != nil {
158
158
pass .ReportRangef (expr , "%s passes lock by value: %v" , name , path )
159
159
}
160
160
}
@@ -200,7 +200,7 @@ func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) {
200
200
if typ == nil {
201
201
return
202
202
}
203
- if path := lockPath (pass .Pkg , typ ); path != nil {
203
+ if path := lockPath (pass .Pkg , typ , nil ); path != nil {
204
204
pass .Reportf (e .Pos (), "range var %s copies lock: %v" , analysisutil .Format (pass .Fset , e ), path )
205
205
}
206
206
}
@@ -235,23 +235,35 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
235
235
return nil
236
236
}
237
237
}
238
- return lockPath (pass .Pkg , pass .TypesInfo .Types [x ].Type )
238
+ return lockPath (pass .Pkg , pass .TypesInfo .Types [x ].Type , nil )
239
239
}
240
240
241
241
// lockPath returns a typePath describing the location of a lock value
242
242
// contained in typ. If there is no contained lock, it returns nil.
243
- func lockPath (tpkg * types.Package , typ types.Type ) typePath {
243
+ //
244
+ // The seenTParams map is used to short-circuit infinite recursion via type
245
+ // parameters.
246
+ func lockPath (tpkg * types.Package , typ types.Type , seenTParams map [* typeparams.TypeParam ]bool ) typePath {
244
247
if typ == nil {
245
248
return nil
246
249
}
247
250
248
251
if tpar , ok := typ .(* typeparams.TypeParam ); ok {
252
+ if seenTParams == nil {
253
+ // Lazily allocate seenTParams, since the common case will not involve
254
+ // any type parameters.
255
+ seenTParams = make (map [* typeparams.TypeParam ]bool )
256
+ }
257
+ if seenTParams [tpar ] {
258
+ return nil
259
+ }
260
+ seenTParams [tpar ] = true
249
261
terms , err := typeparams .StructuralTerms (tpar )
250
262
if err != nil {
251
263
return nil // invalid type
252
264
}
253
265
for _ , term := range terms {
254
- subpath := lockPath (tpkg , term .Type ())
266
+ subpath := lockPath (tpkg , term .Type (), seenTParams )
255
267
if len (subpath ) > 0 {
256
268
if term .Tilde () {
257
269
// Prepend a tilde to our lock path entry to clarify the resulting
@@ -285,7 +297,7 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath {
285
297
ttyp , ok := typ .Underlying ().(* types.Tuple )
286
298
if ok {
287
299
for i := 0 ; i < ttyp .Len (); i ++ {
288
- subpath := lockPath (tpkg , ttyp .At (i ).Type ())
300
+ subpath := lockPath (tpkg , ttyp .At (i ).Type (), seenTParams )
289
301
if subpath != nil {
290
302
return append (subpath , typ .String ())
291
303
}
@@ -319,7 +331,7 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath {
319
331
nfields := styp .NumFields ()
320
332
for i := 0 ; i < nfields ; i ++ {
321
333
ftyp := styp .Field (i ).Type ()
322
- subpath := lockPath (tpkg , ftyp )
334
+ subpath := lockPath (tpkg , ftyp , seenTParams )
323
335
if subpath != nil {
324
336
return append (subpath , typ .String ())
325
337
}
0 commit comments