[mcs] null operator receiver type needs to be convertible to null. Fixes #40493
authorMarek Safar <marek.safar@gmail.com>
Wed, 20 Apr 2016 12:23:19 +0000 (14:23 +0200)
committerMarek Safar <marek.safar@gmail.com>
Wed, 20 Apr 2016 12:26:04 +0000 (14:26 +0200)
mcs/errors/cs0023-27.cs [new file with mode: 0644]
mcs/errors/cs0023-28.cs [new file with mode: 0644]
mcs/errors/cs0023-29.cs [new file with mode: 0644]
mcs/mcs/codegen.cs
mcs/mcs/delegate.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/tests/test-null-operator-04.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

diff --git a/mcs/errors/cs0023-27.cs b/mcs/errors/cs0023-27.cs
new file mode 100644 (file)
index 0000000..068c08a
--- /dev/null
@@ -0,0 +1,13 @@
+// CS0023: The `?' operator cannot be applied to operand of type `T'
+// Line: 11
+
+class C2<T>
+{
+       C2<T> i;
+       T field;
+
+       public void Foo ()
+       {
+               var x = i?.field;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs0023-28.cs b/mcs/errors/cs0023-28.cs
new file mode 100644 (file)
index 0000000..e9f7942
--- /dev/null
@@ -0,0 +1,15 @@
+// CS0023: The `?' operator cannot be applied to operand of type `T'
+// Line: 13
+
+interface IFoo<T>
+{
+       T Call ();
+}
+
+class C1
+{
+       U Foo<T, U> (IFoo<T> t)
+       {
+               return t?.Call ();
+       }
+}
diff --git a/mcs/errors/cs0023-29.cs b/mcs/errors/cs0023-29.cs
new file mode 100644 (file)
index 0000000..aea3068
--- /dev/null
@@ -0,0 +1,10 @@
+// CS0023: The `?' operator cannot be applied to operand of type `T'
+// Line: 8
+
+class X
+{
+       static void Bug<T>(System.Func<T> func)
+       {
+               var r = func?.Invoke ();
+       }
+}
\ No newline at end of file
index 1dfb747ba6a46f96ebff889b48259408c371f46a..d5ba75c12813af9d07e4b3182134f82cc3e557f9 100644 (file)
@@ -1263,10 +1263,15 @@ namespace Mono.CSharp
 
                        if (conditionalAccess) {
                                if (!ec.ConditionalAccess.Statement) {
-                                       if (ec.ConditionalAccess.Type.IsNullableType)
-                                               Nullable.LiftedNull.Create (ec.ConditionalAccess.Type, Location.Null).Emit (ec);
-                                       else
+                                       var t = ec.ConditionalAccess.Type;
+                                       if (t.IsNullableType)
+                                               Nullable.LiftedNull.Create (t, Location.Null).Emit (ec);
+                                       else {
                                                ec.EmitNull ();
+
+                                               if (t.IsGenericParameter)
+                                                       ec.Emit (OpCodes.Unbox_Any, t);
+                                       }
                                }
 
                                ec.Emit (OpCodes.Br, ec.ConditionalAccess.EndLabel);
index 8553856ac585229093f9edb551cd9f993ce78276..4a0e4af6fc896df171530249f820649ebb8df0d5 100644 (file)
@@ -535,7 +535,7 @@ namespace Mono.CSharp {
 
                void ResolveConditionalAccessReceiver (ResolveContext rc)
                {
-                       // LAMESPEC: Not sure why this is explicitly disalloed with very odd error message
+                       // LAMESPEC: Not sure why this is explicitly disallowed with very odd error message
                        if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && method_group.HasConditionalAccess ()) {
                                Error_OperatorCannotBeApplied (rc, loc, "?", method_group.Type);
                        }
index be79b14e86fc012de410ccd9af58bed2de6727f2..fc99defc44e19359646b879d59bb7feb63bba902 100644 (file)
@@ -469,8 +469,13 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
+               protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
                {
+                       var tps = type as TypeParameterSpec;
+                       if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
+                               Error_OperatorCannotBeApplied (rc, loc, "?", type);
+                       }
+
                        return TypeSpec.IsValueType (type) && !type.IsNullableType ?
                                Nullable.NullableInfo.MakeType (rc.Module, type) :
                                type;
@@ -1332,7 +1337,7 @@ namespace Mono.CSharp {
                {
                }
 
-               public ExpressionStatement ResolveStatement (BlockContext ec)
+               public virtual ExpressionStatement ResolveStatement (BlockContext ec)
                {
                        Expression e = Resolve (ec);
                        if (e == null)
index b011b264250dab49906455a83bc8e0fe8f7ea3a0..aadf818066d2ad89b3d82a2b8488256753e09d9c 100644 (file)
@@ -7023,6 +7023,16 @@ namespace Mono.CSharp
                        }
                }
 
+               bool statement_resolve;
+               public override ExpressionStatement ResolveStatement (BlockContext bc)
+               {
+                       statement_resolve = true;
+                       var es = base.ResolveStatement (bc);
+                       statement_resolve = false;
+
+                       return es;
+               }
+
                protected override Expression DoResolve (ResolveContext rc)
                {
                        ResolveConditionalAccessReceiver (rc);
@@ -7111,7 +7121,7 @@ namespace Mono.CSharp
 
                        var method = mg.BestCandidate;
                        type = mg.BestCandidateReturnType;
-                       if (conditional_access_receiver)
+                       if (conditional_access_receiver && !statement_resolve)
                                type = LiftMemberType (ec, type);
 
                        if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
diff --git a/mcs/tests/test-null-operator-04.cs b/mcs/tests/test-null-operator-04.cs
new file mode 100644 (file)
index 0000000..c28aa17
--- /dev/null
@@ -0,0 +1,55 @@
+using System;
+
+interface IFoo<T>
+{
+       T Call ();
+}
+
+class C1
+{
+       public void Foo<T> (IFoo<T> t) where T : class
+       {
+               t?.Call ();
+               var x = t?.Call ();
+       }
+
+       public void Foo2<T> (IFoo<T> t)
+       {
+               t?.Call ();
+       }       
+}
+
+class C2<T> where T : class
+{
+       C2<T> i;
+       T field;
+
+       public void Foo ()
+       {
+               var x = i?.field;
+       }
+}
+
+class Program
+{
+       static void Test<T>(Func<T> func) where T : struct
+       {
+               var r = func?.Invoke ();
+       }
+
+       static void Test2<T>(Func<T> func)
+       {
+               func?.Invoke ();
+       }
+
+       static void Main()
+       {
+               new C1 ().Foo<Program> (null);
+               new C1 ().Foo2<Program> (null);
+
+               new C2<string> ().Foo ();
+
+               Test (() => 1);
+               Test (() => 2);
+       }
+}
\ No newline at end of file
index a395cb4cf763feba3bc83cb76ee5ffd691bc5c08..027fd9871ef422bf008dc6f7e66ff4196ed13027 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-null-operator-04.cs">
+    <type name="C1">
+      <method name="Void Foo[T](IFoo`1[T])" attrs="134">
+        <size>38</size>
+      </method>
+      <method name="Void Foo2[T](IFoo`1[T])" attrs="134">
+        <size>17</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="C2`1[T]">
+      <method name="Void Foo()" attrs="134">
+        <size>33</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Program">
+      <method name="Void Test[T](System.Func`1[T])" attrs="145">
+        <size>31</size>
+      </method>
+      <method name="Void Test2[T](System.Func`1[T])" attrs="145">
+        <size>17</size>
+      </method>
+      <method name="Void Main()" attrs="145">
+        <size>102</size>
+      </method>
+      <method name="Int32 &lt;Main&gt;m__0()" attrs="145">
+        <size>9</size>
+      </method>
+      <method name="Int32 &lt;Main&gt;m__1()" attrs="145">
+        <size>9</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-null-operator-05.cs">
     <type name="CI">
       <method name="Void set_Item(System.String, System.String)" attrs="2182">