//
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)
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 {
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))
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)
}
}
- 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.
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 ());
}
}
return false;
}
- static bool HasDefaultConstructor (TypeSpec atype)
+ bool HasDefaultConstructor (TypeSpec atype)
{
var tp = atype as TypeParameterSpec;
if (tp != null) {
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);
</type>
<type name="DynamicAssignments">
<method name="Int32 Main()">
- <size>102</size>
+ <size>130</size>
</method>
<method name="System.Object <Main>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 <FailsToCompile>m__0()">
- <size>37</size>
+ <size>44</size>
</method>
</type>
<type name="SomeGenericClass`1+<FailsToCompile>c__AnonStorey0[SomeType]">
</type>
<type name="C">
<method name="Int32 <Test>m__0()">
- <size>38</size>
+ <size>45</size>
</method>
</type>
<type name="C+<Test>c__AnonStorey1">