title: Serious bugs with lifted/nullable conversions from int, allowing conversion from decimal
body: <p>I think this question will bring me instant fame here on Stack Overflow.</p>
  
  <p>Suppose you have the following type:</p>
  
  <pre><code>// represents a decimal number with at most two decimal places after the period
  struct NumberFixedPoint2
  {
      decimal number;
  
      // an integer has no fractional part; can convert to this type
      public static implicit operator NumberFixedPoint2(int integer)
      {
          return new NumberFixedPoint2 { number = integer };
      }
  
      // this type is a decimal number; can convert to System.Decimal
      public static implicit operator decimal(NumberFixedPoint2 nfp2)
      {
          return nfp2.number;
      }
  
      /* will add more nice members later */
  }
  </code></pre>
  
  <p>It has been written such that only safe conversions that don't lose precision are allowed. However, when I try this code:</p>
  
  <pre><code>    static void Main()
      {
          decimal bad = 2.718281828m;
          NumberFixedPoint2 badNfp2 = (NumberFixedPoint2)bad;
          Console.WriteLine(badNfp2);
      }
  </code></pre>
  
  <p>I am surprised this compiles and, when run, <strong>writes out <code>2</code></strong>. The conversion from <code>int</code> (of value <code>2</code>) to <code>NumberFixedPoint2</code> is important here. (An overload of <code>WriteLine</code> that takes in a <code>System.Decimal</code> is preferred, in case anyone wonders.)</p>
  
  <p>Why on Earth is the conversion from <code>decimal</code> to <code>NumberFixedPoint2</code> allowed? (By the way, in the above code, if <code>NumberFixedPoint2</code> is changed from a struct to a class, nothing changes.)</p>
  
  <p>Do you know if the C# Language Specification says that an implicit conversion from <code>int</code> to a custom type "implies" the existence of a "direct" explicit conversion from <code>decimal</code> to that custom type?</p>
  
  <p>It becomes much worse. Try this code instead:</p>
  
  <pre><code>    static void Main()
      {
          decimal? moreBad = 7.3890560989m;
          NumberFixedPoint2? moreBadNfp2 = (NumberFixedPoint2?)moreBad;
          Console.WriteLine(moreBadNfp2.Value);
      }
  </code></pre>
  
  <p>As you see, we have (lifted) <code>Nullable&lt;&gt;</code> conversions here. But oh yes, that does compile.</p>
  
  <p>When compiled in <strong>x86</strong> "platform", this code writes out an unpredictable numeric value. Which one varies from time to time. As an example, on one occasion I got <strong><code>2289956</code></strong>. Now, that's one serious bug!</p>
  
  <p>When compiled for the <strong>x64</strong> platform, the above code crashes the application with a <code>System.InvalidProgramException</code> with message <strong>Common Language Runtime detected an invalid program.</strong> According to the documentation of the <code>InvalidProgramException</code> class:</p>
  
  <blockquote>
    <p>Generally this indicates a bug in the compiler that generated the program.</p>
  </blockquote>
  
  <p>Does anyone (like Eric Lippert, or someone who has worked with lifted conversions in the C# compiler) know the cause of these bugs? Like, what is a sufficient condition that we don't run into them in our code? Because the type <code>NumberFixedPoint2</code> is actually something that we have in real code (managing other people's money and stuff).</p>