[mcs] Parentheses expression can act as conditional access receiver. Fixes #32130
authorMarek Safar <marek.safar@gmail.com>
Mon, 20 Jul 2015 16:41:06 +0000 (18:41 +0200)
committerMarek Safar <marek.safar@gmail.com>
Mon, 20 Jul 2015 16:41:06 +0000 (18:41 +0200)
mcs/mcs/expression.cs
mcs/tests/test-null-operator-010.cs [deleted file]
mcs/tests/test-null-operator-011.cs [deleted file]
mcs/tests/test-null-operator-13.cs [new file with mode: 0644]
mcs/tests/test-null-operator-14.cs [new file with mode: 0644]
mcs/tests/test-null-operator-15.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

index b958df38305b7dd65047b6d3f16aa94dfb0e076c..96248f3571a2cca6b90a325b66a1df77a8e7110e 100644 (file)
@@ -101,19 +101,41 @@ namespace Mono.CSharp
 
        public class ParenthesizedExpression : ShimExpression
        {
+               bool conditional_access_receiver;
+
                public ParenthesizedExpression (Expression expr, Location loc)
                        : base (expr)
                {
                        this.loc = loc;
                }
 
-               protected override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext rc)
                {
-                       var res = expr.Resolve (ec);
+                       Expression res = null;
+
+                       if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
+                               if (expr.HasConditionalAccess ()) {
+                                       conditional_access_receiver = true;
+                                       using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
+                                               res = expr.Resolve (rc);
+                                       }
+                               }
+                       }
+
+                       if (!conditional_access_receiver)
+                               res = expr.Resolve (rc);
+
                        var constant = res as Constant;
                        if (constant != null && constant.IsLiteral)
                                return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
 
+                       if (conditional_access_receiver) {
+                               expr = res;
+                               type = LiftMemberType (rc, res.Type);
+                               eclass = expr.eclass;
+                               return this;
+                       }
+
                        return res;
                }
 
@@ -127,9 +149,21 @@ namespace Mono.CSharp
                        return visitor.Visit (this);
                }
 
+               public override void Emit (EmitContext ec)
+               {
+                       if (!conditional_access_receiver)
+                               base.Emit (ec);
+
+                       var prev = ec.ConditionalAccess;
+                       ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
+                       expr.Emit (ec);
+                       ec.CloseConditionalAccess (type.IsNullableType ? type : null);
+                       ec.ConditionalAccess = prev;
+               }
+
                public override bool HasConditionalAccess ()
                {
-                       return expr.HasConditionalAccess ();
+                       return false;
                }
        }
        
diff --git a/mcs/tests/test-null-operator-010.cs b/mcs/tests/test-null-operator-010.cs
deleted file mode 100644 (file)
index 2d72403..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-
-class Test
-{
-       static void Main ()
-       {
-               Test_1 ("");
-               Test_1<object> (null);
-
-               Test_2<object> (null);
-               Test_2 ("z");
-               Test_2 (0);
-               Test_2 ((long?) -8);
-
-               Test_3 (new int[1]);
-               Test_3 (new int[] { 5 });
-       }
-
-       static void Test_1<T> (T x) where T : class
-       {
-               x?.Call ();
-       }
-
-       static void Test_2<T> (T x)
-       {
-               x?.Call ();
-       }
-
-       static void Test_3<T> (T[] x)
-       {
-               x[0]?.Call ();
-       }
-}
-
-static class Ext
-{
-       public static void Call<T> (this T t)
-       {
-               Console.WriteLine (typeof (T));
-       }
-}
diff --git a/mcs/tests/test-null-operator-011.cs b/mcs/tests/test-null-operator-011.cs
deleted file mode 100644 (file)
index 9c116a4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-static class Crash
-{
-       static string GetFoo ()
-       {
-               return null;
-       }
-
-       static void Main ()
-       {
-               (GetFoo ()?.ToLower ()).ToUpper ();
-       }
-}
diff --git a/mcs/tests/test-null-operator-13.cs b/mcs/tests/test-null-operator-13.cs
new file mode 100644 (file)
index 0000000..4979113
--- /dev/null
@@ -0,0 +1,41 @@
+using System;
+
+static class Crash
+{
+       static X GetFoo ()
+       {
+               return null;
+       }
+
+       static int Main ()
+       {
+               int res = (GetFoo ()?.ToLower ()).ToUpper ();
+               if (res != 0)
+                       return 1;
+
+               return 0;
+       }
+}
+
+class X
+{
+       public Y ToLower ()
+       {
+               throw new ApplicationException ("should not be called");
+       }
+}
+
+class Y
+{
+}
+
+static class SS
+{
+       public static int ToUpper (this Y y)
+       {
+               if (y != null)
+                       return 1;
+
+               return 0;
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-null-operator-14.cs b/mcs/tests/test-null-operator-14.cs
new file mode 100644 (file)
index 0000000..2d72403
--- /dev/null
@@ -0,0 +1,41 @@
+using System;
+
+class Test
+{
+       static void Main ()
+       {
+               Test_1 ("");
+               Test_1<object> (null);
+
+               Test_2<object> (null);
+               Test_2 ("z");
+               Test_2 (0);
+               Test_2 ((long?) -8);
+
+               Test_3 (new int[1]);
+               Test_3 (new int[] { 5 });
+       }
+
+       static void Test_1<T> (T x) where T : class
+       {
+               x?.Call ();
+       }
+
+       static void Test_2<T> (T x)
+       {
+               x?.Call ();
+       }
+
+       static void Test_3<T> (T[] x)
+       {
+               x[0]?.Call ();
+       }
+}
+
+static class Ext
+{
+       public static void Call<T> (this T t)
+       {
+               Console.WriteLine (typeof (T));
+       }
+}
diff --git a/mcs/tests/test-null-operator-15.cs b/mcs/tests/test-null-operator-15.cs
new file mode 100644 (file)
index 0000000..35f16ae
--- /dev/null
@@ -0,0 +1,16 @@
+using System.Linq;
+using System.Collections.Generic;
+
+class MM
+{
+       public IEnumerable<int> myEnumerable { get; set; }
+}
+
+class Test
+{
+       public static void Main ()
+       {
+               MM myobject = null;
+               (myobject?.myEnumerable?.Any ()).GetValueOrDefault (false);      
+       }
+}
index 37c936b86d26a970e19a903217d41536dc9d5c18..5d0fbb5ad56681378298eeddc4c8d191fa230d85 100644 (file)
       </method>
     </type>
   </test>
-  <test name="test-null-operator-010.cs">
-    <type name="Test">
-      <method name="Void Main()" attrs="145">
-        <size>79</size>
-      </method>
-      <method name="Void Test_1[T](T)" attrs="145">
-        <size>22</size>
-      </method>
-      <method name="Void Test_2[T](T)" attrs="145">
-        <size>21</size>
-      </method>
-      <method name="Void Test_3[T](T[])" attrs="145">
-        <size>28</size>
-      </method>
-      <method name="Void .ctor()" attrs="6278">
-        <size>7</size>
-      </method>
-    </type>
-    <type name="Ext">
-      <method name="Void Call[T](T)" attrs="150">
-        <size>17</size>
-      </method>
-    </type>
-  </test>
-  <test name="test-null-operator-011.cs">
-    <type name="Crash">
-      <method name="System.String GetFoo()" attrs="145">
-        <size>10</size>
-      </method>
-      <method name="Void Main()" attrs="145">
-        <size>27</size>
-      </method>
-    </type>
-  </test>
   <test name="test-null-operator-02.cs">
     <type name="CI">
       <method name="Int32 get_Prop()" attrs="2182">
       </method>
     </type>
   </test>
+  <test name="test-null-operator-13.cs">
+    <type name="Crash">
+      <method name="X GetFoo()" attrs="145">
+        <size>10</size>
+      </method>
+      <method name="Int32 Main()" attrs="145">
+        <size>49</size>
+      </method>
+    </type>
+    <type name="X">
+      <method name="Y ToLower()" attrs="134">
+        <size>12</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Y">
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="SS">
+      <method name="Int32 ToUpper(Y)" attrs="150">
+        <size>23</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-null-operator-14.cs">
+    <type name="Test">
+      <method name="Void Main()" attrs="145">
+        <size>79</size>
+      </method>
+      <method name="Void Test_1[T](T)" attrs="145">
+        <size>22</size>
+      </method>
+      <method name="Void Test_2[T](T)" attrs="145">
+        <size>21</size>
+      </method>
+      <method name="Void Test_3[T](T[])" attrs="145">
+        <size>28</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Ext">
+      <method name="Void Call[T](T)" attrs="150">
+        <size>17</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-null-operator-15.cs">
+    <type name="MM">
+      <method name="System.Collections.Generic.IEnumerable`1[System.Int32] get_myEnumerable()" attrs="2182">
+        <size>14</size>
+      </method>
+      <method name="Void set_myEnumerable(System.Collections.Generic.IEnumerable`1[System.Int32])" attrs="2182">
+        <size>8</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Test">
+      <method name="Void Main()" attrs="150">
+        <size>65</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-partial-01.cs">
     <type name="Foo.Hello">
       <method name="Void .ctor()" attrs="6278">