@@ -182,7 +182,7 @@ const concreteTypeDebug = false
182
182
// Returns nil when the concrete type could not be determined, or when there are multiple
183
183
// (different) types assigned to an interface.
184
184
func concreteType (s * State , n ir.Node ) (typ * types.Type ) {
185
- typ , isNil := concreteType1 (s , n , make (map [* ir.Name ]* types. Type ))
185
+ typ , isNil := concreteType1 (s , n , make (map [* ir.Name ]struct {} ))
186
186
if isNil && typ != nil {
187
187
base .Fatalf ("typ = %v; want = <nil>" , typ )
188
188
}
@@ -200,7 +200,7 @@ func concreteType(s *State, n ir.Node) (typ *types.Type) {
200
200
//
201
201
// If n is statically known to be nil, this function returns a nil Type with isNil == true.
202
202
// However, if any concrete type is found, it is returned instead, even if n was assigned with nil.
203
- func concreteType1 (s * State , n ir.Node , analyzed map [* ir.Name ]* types. Type ) (t * types.Type , isNil bool ) {
203
+ func concreteType1 (s * State , n ir.Node , seen map [* ir.Name ]struct {} ) (t * types.Type , isNil bool ) {
204
204
nn := n // for debug messages
205
205
206
206
if concreteTypeDebug {
@@ -270,15 +270,13 @@ func concreteType1(s *State, n ir.Node, analyzed map[*ir.Name]*types.Type) (t *t
270
270
return nil , false // conservatively assume it's reassigned with a different type indirectly
271
271
}
272
272
273
- if typ , ok := analyzed [name ]; ok {
274
- return typ , false
273
+ if _ , ok := seen [name ]; ok {
274
+ // Self assignment, treat is the same as a nil assignment.
275
+ // In case this is the only assignment then we are not going to devirtualize anything.
276
+ // In case there are other assignment, we still preserve the correct type.
277
+ return nil , true
275
278
}
276
-
277
- // For now set the Type to nil, as we don't know it yet, we will update
278
- // it at the end of this function, if we find a concrete type.
279
- // This is not ideal, as in-process concreteType1 calls (that this function also
280
- // executes) will get a nil (from the map lookup above), where we could determine the type.
281
- analyzed [name ] = nil
279
+ seen [name ] = struct {}{}
282
280
283
281
if concreteTypeDebug {
284
282
base .Warn ("concreteType1(%v): analyzing assignments to %v" , nn , name )
@@ -289,7 +287,7 @@ func concreteType1(s *State, n ir.Node, analyzed map[*ir.Name]*types.Type) (t *t
289
287
t := v .typ
290
288
if v .node != nil {
291
289
var isNil bool
292
- t , isNil = concreteType1 (s , v .node , analyzed )
290
+ t , isNil = concreteType1 (s , v .node , seen )
293
291
if isNil {
294
292
if t != nil {
295
293
base .Fatalf ("t = %v; want = <nil>" , t )
@@ -303,15 +301,13 @@ func concreteType1(s *State, n ir.Node, analyzed map[*ir.Name]*types.Type) (t *t
303
301
typ = t
304
302
}
305
303
304
+ delete (seen , name )
305
+
306
306
if typ == nil {
307
307
// Variable either declared with zero value, or only assigned with nil.
308
- // For now don't bother storing the information that we could have
309
- // assigned nil in the analyzed map, if we access the same name again we will
310
- // get an result as if an unknown concrete type was assigned.
311
308
return nil , true
312
309
}
313
310
314
- analyzed [name ] = typ
315
311
return typ , false
316
312
}
317
313
@@ -346,16 +342,16 @@ type ifaceAssignRef struct {
346
342
}
347
343
348
344
// InlinedCall updates the [State] to take into account a newly inlined call.
349
- func (s * State ) InlinedCall (fun * ir.Func , origCall * ir.CallExpr , newInlinedCall * ir.InlinedCallExpr ) {
345
+ func (s * State ) InlinedCall (fun * ir.Func , origCall * ir.CallExpr , inlinedCall * ir.InlinedCallExpr ) {
350
346
if _ , ok := s .analyzedFuncs [fun ]; ! ok {
351
347
// Full analyze has not been yet executed for the provided function, so we can skip it for now.
352
348
// When no devirtualization happens in a function, it is unnecessary to analyze it.
353
349
return
354
350
}
355
351
356
352
// Analyze assignments in the newly inlined function.
357
- s .analyze (newInlinedCall .Init ())
358
- s .analyze (newInlinedCall .Body )
353
+ s .analyze (inlinedCall .Init ())
354
+ s .analyze (inlinedCall .Body )
359
355
360
356
refs , ok := s .ifaceCallExprAssigns [origCall ]
361
357
if ! ok {
@@ -372,12 +368,12 @@ func (s *State) InlinedCall(fun *ir.Func, origCall *ir.CallExpr, newInlinedCall
372
368
if concreteTypeDebug {
373
369
base .Warn (
374
370
"InlinedCall(%v, %v): replacing interface node in (%v,%v) to %v (typ %v)" ,
375
- origCall , newInlinedCall , ref .name , ref .valOrTypeIndex ,
376
- newInlinedCall .ReturnVars [ref .returnIndex ],
377
- newInlinedCall .ReturnVars [ref .returnIndex ].Type (),
371
+ origCall , inlinedCall , ref .name , ref .valOrTypeIndex ,
372
+ inlinedCall .ReturnVars [ref .returnIndex ],
373
+ inlinedCall .ReturnVars [ref .returnIndex ].Type (),
378
374
)
379
375
}
380
- * vt = valOrTyp {node : newInlinedCall .ReturnVars [ref .returnIndex ]}
376
+ * vt = valOrTyp {node : inlinedCall .ReturnVars [ref .returnIndex ]}
381
377
}
382
378
}
383
379
0 commit comments