[mcs] Fixes codegen for type pattern matching in probing expressions over hoisted...
authorMarek Safar <marek.safar@gmail.com>
Fri, 4 Aug 2017 13:15:14 +0000 (15:15 +0200)
committerMarek Safar <marek.safar@gmail.com>
Fri, 4 Aug 2017 13:15:14 +0000 (15:15 +0200)
mcs/mcs/anonymous.cs
mcs/mcs/expression.cs
mcs/tests/test-pattern-09.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

index 6cec0e1da6dc57513c0af368e3ec08a8f5ac6848..3ce9b0c9f199189c703238261602f52d1acb5e33 100644 (file)
@@ -839,6 +839,11 @@ namespace Mono.CSharp {
                {
                        GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
                }
+
+               public void EmitAssignFromStack (EmitContext ec)
+               {
+                       GetFieldExpression (ec).EmitAssignFromStack (ec);
+               }
        }
 
        public class HoistedParameter : HoistedVariable
index f94bc4239202e68cce2e8505efcf2d0fa6d1d150..896980968d82efd168067c2664980380ecbe842c 100644 (file)
@@ -1687,8 +1687,15 @@ namespace Mono.CSharp
                                ec.Emit (OpCodes.Dup);
                                no_value_label = ec.DefineLabel ();
                                ec.Emit (OpCodes.Brfalse_S, no_value_label);
+
+                               if (Variable.HoistedVariant != null)
+                                       ec.EmitThis ();
+
                                expr_unwrap.Emit (ec);
                        } else {
+                               if (Variable?.HoistedVariant != null)
+                                       ec.EmitThis ();
+
                                expr.Emit (ec);
 
                                // Only to make verifier happy
@@ -1708,19 +1715,29 @@ namespace Mono.CSharp
                                        value_on_stack = false;
                                }
 
-                               //
-                               // It's ok to have variable builder created out of order. It simplifies emit
-                               // of statements like while (condition) { }
-                               //
-                               if (!Variable.Created)
-                                       Variable.CreateBuilder (ec);
-                               
-                               Variable.EmitAssign (ec);
+                               if (Variable.HoistedVariant != null) {
+                                       Variable.HoistedVariant.EmitAssignFromStack (ec);
 
-                               if (expr_unwrap != null) {
-                                       ec.MarkLabel (no_value_label);
-                               } else if (!value_on_stack) {
-                                       Variable.Emit (ec);
+                                       if (expr_unwrap != null) {
+                                               ec.MarkLabel (no_value_label);
+                                       } else if (!value_on_stack) {
+                                               Variable.HoistedVariant.Emit (ec);
+                                       }
+                               } else {
+                                       //
+                                       // It's ok to have variable builder created out of order. It simplifies emit
+                                       // of statements like while (condition) { }
+                                       //
+                                       if (!Variable.Created)
+                                               Variable.CreateBuilder (ec);
+
+                                       Variable.EmitAssign (ec);
+
+                                       if (expr_unwrap != null) {
+                                               ec.MarkLabel (no_value_label);
+                                       } else if (!value_on_stack) {
+                                               Variable.Emit (ec);
+                                       }
                                }
                        }
                }
diff --git a/mcs/tests/test-pattern-09.cs b/mcs/tests/test-pattern-09.cs
new file mode 100644 (file)
index 0000000..801469e
--- /dev/null
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+
+class Expr
+{
+       public int Field;
+}
+
+static class X
+{
+       public static IEnumerable<int> Test (Expr expr)
+       {
+               object exprCur = expr;
+               if (exprCur is Expr list) {
+                       yield return list.Field;
+               }
+       }
+
+       public static IEnumerable<string> Test2 (int? expr)
+       {
+               int? exprCur = expr;
+               while (exprCur != null) {
+                       if (exprCur is int list) {
+                               yield return list.ToString ();
+                       }
+               }
+       }       
+
+       public static void Main ()
+       {
+               Test (null);
+               Test2 (3);
+       }
+}
\ No newline at end of file
index aec54869c331e5d3afba0675a3599cf8544715ac..eae0f275f16d50e0c382d004bd08313a90350adb 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-pattern-09.cs">
+    <type name="Expr">
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X">
+      <method name="System.Collections.Generic.IEnumerable`1[System.Int32] Test(Expr)" attrs="150">
+        <size>30</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerable`1[System.String] Test2(System.Nullable`1[System.Int32])" attrs="150">
+        <size>30</size>
+      </method>
+      <method name="Void Main()" attrs="150">
+        <size>21</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test&gt;c__Iterator0">
+      <method name="Boolean MoveNext()" attrs="486">
+        <size>124</size>
+      </method>
+      <method name="Int32 System.Collections.Generic.IEnumerator&lt;int&gt;.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+        <size>19</size>
+      </method>
+      <method name="Void Dispose()" attrs="486">
+        <size>15</size>
+      </method>
+      <method name="Void Reset()" attrs="486">
+        <size>6</size>
+      </method>
+      <method name="System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+        <size>14</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerator`1[System.Int32] System.Collections.Generic.IEnumerable&lt;int&gt;.GetEnumerator()" attrs="481">
+        <size>40</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="X+&lt;Test2&gt;c__Iterator1">
+      <method name="Boolean MoveNext()" attrs="486">
+        <size>161</size>
+      </method>
+      <method name="System.String System.Collections.Generic.IEnumerator&lt;string&gt;.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+        <size>14</size>
+      </method>
+      <method name="Void Dispose()" attrs="486">
+        <size>15</size>
+      </method>
+      <method name="Void Reset()" attrs="486">
+        <size>6</size>
+      </method>
+      <method name="System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+        <size>14</size>
+      </method>
+      <method name="System.Collections.Generic.IEnumerator`1[System.String] System.Collections.Generic.IEnumerable&lt;string&gt;.GetEnumerator()" attrs="481">
+        <size>40</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-pragma-unrecognized.cs">
     <type name="C">
       <method name="Void Main()" attrs="150">