@@ -301,7 +301,7 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
301
301
// Thus, we have to ensure we're operating on an r-value.
302
302
// Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
303
303
// of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
304
- if ( IsUsedAsThisPointerInCall ( loadInst , out var method ) )
304
+ if ( IsUsedAsThisPointerInCall ( loadInst , out var method , out var constrainedTo ) )
305
305
{
306
306
if ( options . HasFlag ( InliningOptions . Aggressive ) )
307
307
{
@@ -321,7 +321,7 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
321
321
case ExpressionClassification . ReadonlyLValue :
322
322
// For struct method calls on readonly lvalues, the C# compiler
323
323
// only generates a temporary if it isn't a "readonly struct"
324
- return MethodRequiresCopyForReadonlyLValue ( method ) ;
324
+ return MethodRequiresCopyForReadonlyLValue ( method , constrainedTo ) ;
325
325
default :
326
326
throw new InvalidOperationException ( "invalid expression classification" ) ;
327
327
}
@@ -337,11 +337,11 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
337
337
}
338
338
}
339
339
340
- internal static bool MethodRequiresCopyForReadonlyLValue ( IMethod method )
340
+ internal static bool MethodRequiresCopyForReadonlyLValue ( IMethod method , IType constrainedTo = null )
341
341
{
342
342
if ( method == null )
343
343
return true ;
344
- var type = method . DeclaringType ;
344
+ var type = constrainedTo ?? method . DeclaringType ;
345
345
if ( type . IsReferenceType == true )
346
346
return false ; // reference types are never implicitly copied
347
347
if ( method . ThisIsRefReadOnly )
@@ -351,12 +351,13 @@ internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method)
351
351
352
352
internal static bool IsUsedAsThisPointerInCall ( LdLoca ldloca )
353
353
{
354
- return IsUsedAsThisPointerInCall ( ldloca , out _ ) ;
354
+ return IsUsedAsThisPointerInCall ( ldloca , out _ , out _ ) ;
355
355
}
356
356
357
- static bool IsUsedAsThisPointerInCall ( LdLoca ldloca , out IMethod method )
357
+ static bool IsUsedAsThisPointerInCall ( LdLoca ldloca , out IMethod method , out IType constrainedType )
358
358
{
359
359
method = null ;
360
+ constrainedType = null ;
360
361
if ( ldloca . Variable . Type . IsReferenceType ?? false )
361
362
return false ;
362
363
ILInstruction inst = ldloca ;
@@ -370,7 +371,9 @@ static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method)
370
371
{
371
372
case OpCode . Call :
372
373
case OpCode . CallVirt :
373
- method = ( ( CallInstruction ) inst . Parent ) . Method ;
374
+ var callInst = ( CallInstruction ) inst . Parent ;
375
+ method = callInst . Method ;
376
+ constrainedType = callInst . ConstrainedTo ;
374
377
if ( method . IsAccessor )
375
378
{
376
379
if ( method . AccessorKind == MethodSemanticsAttributes . Getter )
0 commit comments