2

Consider following code:

    public class DecimalWrapper
    {
        public static implicit operator DecimalWrapper(decimal x) => new();
    }

    [Fact]
    public void Test()
    {
        // Why this even compiles? Since there is no implicit conversion from decimal? -> decimal
        DecimalWrapper c = (decimal?)null; // variable 'c' is null!
    }

I would not expect it to compile at all, since there is no implicit conversion from decimal? to decimal.

I consider it a bug or do I get something wrong?

I have seen this: Serious bugs with lifted/nullable conversions from int, allowing conversion from decimal

but this looks different and it is old (7+ years), so the bugs should be fixed by now, but cannot be sure since all the links to bug reports are gone)... :(

I would really like to use such code in real solution (tracking of calculations), but this prevents me from it.

PS: I am compiling on Windows.

videokojot
  • 499
  • 3
  • 12
  • 1
    [Predefined implicit conversions that operate on non-nullable value types can also be used with nullable forms of those types](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions#implicit-nullable-conversions) – DekuDesu Aug 25 '21 at 12:27
  • 1
    Side note, if you feel this is unintended behavior on the compilers part you should file an issue on your respective compiler's GitHub page. – DekuDesu Aug 25 '21 at 12:29
  • @DekuDesu I am not sure if that applies to out case since this is not about 'predfined' conversion, but here we are going from decimal? ->(should not be allowed) decimal -> DecimalWrapper. But maybe I am interpreting docs wrongly, so can you elaborate and post it as an answer, please? – videokojot Aug 25 '21 at 12:48

1 Answers1

5

According to specification lifted conversion operators are allowed only for value type to value type conversions (and their nullable counterparts) but in the Roslyn compiler source code you can find next comment:

DELIBERATE SPEC VIOLATION:
The native compiler allows for a "lifted" conversion even when the return type of the conversion not a non-nullable value type. For example, if we have a conversion from struct S to string, then a "lifted" conversion from S? to string is considered by the native compiler to exist, with the semantics of "s.HasValue ? (string)s.Value : (string)null". The Roslyn compiler perpetuates this error for the sake of backwards compatibility.

So it seems to be an actuall bug which was introduced for backwards compatibility. And the decompilation shows exactly that behaviour.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    Note: doesn't actually get called in case of null : https://dotnetfiddle.net/stoRFW – Fildor Aug 25 '21 at 12:32
  • Thank you! Did not known about this, does not feel like supposed behavior, but that's on me. – videokojot Aug 25 '21 at 12:35
  • @videokojot can you please unmark my answer cause it is not correct - because it is about VALUE TYPES, and `DecimalWrapper` is a reference type. – Guru Stron Aug 25 '21 at 12:41
  • @GuruStron yeah, missed that too. So answer unmarked.. – videokojot Aug 25 '21 at 12:46
  • @GuruStron thats ugly... but we have to live with this.. So marking as answered again (so you can delete your comment about unmarking, so we do not confuse future reader). thx – videokojot Aug 25 '21 at 12:55