Nullable types can satisfy only identity or base type constraints
authorMarek Safar <marek.safar@gmail.com>
Sun, 30 Oct 2011 08:58:41 +0000 (08:58 +0000)
committerMarek Safar <marek.safar@gmail.com>
Wed, 2 Nov 2011 11:09:47 +0000 (11:09 +0000)
mcs/errors/cs0312-2.cs [new file with mode: 0644]
mcs/errors/cs0312-3.cs [new file with mode: 0644]
mcs/errors/cs0312.cs [new file with mode: 0644]
mcs/errors/cs0313-2.cs [new file with mode: 0644]
mcs/errors/cs0313.cs
mcs/mcs/generic.cs
mcs/tests/gtest-563.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0312-2.cs b/mcs/errors/cs0312-2.cs
new file mode 100644 (file)
index 0000000..bc579b6
--- /dev/null
@@ -0,0 +1,18 @@
+// CS0312: The type `E?' cannot be used as type parameter `T' in the generic type or method `C<E>.Foo<T>(T)'. The nullable type `E?' does not satisfy constraint `E'
+// Line: 16
+
+enum E
+{
+}
+
+class C<U>
+{
+       static void Foo<T> (T value) where T : U
+       {
+       }
+
+       static void Test (E? e)
+       {
+               C<E>.Foo (e);
+       }
+}
diff --git a/mcs/errors/cs0312-3.cs b/mcs/errors/cs0312-3.cs
new file mode 100644 (file)
index 0000000..9257697
--- /dev/null
@@ -0,0 +1,18 @@
+// CS0312: The type `E?' cannot be used as type parameter `T' in the generic type or method `C<System.Enum>.Foo<T>(T)'. The nullable type `E?' does not satisfy constraint `System.Enum'
+// Line: 16
+
+enum E
+{
+}
+
+class C<U>
+{
+       static void Foo<T> (T value) where T : U
+       {
+       }
+
+       static void Test (E? s)
+       {
+               C<System.Enum>.Foo (s);
+       }
+}
diff --git a/mcs/errors/cs0312.cs b/mcs/errors/cs0312.cs
new file mode 100644 (file)
index 0000000..431818f
--- /dev/null
@@ -0,0 +1,18 @@
+// CS0312: The type `S?' cannot be used as type parameter `T' in the generic type or method `C<S>.Foo<T>(T)'. The nullable type `S?' does not satisfy constraint `S'
+// Line: 16
+
+struct S
+{
+}
+
+class C<U>
+{
+       static void Foo<T> (T value) where T : U
+       {
+       }
+
+       static void Test (S? s)
+       {
+               C<S>.Foo (s);
+       }
+}
diff --git a/mcs/errors/cs0313-2.cs b/mcs/errors/cs0313-2.cs
new file mode 100644 (file)
index 0000000..7489c65
--- /dev/null
@@ -0,0 +1,22 @@
+// CS0313: The type `S?' cannot be used as type parameter `T' in the generic type or method `C<I>.Foo<T>(T)'. The nullable type `S?' never satisfies interface constraint `I'
+// Line: 20
+
+struct S : I
+{
+}
+
+interface I
+{
+}
+
+class C<U>
+{
+       static void Foo<T> (T value) where T : U
+       {
+       }
+
+       static void Bar (S? s)
+       {
+               C<I>.Foo (s);
+       }
+}
index 17fe7bc883f6d1dbcd6a4a05836bb81ab9eccfee..13ac1b3c80ab0347df02b80aa7aae343e5c8cd57 100644 (file)
@@ -1,4 +1,4 @@
-// CS0313: The type `S?' cannot be used as type parameter `T' in the generic type or method `S.Foo<T>(T)'. The nullable type `S?' never satisfies interface constraint
+// CS0313: The type `S?' cannot be used as type parameter `T' in the generic type or method `S.Foo<T>(T)'. The nullable type `S?' never satisfies interface constraint `I'
 // Line: 16
 
 interface I
index 871ca9e2bbf116fdbfa186b633b4dba7975631ea..444e9e62780efbc619624e9fba8b77720cb849aa 100644 (file)
@@ -2240,35 +2240,25 @@ namespace Mono.CSharp {
                        // Check the interfaces constraints
                        //
                        if (tparam.Interfaces != null) {
-                               if (atype.IsNullableType) {
-                                       if (mc == null)
-                                               return false;
+                               foreach (TypeSpec iface in tparam.Interfaces) {
+                                       var dep = iface.GetMissingDependencies ();
+                                       if (dep != null) {
+                                               if (mc == null)
+                                                       return false;
 
-                                       mc.Module.Compiler.Report.Error (313, loc,
-                                               "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint",
-                                               atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
-                                       ok = false;
-                               } else {
-                                       foreach (TypeSpec iface in tparam.Interfaces) {
-                                               var dep = iface.GetMissingDependencies ();
-                                               if (dep != null) {
-                                                       if (mc == null)
-                                                               return false;
+                                               ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
+                                               ok = false;
 
-                                                       ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
-                                                       ok = false;
+                                               // return immediately to avoid duplicate errors because we are scanning
+                                               // expanded interface list
+                                               return false;
+                                       }
 
-                                                       // return immediately to avoid duplicate errors because we are scanning
-                                                       // expanded interface list
+                                       if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
+                                               if (mc == null)
                                                        return false;
-                                               }
-
-                                               if (!CheckConversion (mc, context, atype, tparam, iface, loc)) {
-                                                       if (mc == null)
-                                                               return false;
 
-                                                       ok = false;
-                                               }
+                                               ok = false;
                                        }
                                }
                        }
@@ -2340,11 +2330,20 @@ namespace Mono.CSharp {
                                        return true;
 
                        } else if (TypeSpec.IsValueType (atype)) {
-                               if (Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
-                                       return true;
+                               if (atype.IsNullableType) {
+                                       //
+                                       // LAMESPEC: Only identity or base type ValueType or Object satisfy nullable type
+                                       //
+                                       if (TypeSpec.IsBaseClass (atype, ttype, false))
+                                               return true;
+                               } else {
+                                       if (Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
+                                               return true;
+                               }
                        } else {
                                var expr = new EmptyExpression (atype);
-                               if (Convert.ImplicitStandardConversionExists (expr, ttype))
+                               if (Convert.ImplicitReferenceConversionExists (atype, ttype) || Convert.ImplicitBoxingConversion (null, atype, ttype) != null)
+                               //      Convert.ImplicitStandardConversionExists (expr, ttype))
                                        return true;
                        }
 
@@ -2363,9 +2362,21 @@ namespace Mono.CSharp {
                                                "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
                                } else if (TypeSpec.IsValueType (atype)) {
-                                       mc.Module.Compiler.Report.Error (315, loc,
-                                               "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'",
-                                               atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+                                       if (atype.IsNullableType) {
+                                               if (ttype.IsInterface) {
+                                                       mc.Module.Compiler.Report.Error (313, loc,
+                                                               "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint `{3}'",
+                                                               atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+                                               } else {
+                                                       mc.Module.Compiler.Report.Error (312, loc,
+                                                               "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' does not satisfy constraint `{3}'",
+                                                               atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+                                               }
+                                       } else {
+                                               mc.Module.Compiler.Report.Error (315, loc,
+                                                       "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'",
+                                                       atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+                                       }
                                } else {
                                        mc.Module.Compiler.Report.Error (311, loc,
                                                "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'",
diff --git a/mcs/tests/gtest-563.cs b/mcs/tests/gtest-563.cs
new file mode 100644 (file)
index 0000000..a5b208b
--- /dev/null
@@ -0,0 +1,27 @@
+using System;
+
+struct S
+{
+}
+
+class C<U>
+{
+       static void Foo<T> (T value) where T : U
+       {
+       }
+
+       public static void Test (S? s)
+       {
+               C<S?>.Foo (s);
+               C<ValueType>.Foo (s);
+               C<object>.Foo (s);
+       }
+}
+
+class M
+{
+       public static void Main ()
+       {
+               C<int>.Test (null);
+       }
+}
\ No newline at end of file
index b2f49298e7ed729638ee07d1f32a16722bd229bc..fb458d08d2930b754223fe20492ff45f1ae1d146 100644 (file)
       </method>
     </type>
   </test>
+  <test name="gtest-563.cs">
+    <type name="C`1[U]">
+      <method name="Void Foo[T](T)">
+        <size>1</size>
+      </method>
+      <method name="Void Test(Nullable`1)">
+        <size>19</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="M">
+      <method name="Void Main()">
+        <size>15</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="gtest-anon-type-12.cs">
     <type name="C">
       <method name="Int32 Main()">