From: Marek Safar Date: Mon, 20 Sep 2010 15:08:46 +0000 (+0100) Subject: Don't check inferred dynamic type arguments against best candidate constraints. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=8881d43ffd330b8323756a2e12f648761cde1d3f;p=mono.git Don't check inferred dynamic type arguments against best candidate constraints. --- diff --git a/mcs/errors/known-issues-dmcs b/mcs/errors/known-issues-dmcs index b2a5dca511e..522f471bfbd 100644 --- a/mcs/errors/known-issues-dmcs +++ b/mcs/errors/known-issues-dmcs @@ -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 diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 3ab3ec5b107..1547bdf467c 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -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)) diff --git a/mcs/mcs/generic.cs b/mcs/mcs/generic.cs index 2fb4a997c86..3f3d7be5a39 100644 --- a/mcs/mcs/generic.cs +++ b/mcs/mcs/generic.cs @@ -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; } - - /// - /// 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. - /// - 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); diff --git a/mcs/tests/dtest-017.cs b/mcs/tests/dtest-017.cs index 9fcd0acfa99..ee4b8ba5357 100644 --- a/mcs/tests/dtest-017.cs +++ b/mcs/tests/dtest-017.cs @@ -16,6 +16,10 @@ interface IA { } +struct S +{ +} + delegate dynamic D (dynamic d); class DynamicAssignments @@ -48,6 +52,13 @@ class DynamicAssignments I io = null; IA id = io; + IA ia_o = null; + IA ia_d = ia_o; + + S s_d = new S (); + S s_o = s_d; + S? s_o_n = s_d; + D del = delegate (object del_arg) { return (object) null; }; diff --git a/mcs/tests/dtest-028.cs b/mcs/tests/dtest-028.cs index 65b6b1a7ac3..94c33799bde 100644 --- a/mcs/tests/dtest-028.cs +++ b/mcs/tests/dtest-028.cs @@ -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 index 00000000000..979e71965c5 --- /dev/null +++ b/mcs/tests/dtest-030.cs @@ -0,0 +1,40 @@ +using System; + +class A +{ +} + +class B +{ + static void M1 (T t) where T : struct + { + } + + static void M2 (T t, U u) where U : IEquatable + { + } + + static void M3 (T t, A u) where U : IEquatable + { + } + + static void M4 (T t, IEquatable u) where T : IEquatable + { + } + + public static void Main () + { + dynamic d = 2; + M1 (d); + + M2 (d, 6); + M2 (4, d); + + M3 (d, new A ()); + + 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 index 00000000000..55bbbb7d2bc --- /dev/null +++ b/mcs/tests/dtest-collectioninit-01.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +public class Test +{ + class Wrap + { + List numbers = new List (); + + 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 index 00000000000..95553f94104 --- /dev/null +++ b/mcs/tests/dtest-etree-01.cs @@ -0,0 +1,25 @@ +using System; +using System.Linq.Expressions; + +public class C +{ + static void Conv1(Expression> l) + { + } + + static void Conv2(Expression> l) + { + } + + public static void Main () + { + Expression> e1 = () => (dynamic) 1; + Expression> 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 diff --git a/mcs/tests/ver-il-dmcs.xml b/mcs/tests/ver-il-dmcs.xml index bdb33286ff1..c2db5c4ce36 100644 --- a/mcs/tests/ver-il-dmcs.xml +++ b/mcs/tests/ver-il-dmcs.xml @@ -1778,7 +1778,7 @@ - 102 + 130 2 @@ -2032,7 +2032,7 @@ - 225 + 236 7 @@ -2054,6 +2054,11 @@ 0 + + + 1 + + @@ -2071,6 +2076,51 @@ + + + + 7 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + 576 + + + 7 + + + + + + + 475 + + + 7 + + + + + 7 + + + 18 + + + @@ -2118,6 +2168,22 @@ + + + + 1 + + + 1 + + + 382 + + + 7 + + + @@ -13004,6 +13070,16 @@ 21 + + + 7 + + + + + 7 + + @@ -17640,7 +17716,7 @@ 7 - 1 + 7 19 @@ -17667,7 +17743,7 @@ - 37 + 44 @@ -47570,7 +47646,7 @@ - 38 + 45