Don't check inferred dynamic type arguments against best candidate constraints.
authorMarek Safar <marek.safar@gmail.com>
Mon, 20 Sep 2010 15:08:46 +0000 (16:08 +0100)
committerMarek Safar <marek.safar@gmail.com>
Mon, 20 Sep 2010 15:10:43 +0000 (16:10 +0100)
mcs/errors/known-issues-dmcs
mcs/mcs/ecore.cs
mcs/mcs/generic.cs
mcs/tests/dtest-017.cs
mcs/tests/dtest-028.cs
mcs/tests/dtest-030.cs [new file with mode: 0644]
mcs/tests/dtest-collectioninit-01.cs [new file with mode: 0644]
mcs/tests/dtest-etree-01.cs [new file with mode: 0644]
mcs/tests/ver-il-dmcs.xml

index b2a5dca511ea3b0b4e17c229de08015393982e43..522f471bfbdd30dd55a15d807dafde1f552af7b5 100644 (file)
@@ -11,7 +11,6 @@
 # csXXXX.cs NO ERROR   : error test case doesn't report any error. An exception is considered
 #                        as NO ERROR and CS5001 is automatically ignored.
 
-cs0158-5.cs
 cs0162-7.cs NO ERROR
 
 # Operators
index 3ab3ec5b107cee5ad673c2841d1128525ebed3c2..1547bdf467cbbfea66775e9e2c6c370a94b00600 100644 (file)
@@ -3643,6 +3643,9 @@ namespace Mono.CSharp {
                        //
                        var ms = candidate as MethodSpec;
                        if (ms != null && ms.IsGeneric) {
+                               // Setup constraint checker for probing only
+                               ConstraintChecker cc = new ConstraintChecker (null);
+
                                if (type_arguments != null) {
                                        var g_args_count = ms.Arity;
                                        if (g_args_count != type_arguments.Count)
@@ -3658,20 +3661,25 @@ namespace Mono.CSharp {
                                                prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
                                        }
 
-                                       score = TypeManager.InferTypeArguments (ec, arguments, ref ms);
+                                       var ti = new TypeInference (arguments);
+                                       TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
                                        lambda_conv_msgs.EndSession ();
 
-                                       if (score != 0)
-                                               return score - 20000;
+                                       if (i_args == null)
+                                               return ti.InferenceScore - 20000;
 
-                                       candidate = ms;
-                                       pd = ms.Parameters;
+                                       if (i_args.Length != 0) {
+                                               candidate = ms = ms.MakeGenericMethod (i_args);
+                                               pd = ms.Parameters;
+                                       }
+
+                                       cc.IgnoreInferredDynamic = true;
                                }
 
                                //
-                               // Type arguments constraints have to match
+                               // Type arguments constraints have to match for the method to be applicable
                                //
-                               if (!ConstraintChecker.CheckAll (null, ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
+                               if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
                                        return int.MaxValue - 25000;
 
                        } else {
@@ -4139,7 +4147,7 @@ namespace Mono.CSharp {
                                        if (ms != null && ms.IsGeneric) {
                                                bool constr_ok = true;
                                                if (ms.TypeArguments != null)
-                                                       constr_ok = ConstraintChecker.CheckAll (rc.MemberContext, ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
+                                                       constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
 
                                                if (ta_count == 0) {
                                                        if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
index 2fb4a997c8643ba756cc9a9e93e3054389235bc4..3f3d7be5a396a70a07f2e257908421c2c20d4fcb 100644 (file)
@@ -1782,7 +1782,7 @@ namespace Mono.CSharp {
                        if (constraints == null)
                                return true;
 
-                       return ConstraintChecker.CheckAll (ec, open_type, args.Arguments, constraints, loc);
+                       return new ConstraintChecker(ec).CheckAll (open_type, args.Arguments, constraints, loc);
                }
        
                public override bool CheckAccessLevel (IMemberContext mc)
@@ -1858,23 +1858,48 @@ namespace Mono.CSharp {
                }
        }
 
-       static class ConstraintChecker
+       struct ConstraintChecker
        {
+               IMemberContext mc;
+               bool ignore_inferred_dynamic;
+
+               public ConstraintChecker (IMemberContext ctx)
+               {
+                       this.mc = ctx;
+                       ignore_inferred_dynamic = false;
+               }
+
+               #region Properties
+
+               public bool IgnoreInferredDynamic {
+                       get {
+                               return ignore_inferred_dynamic;
+                       }
+                       set {
+                               ignore_inferred_dynamic = value;
+                       }
+               }
+
+               #endregion
+
                //
                // Checks all type arguments againts type parameters constraints
                // NOTE: It can run in probing mode when `mc' is null
                //
-               public static bool CheckAll (IMemberContext mc, MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc)
+               public bool CheckAll (MemberSpec context, TypeSpec[] targs, TypeParameterSpec[] tparams, Location loc)
                {
                        for (int i = 0; i < tparams.Length; i++) {
-                               if (!CheckConstraint (mc, context, targs [i], tparams [i], loc))
+                               if (ignore_inferred_dynamic && targs[i] == InternalType.Dynamic)
+                                       continue;
+
+                               if (!CheckConstraint (context, targs [i], tparams [i], loc))
                                        return false;
                        }
 
                        return true;
                }
 
-               static bool CheckConstraint (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc)
+               bool CheckConstraint (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, Location loc)
                {
                        //
                        // First, check the `class' and `struct' constraints.
@@ -1956,22 +1981,47 @@ namespace Mono.CSharp {
                        return ok;
                }
 
-               static bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
+               static bool HasDynamicTypeArgument (TypeSpec[] targs)
+               {
+                       for (int i = 0; i < targs.Length; ++i) {
+                               var targ = targs [i];
+                               if (targ == InternalType.Dynamic)
+                                       return true;
+
+                               if (HasDynamicTypeArgument (targ.TypeArguments))
+                                       return true;
+                       }
+
+                       return false;
+               }
+
+               bool CheckConversion (IMemberContext mc, MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc)
                {
                        var expr = new EmptyExpression (atype);
                        if (Convert.ImplicitStandardConversionExists (expr, ttype))
                                return true;
 
+                       //
+                       // When partial/full type inference finds a dynamic type argument delay
+                       // the constraint check to runtime, it can succeed for real underlying
+                       // dynamic type
+                       //
+                       if (ignore_inferred_dynamic && HasDynamicTypeArgument (ttype.TypeArguments))
+                               return true;
+
                        if (mc != null) {
                                mc.Compiler.Report.SymbolRelatedToPreviousError (tparam);
                                if (TypeManager.IsValueType (atype)) {
-                                       mc.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}'",
+                                       mc.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 if (atype.IsGenericParameter) {
-                                       mc.Compiler.Report.Error (314, loc, "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}'",
+                                       mc.Compiler.Report.Error (314, loc,
+                                               "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 {
-                                       mc.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}'",
+                                       mc.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}'",
                                                atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
                                }
                        }
@@ -1979,7 +2029,7 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               static bool HasDefaultConstructor (TypeSpec atype)
+               bool HasDefaultConstructor (TypeSpec atype)
                {
                        var tp = atype as TypeParameterSpec;
                        if (tp != null) {
@@ -2167,76 +2217,34 @@ namespace Mono.CSharp {
 
                        return Variance.None;
                }
-
-               /// <summary>
-               ///   Type inference.  Try to infer the type arguments from `method',
-               ///   which is invoked with the arguments `arguments'.  This is used
-               ///   when resolving an Invocation or a DelegateInvocation and the user
-               ///   did not explicitly specify type arguments.
-               /// </summary>
-               public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodSpec method)
-               {
-                       ATypeInference ti = ATypeInference.CreateInstance (arguments);
-                       TypeSpec[] i_args = ti.InferMethodArguments (ec, method);
-                       if (i_args == null)
-                               return ti.InferenceScore;
-
-                       if (i_args.Length == 0)
-                               return 0;
-
-                       method = method.MakeGenericMethod (i_args);
-                       return 0;
-               }
-       }
-
-       abstract class ATypeInference
-       {
-               protected readonly Arguments arguments;
-               protected readonly int arg_count;
-
-               protected ATypeInference (Arguments arguments)
-               {
-                       this.arguments = arguments;
-                       if (arguments != null)
-                               arg_count = arguments.Count;
-               }
-
-               public static ATypeInference CreateInstance (Arguments arguments)
-               {
-                       return new TypeInference (arguments);
-               }
-
-               public virtual int InferenceScore {
-                       get {
-                               return int.MaxValue;
-                       }
-               }
-
-               public abstract TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method);
        }
 
        //
        // Implements C# type inference
        //
-       class TypeInference : ATypeInference
+       class TypeInference
        {
                //
                // Tracks successful rate of type inference
                //
                int score = int.MaxValue;
+               readonly Arguments arguments;
+               readonly int arg_count;
 
                public TypeInference (Arguments arguments)
-                       : base (arguments)
                {
+                       this.arguments = arguments;
+                       if (arguments != null)
+                               arg_count = arguments.Count;
                }
 
-               public override int InferenceScore {
+               public int InferenceScore {
                        get {
                                return score;
                        }
                }
 
-               public override TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
+               public TypeSpec[] InferMethodArguments (ResolveContext ec, MethodSpec method)
                {
                        var method_generic_args = method.GenericDefinition.TypeParameters;
                        TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
index 9fcd0acfa998391b98d1e61fd9accc478d7295ff..ee4b8ba53576afcd05c392e87fdd33a9f141d70d 100644 (file)
@@ -16,6 +16,10 @@ interface IA<U>
 {
 }
 
+struct S<T>
+{
+}
+
 delegate dynamic D (dynamic d);
 
 class DynamicAssignments
@@ -48,6 +52,13 @@ class DynamicAssignments
                I<object> io = null;
                IA<dynamic> id = io;
                
+               IA<object> ia_o = null;
+               IA<dynamic> ia_d = ia_o;
+               
+               S<dynamic> s_d = new S<dynamic> ();
+               S<object> s_o = s_d;
+               S<object>? s_o_n = s_d;
+               
                D del = delegate (object del_arg) {
                         return (object) null;
                };
index 65b6b1a7ac3145c41561d1d262bbe02accae65c3..94c33799bde4a0103b2ab7a0eb1fa95db602a442 100644 (file)
@@ -13,6 +13,10 @@ class C
 
 public class Test
 {
+       static void M (ref dynamic[] d, ref object[] o)
+       {
+       }
+       
        public static int Main ()
        {
                dynamic d = new C ();
@@ -27,6 +31,9 @@ public class Test
                if (u != 40)
                        return 2;
                
+               object[] o = null;
+               M (ref o, ref o);
+               
                return 0;
        }
 }
diff --git a/mcs/tests/dtest-030.cs b/mcs/tests/dtest-030.cs
new file mode 100644 (file)
index 0000000..979e719
--- /dev/null
@@ -0,0 +1,40 @@
+using System;
+
+class A<T>
+{
+}
+
+class B
+{
+       static void M1<T> (T t) where T : struct
+       {
+       }
+       
+       static void M2<T, U> (T t, U u) where U : IEquatable<T>
+       {
+       }
+       
+       static void M3<T, U> (T t, A<U> u) where U : IEquatable<T>
+       {
+       }
+
+       static void M4<T, U> (T t, IEquatable<U> u) where T : IEquatable<U>
+       {
+       }
+
+       public static void Main ()
+       {
+               dynamic d = 2;
+               M1 (d);
+               
+               M2 (d, 6);
+               M2 (4, d);
+               
+               M3 (d, new A<int> ());
+               
+               M4 (d, 6);
+               // TODO: type inference
+               //M4 (4, d);
+       }
+}
+
diff --git a/mcs/tests/dtest-collectioninit-01.cs b/mcs/tests/dtest-collectioninit-01.cs
new file mode 100644 (file)
index 0000000..55bbbb7
--- /dev/null
@@ -0,0 +1,31 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+public class Test
+{
+       class Wrap
+       {
+               List<short> numbers = new List<short> ();
+               
+               public dynamic Numbers { 
+                       get { 
+                               return numbers;
+                       }
+               }
+       }
+       
+       static int Main ()
+       {
+               var a = new Wrap () {
+                       Numbers =  { 3, 9 }
+               };
+               
+               if (a.Numbers [1] != 9)
+                       return 1;
+               
+               Console.WriteLine ("OK");
+               return 0;
+       }
+}
+
diff --git a/mcs/tests/dtest-etree-01.cs b/mcs/tests/dtest-etree-01.cs
new file mode 100644 (file)
index 0000000..95553f9
--- /dev/null
@@ -0,0 +1,25 @@
+using System;
+using System.Linq.Expressions;
+
+public class C
+{
+       static void Conv1(Expression<Func<object, object>> l)
+       {
+       }
+       
+       static void Conv2(Expression<Func<dynamic, dynamic>> l)
+       {
+       }
+       
+       public static void Main ()
+       {
+               Expression<Func<object>> e1 = () => (dynamic) 1;
+               Expression<Func<dynamic>> e2 = () => (object) 1;
+               
+               Conv1 ((d) => (dynamic) 1);
+               Conv1 ((dynamic d) => d);
+               
+               Conv2 ((o) => (object) 1);
+               Conv2 ((object o) => o);
+       }
+}
\ No newline at end of file
index bdb33286ff1d378ec18533dea18ff7c53fe19cb1..c2db5c4ce367f199e3c91330274c625ba0b02e24 100644 (file)
     </type>
     <type name="DynamicAssignments">
       <method name="Int32 Main()">
-        <size>102</size>
+        <size>130</size>
       </method>
       <method name="System.Object &lt;Main&gt;m__0(System.Object)">
         <size>2</size>
     </type>
     <type name="Test">
       <method name="Int32 Main()">
-        <size>225</size>
+        <size>236</size>
       </method>
       <method name="Void .ctor()">
         <size>7</size>
         <size>0</size>
       </method>
     </type>
+    <type name="Test">
+      <method name="Void M(System.Object[] ByRef, System.Object[] ByRef)">
+        <size>1</size>
+      </method>
+    </type>
   </test>
   <test name="dtest-029.cs">
     <type name="C">
       </method>
     </type>
   </test>
+  <test name="dtest-030.cs">
+    <type name="A`1[T]">
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="B">
+      <method name="Void M1[T](T)">
+        <size>1</size>
+      </method>
+      <method name="Void M2[T,U](T, U)">
+        <size>1</size>
+      </method>
+      <method name="Void M3[T,U](T, A`1[U])">
+        <size>1</size>
+      </method>
+      <method name="Void M4[T,U](T, IEquatable`1)">
+        <size>1</size>
+      </method>
+      <method name="Void Main()">
+        <size>576</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="dtest-collectioninit-01.cs">
+    <type name="Test">
+      <method name="Int32 Main()">
+        <size>475</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Test+Wrap">
+      <method name="System.Object get_Numbers()">
+        <size>7</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>18</size>
+      </method>
+    </type>
+  </test>
   <test name="dtest-error-01.cs">
     <type name="Helper">
       <method name="Int32* Foo(Int32)">
       </method>
     </type>
   </test>
+  <test name="dtest-etree-01.cs">
+    <type name="C">
+      <method name="Void Conv1(System.Linq.Expressions.Expression`1[System.Func`2[System.Object,System.Object]])">
+        <size>1</size>
+      </method>
+      <method name="Void Conv2(System.Linq.Expressions.Expression`1[System.Func`2[System.Object,System.Object]])">
+        <size>1</size>
+      </method>
+      <method name="Void Main()">
+        <size>382</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="dtest-implicitarray-01.cs">
     <type name="C">
       <method name="Void Method()">
         <size>21</size>
       </method>
     </type>
+    <type name="A`1[T]">
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="ConditionalParsing">
+      <method name="Void Test_11()">
+        <size>7</size>
+      </method>
+    </type>
   </test>
   <test name="gtest-410.cs">
     <type name="Program">
         <size>7</size>
       </method>
       <method name="Void Invoke(SomeGenericClass`1+SomeHandlerType[SomeType])">
-        <size>1</size>
+        <size>7</size>
       </method>
       <method name="Void FailsToCompile()">
         <size>19</size>
     </type>
     <type name="SomeGenericClass`1[SomeType]">
       <method name="Void &lt;FailsToCompile&gt;m__0()">
-        <size>37</size>
+        <size>44</size>
       </method>
     </type>
     <type name="SomeGenericClass`1+&lt;FailsToCompile&gt;c__AnonStorey0[SomeType]">
     </type>
     <type name="C">
       <method name="Int32 &lt;Test&gt;m__0()">
-        <size>38</size>
+        <size>45</size>
       </method>
     </type>
     <type name="C+&lt;Test&gt;c__AnonStorey1">