Skip to content

Commit 397661b

Browse files
Merge pull request #3041 from icsharpcode/roslyn46
Roslyn 4.6
2 parents 50c2398 + 32e04ea commit 397661b

File tree

5 files changed

+386
-11
lines changed

5 files changed

+386
-11
lines changed

ICSharpCode.Decompiler.Tests/TestCases/Correctness/ValueTypeCall.cs

+37
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public void Increment()
1616
public void Dispose()
1717
{
1818
Console.WriteLine("MutValueType disposed on {0}", val);
19+
val = val + 1;
1920
}
2021

2122
public override string ToString()
@@ -67,6 +68,10 @@ public static void Main()
6768
gvt.Call(ref gvt);
6869
new ValueTypeCall().InstanceFieldTests();
6970
ForEach();
71+
#if CS73
72+
DisposeMultipleTimes(ref m, in m);
73+
ToStringGeneric(ref m, in m);
74+
#endif
7075
}
7176

7277
static void RefParameter(ref MutValueType m)
@@ -213,5 +218,37 @@ static void ForEachArray1(MutValueType[] list)
213218
}
214219
Console.WriteLine("after: " + list[0].val);
215220
}
221+
222+
#if CS73
223+
static void DisposeMultipleTimes<T>(ref T mutRef, in T immutableRef) where T : struct, IDisposable
224+
{
225+
Console.WriteLine("DisposeMultipleTimes:");
226+
mutRef.Dispose();
227+
mutRef.Dispose();
228+
T copyFromMut = mutRef;
229+
copyFromMut.Dispose();
230+
immutableRef.Dispose();
231+
immutableRef.Dispose();
232+
T copyFromImmutable = immutableRef;
233+
copyFromImmutable.Dispose();
234+
mutRef.Dispose();
235+
immutableRef.Dispose();
236+
}
237+
238+
static void ToStringGeneric<T>(ref T mutRef, in T immutableRef) where T : struct
239+
{
240+
Console.WriteLine("ToStringGeneric:");
241+
Console.WriteLine(mutRef.ToString());
242+
Console.WriteLine(mutRef.ToString());
243+
T copyFromMut = mutRef;
244+
Console.WriteLine(copyFromMut.ToString());
245+
Console.WriteLine(immutableRef.ToString());
246+
Console.WriteLine(immutableRef.ToString());
247+
T copyFromImmutable = immutableRef;
248+
Console.WriteLine(copyFromImmutable.ToString());
249+
Console.WriteLine(mutRef.ToString());
250+
Console.WriteLine(immutableRef.ToString());
251+
}
252+
#endif
216253
}
217254
}

ICSharpCode.Decompiler/DecompilerSettings.cs

+1
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ public bool ScopedRef {
379379
}
380380

381381
[Obsolete("Renamed to ScopedRef. This property will be removed in a future version of the decompiler.")]
382+
[Browsable(false)]
382383
public bool LifetimeAnnotations {
383384
get { return ScopedRef; }
384385
set { ScopedRef = value; }

ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

+10-7
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
301301
// Thus, we have to ensure we're operating on an r-value.
302302
// Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
303303
// 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))
305305
{
306306
if (options.HasFlag(InliningOptions.Aggressive))
307307
{
@@ -321,7 +321,7 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
321321
case ExpressionClassification.ReadonlyLValue:
322322
// For struct method calls on readonly lvalues, the C# compiler
323323
// only generates a temporary if it isn't a "readonly struct"
324-
return MethodRequiresCopyForReadonlyLValue(method);
324+
return MethodRequiresCopyForReadonlyLValue(method, constrainedTo);
325325
default:
326326
throw new InvalidOperationException("invalid expression classification");
327327
}
@@ -337,11 +337,11 @@ static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstr
337337
}
338338
}
339339

340-
internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method)
340+
internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method, IType constrainedTo = null)
341341
{
342342
if (method == null)
343343
return true;
344-
var type = method.DeclaringType;
344+
var type = constrainedTo ?? method.DeclaringType;
345345
if (type.IsReferenceType == true)
346346
return false; // reference types are never implicitly copied
347347
if (method.ThisIsRefReadOnly)
@@ -351,12 +351,13 @@ internal static bool MethodRequiresCopyForReadonlyLValue(IMethod method)
351351

352352
internal static bool IsUsedAsThisPointerInCall(LdLoca ldloca)
353353
{
354-
return IsUsedAsThisPointerInCall(ldloca, out _);
354+
return IsUsedAsThisPointerInCall(ldloca, out _, out _);
355355
}
356356

357-
static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method)
357+
static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method, out IType constrainedType)
358358
{
359359
method = null;
360+
constrainedType = null;
360361
if (ldloca.Variable.Type.IsReferenceType ?? false)
361362
return false;
362363
ILInstruction inst = ldloca;
@@ -370,7 +371,9 @@ static bool IsUsedAsThisPointerInCall(LdLoca ldloca, out IMethod method)
370371
{
371372
case OpCode.Call:
372373
case OpCode.CallVirt:
373-
method = ((CallInstruction)inst.Parent).Method;
374+
var callInst = (CallInstruction)inst.Parent;
375+
method = callInst.Method;
376+
constrainedType = callInst.ConstrainedTo;
374377
if (method.IsAccessor)
375378
{
376379
if (method.AccessorKind == MethodSemanticsAttributes.Getter)

0 commit comments

Comments
 (0)