Browse Source

Merge pull request #3823 from sailro/fix-refstruct-nullpropagation

Fix #3821: keep ref-struct conditional as if/return, not ?. / ?? (CS8978)
pull/3789/head
Siegfried Pammer 1 week ago committed by GitHub
parent
commit
f5d156b0e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 34
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs
  2. 6
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

34
ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs

@ -7,6 +7,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
static void Main() static void Main()
{ {
new NullPropagation().TestNotCoalescing(); new NullPropagation().TestNotCoalescing();
#if CS72
new NullPropagation().TestRefStructNotCoalescing();
#endif
} }
class MyClass class MyClass
@ -25,5 +28,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{ {
return c != null ? c.Text : "Hello"; return c != null ? c.Text : "Hello";
} }
#if CS72
ref struct ByRefLikeStruct
{
public int Value;
}
class RefStructHolder
{
public ByRefLikeStruct Get()
{
ByRefLikeStruct result = default(ByRefLikeStruct);
result.Value = 42;
return result;
}
}
void TestRefStructNotCoalescing()
{
Console.WriteLine("TestRefStructNotCoalescing:");
Console.WriteLine(RefStructNotCoalescing(null).Value);
Console.WriteLine(RefStructNotCoalescing(new RefStructHolder()).Value);
}
// A by-ref-like return type cannot be turned into a ?. / ?? null-propagation: a ref struct
// cannot be wrapped in Nullable<T>, so that form does not compile.
ByRefLikeStruct RefStructNotCoalescing(RefStructHolder holder)
{
return holder != null ? holder.Get() : default(ByRefLikeStruct);
}
#endif
} }
} }

6
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -140,12 +140,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IntroduceUnwrap(testedVar, varLoad, mode); IntroduceUnwrap(testedVar, varLoad, mode);
return new NullableRewrap(nonNullInst); return new NullableRewrap(nonNullInst);
} }
else if (!removedRewrapOrNullableCtor && NullableType.IsNonNullableValueType(returnType)) else if (!removedRewrapOrNullableCtor && NullableType.IsNonNullableValueType(returnType)
&& !returnType.IsByRefLike)
{ {
context.Step($"Null propagation (mode={mode}, output=null coalescing)", nonNullInst); context.Step($"Null propagation (mode={mode}, output=null coalescing)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : nullInst // testedVar != null ? testedVar.AccessChain : nullInst
// => testedVar?.AccessChain ?? nullInst // => testedVar?.AccessChain ?? nullInst
// (only valid if AccessChain returns a non-nullable value) // (only valid if AccessChain returns a non-nullable value; a by-ref-like type such as
// Span<T> is excluded because it cannot be wrapped in Nullable<T> for the ?. / ?? form)
IntroduceUnwrap(testedVar, varLoad, mode); IntroduceUnwrap(testedVar, varLoad, mode);
return new NullCoalescingInstruction( return new NullCoalescingInstruction(
NullCoalescingKind.NullableWithValueFallback, NullCoalescingKind.NullableWithValueFallback,

Loading…
Cancel
Save