title: Is this a possible bug in .Net Native compilation and optimization?
body: <p>I discovered an issue with (what might be) over-optimization in <code>.Net Native</code> and <code>structs</code>. I'm not sure if the compiler is too aggressive, or I'm too blind to see what I've done wrong. </p>
  
  <p>To reproduce this, follow these steps:</p>
  
  <p><strong>Step 1</strong>: Create a new Blank Universal (win10) app in <em>Visual Studio 2015 Update 2</em> targeting build 10586 with a min build of 10240. Call the project <em>NativeBug</em> so we have the same namespace.</p>
  
  <p><strong>Step 2</strong>: Open <code>MainPage.xaml</code> and insert this label</p>
  
  <pre><code>&lt;Page x:Class="NativeBug.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"&gt;
  
      &lt;Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"&gt;
          &lt;!-- INSERT THIS LABEL --&gt;
          &lt;TextBlock x:Name="_Label" HorizontalAlignment="Center" VerticalAlignment="Center" /&gt;
      &lt;/Grid&gt;
  &lt;/Page&gt;
  </code></pre>
  
  <p><strong>Step 3</strong>: Copy/paste the following into <code>MainPage.xaml.cs</code></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  
  namespace NativeBug
  {
      public sealed partial class MainPage
      {
          public MainPage()
          {
              InitializeComponent();
  
              var startPoint = new Point2D(50, 50);
              var points = new[]
              {
                  new Point2D(100, 100), 
                  new Point2D(100, 50), 
                  new Point2D(50, 100), 
              };
  
              var bounds = ComputeBounds(startPoint, points, 15);
  
              _Label.Text = $"{bounds.MinX} , {bounds.MinY}   =&gt;   {bounds.MaxX} , {bounds.MaxY}";
          }
  
          private static Rectangle2D ComputeBounds(Point2D startPoint, IEnumerable&lt;Point2D&gt; points, double strokeThickness = 0)
          {
              var lastPoint = startPoint;
              var cumulativeBounds = new Rectangle2D();
  
              foreach (var point in points)
              {
                  var bounds = ComputeBounds(lastPoint, point, strokeThickness);
                  cumulativeBounds = cumulativeBounds.Union(bounds);
                  lastPoint = point;
              }
  
              return cumulativeBounds;
          }
  
          private static Rectangle2D ComputeBounds(Point2D fromPoint, Point2D toPoint, double strokeThickness)
          {
              var bounds = new Rectangle2D(fromPoint.X, fromPoint.Y, toPoint.X, toPoint.Y);
  
              // ** Uncomment the line below to see the difference **
              //return strokeThickness &lt;= 0 ? bounds : bounds.Inflate2(strokeThickness);
  
              return strokeThickness &lt;= 0 ? bounds : bounds.Inflate1(strokeThickness);
          }
      }
  
      public struct Point2D
      {
          public readonly double X;
          public readonly double Y;
  
          public Point2D(double x, double y)
          {
              X = x;
              Y = y;
          }
      }
  
      public struct Rectangle2D
      {
          public readonly double MinX;
          public readonly double MinY;
          public readonly double MaxX;
          public readonly double MaxY;
  
          private bool IsEmpty =&gt; MinX == 0 &amp;&amp; MinY == 0 &amp;&amp; MaxX == 0 &amp;&amp; MaxY == 0;
  
          public Rectangle2D(double x1, double y1, double x2, double y2)
          {
              MinX = Math.Min(x1, x2);
              MinY = Math.Min(y1, y2);
              MaxX = Math.Max(x1, x2);
              MaxY = Math.Max(y1, y2);
          }
  
          public Rectangle2D Union(Rectangle2D rectangle)
          {
              if (IsEmpty)
              {
                  return rectangle;
              }
  
              var newMinX = Math.Min(MinX, rectangle.MinX);
              var newMinY = Math.Min(MinY, rectangle.MinY);
              var newMaxX = Math.Max(MaxX, rectangle.MaxX);
              var newMaxY = Math.Max(MaxY, rectangle.MaxY);
  
              return new Rectangle2D(newMinX, newMinY, newMaxX, newMaxY);
          }
  
          public Rectangle2D Inflate1(double value)
          {
              var halfValue = value * .5;
  
              return new Rectangle2D(MinX - halfValue, MinY - halfValue, MaxX + halfValue, MaxY + halfValue);
          }
  
          public Rectangle2D Inflate2(double value)
          {
              var halfValue = value * .5;
              var x1 = MinX - halfValue;
              var y1 = MinY - halfValue;
              var x2 = MaxX + halfValue;
              var y2 = MaxY + halfValue;
  
              return new Rectangle2D(x1, y1, x2, y2);
          }
      }
  }
  </code></pre>
  
  <p><strong>Step 4</strong>: Run the application in <code>Debug</code> <code>x64</code>. You should see this label:</p>
  
  <blockquote>
    <p>42.5 , 42.5  =>  107.5 , 107.5</p>
  </blockquote>
  
  <p><strong>Step 5</strong>: Run the application in <code>Release</code> <code>x64</code>. You should see this label:</p>
  
  <blockquote>
    <p>-7.5 , -7.5  =>  7.5, 7.5</p>
  </blockquote>
  
  <p><strong>Step 6</strong>: Uncomment <code>line 45</code> in <code>MainPage.xaml.cs</code> and repeat step 5. Now you see the original label</p>
  
  <blockquote>
    <p>42.5 , 42.5  =>  107.5 , 107.5</p>
  </blockquote>
  
  <hr>
  
  <p>By commenting out <code>line 45</code>, the code will use <code>Rectangle2D.Inflate2(...)</code> which is exactly the same as <code>Rectangle2D.Inflate1(...)</code> except it creates a local copy of the computations before sending them to the constructor of <code>Rectangle2D</code>. In debug mode, these two function exactly the same. In release however, something is getting optimized out.</p>
  
  <p>This was a nasty bug in our app. The code you see here was stripped from a much larger library and I'm afraid there might be more. Before I report this to Microsoft, I would appreciate it if you could take a look and let me know why <code>Inflate1</code> doesn't work in release mode. Why do we have to create local copies?</p>