[mcs] Fix using type relationship check for type parameters. Fixes #18639
authorMarek Safar <marek.safar@gmail.com>
Fri, 2 May 2014 08:11:38 +0000 (10:11 +0200)
committerMarek Safar <marek.safar@gmail.com>
Fri, 2 May 2014 08:12:59 +0000 (10:12 +0200)
mcs/mcs/statement.cs
mcs/tests/gtest-608.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

index ce96b6971dbfddf01628aa8808c175b3b5a8be3c..cbce03f2bc5506facff0ca588a77ec51cef52df0 100644 (file)
@@ -6849,7 +6849,7 @@ namespace Mono.CSharp {
                        {
                                var type = li.Type;
 
-                               if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
+                               if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
                                        if (type.IsNullableType) {
                                                // it's handled in CreateDisposeCall
                                                return;
@@ -6866,6 +6866,16 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
+                       {
+                               var target = bc.BuiltinTypes.IDisposable;
+                               var tp = type as TypeParameterSpec;
+                               if (tp != null)
+                                       return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
+
+                               return type.ImplementsInterface (target, false);
+                       }
+
                        protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
                        {
                                var lvr = lv.CreateReferenceExpression (bc, lv.Location);
@@ -6886,7 +6896,7 @@ namespace Mono.CSharp {
                                Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
 
                                // Add conditional call when disposing possible null variable
-                               if (!type.IsStruct || type.IsNullableType)
+                               if (!TypeSpec.IsValueType (type) || type.IsNullableType)
                                        dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
 
                                return dispose;
diff --git a/mcs/tests/gtest-608.cs b/mcs/tests/gtest-608.cs
new file mode 100644 (file)
index 0000000..d675165
--- /dev/null
@@ -0,0 +1,43 @@
+using System;
+
+class R<T, U>
+       where T : System.IDisposable
+       where U : T
+{
+       public void M (U u)
+       {
+               using (u) {
+               }
+       }
+}
+
+struct S<T, U>
+       where T : System.IDisposable
+       where U : struct, T
+{
+       public void M (U u)
+       {
+               using (u) {
+               }
+       }
+}
+
+class X : IDisposable
+{
+       public void Dispose ()
+       {
+       }
+
+       public static void Main ()
+       {
+               new R<X, X> ().M (new X ());
+               new S<Y, Y> ().M (new Y ());
+       }
+}
+
+struct Y : IDisposable
+{
+       public void Dispose ()
+       {
+       }
+}
\ No newline at end of file
index 3588970efd4858924c057d303b105171567ab7a8..fa8b1d9933f58884b56632a2f30ed16a8e910e19 100644 (file)
       </method>\r
     </type>\r
   </test>\r
+  <test name="gtest-608.cs">\r
+    <type name="R`2[T,U]">\r
+      <method name="Void M(U)" attrs="134">\r
+        <size>36</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="S`2[T,U]">\r
+      <method name="Void M(U)" attrs="134">\r
+        <size>25</size>\r
+      </method>\r
+    </type>\r
+    <type name="X">\r
+      <method name="Void Dispose()" attrs="486">\r
+        <size>2</size>\r
+      </method>\r
+      <method name="Void Main()" attrs="150">\r
+        <size>41</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+    <type name="Y">\r
+      <method name="Void Dispose()" attrs="486">\r
+        <size>2</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
   <test name="gtest-anontype-01.cs">\r
     <type name="Test">\r
       <method name="Int32 Main()" attrs="150">\r