+ //
+ // Infers the type of a single LambdaExpression in the invocation call and
+ // stores the infered type in the inferred_types array.
+ //
+ // The index of the arguments that contain lambdas is passed in
+ //
+ // @lambdas. Merely to avoid rescanning the list.
+ //
+ // The method being called:
+ // @method_generic_args: The generic type arguments for the method being called
+ // @method_pd: The ParameterData for the method being called.
+ //
+ // The call site:
+ // @arguments: Arraylist of Argument()s. The arguments being passed.
+ //
+ // Returns:
+ // @inferred_types: the array that is populated with our results.
+ //
+ // true if the code was able to do one inference.
+ //
+ static bool LambdaInfer (EmitContext ec,
+ Type [] method_generic_args,
+ ParameterData method_pd,
+ ArrayList arguments,
+ Type[] inferred_types,
+ ArrayList lambdas)
+ {
+ int last_count = lambdas.Count;
+
+ for (int i = 0; i < last_count; i++){
+ int argn = (int) lambdas [i];
+
+ Argument a = (Argument) arguments [argn];
+
+ LambdaExpression le = a.Expr as LambdaExpression;
+
+ if (le == null)
+ throw new Exception (
+ String.Format ("Internal Compiler error: argument {0} should be a Lambda Expression",
+ argn));
+
+ //
+ // "The corresponding parameter’s type, in the
+ // following called P, is a delegate type with a
+ // return type that involves one or more method type
+ // parameters."
+ //
+ //
+ if (!TypeManager.IsDelegateType (method_pd.ParameterType (argn)))
+ goto useless_lambda;
+
+ Type p_type = method_pd.ParameterType (argn);
+ MethodGroupExpr method_group = Expression.MemberLookup (
+ ec.ContainerType, p_type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
+
+ if (method_group == null){
+ // This we report elsewhere as -200, but here we can ignore
+ goto useless_lambda;
+ }
+ MethodInfo p_delegate_method = method_group.Methods [0] as MethodInfo;
+ if (p_delegate_method == null){
+ // This should not happen.
+ goto useless_lambda;
+ }
+
+ Type p_return_type = p_delegate_method.ReturnType;
+ if (!p_return_type.IsGenericParameter)
+ goto useless_lambda;
+
+ //
+ // P and L have the same number of parameters, and
+ // each parameter in P has the same modifiers as the
+ // corresponding parameter in L, or no modifiers if
+ // L has an implicitly typed parameter list.
+ //
+ ParameterData p_delegate_parameters = TypeManager.GetParameterData (p_delegate_method);
+ int p_delegate_parameter_count = p_delegate_parameters.Count;
+ if (p_delegate_parameter_count != le.Parameters.Count)
+ goto useless_lambda;
+
+ if (le.HasExplicitParameters){
+ for (int j = 0; j < p_delegate_parameter_count; j++){
+ if (p_delegate_parameters.ParameterModifier (j) !=
+ le.Parameters.ParameterModifier (j))
+ goto useless_lambda;
+ }
+ } else {
+ for (int j = 0; j < p_delegate_parameter_count; j++)
+ if (le.Parameters.ParameterModifier (j) != Parameter.Modifier.NONE)
+ goto useless_lambda;
+ }
+
+ //
+ // TODO: P’s parameter types involve no method type
+ // parameters or involve only method type parameters
+ // for which a consistent set of inferences have
+ // already been made.
+ //
+ //Console.WriteLine ("Method: {0}", p_delegate_method);
+ //for (int j = 0; j < p_delegate_parameter_count; j++){
+ //Console.WriteLine ("PType [{2}, {0}] = {1}", j, p_delegate_parameters.ParameterType (j), argn);
+ //}
+
+ //
+ // At this point we know that P has method type parameters
+ // that involve only type parameters that have a consistent
+ // set of inferences made.
+ //
+ if (le.HasExplicitParameters){
+ //
+ // TODO: If L has an explicitly typed parameter
+ // list, when inferred types are substituted for
+ // method type parameters in P, each parameter in P
+ // has the same type as the corresponding parameter
+ // in L.
+ //
+ } else {
+ //
+ // TODO: If L has an implicitly typed parameter
+ // list, when inferred types are substituted for
+ // method type parameters in P and the resulting
+ // parameter types are given to the parameters of L,
+ // the body of L is a valid expression or statement
+ // block.
+
+ Type [] types = new Type [p_delegate_parameter_count];
+
+ //bool failure = false;
+ for (int j = 0; j < p_delegate_parameter_count; j++){
+ Type p_pt = p_delegate_parameters.ParameterType (j);
+
+ if (!p_pt.IsGenericParameter){
+ types [j] = p_pt;
+ continue;
+ }
+
+ //bool found = false;
+ for (int k = 0; k < method_generic_args.Length; k++){
+ if (method_generic_args [k] == p_pt){
+ types [j] = inferred_types [k];
+ break;
+ }
+ }
+ //
+ // If we could not infer just yet, continue
+ //
+ if (types [j] == null)
+ goto do_continue;
+ }
+
+ //
+ // If it results in a valid expression or statement block
+ //
+ Type lambda_inferred_type = le.TryBuild (ec, types);
+
+ if (lambda_inferred_type != null){
+ //
+ // Success, set the proper inferred_type value to the new type.
+ // return true
+ //
+ for (int k = 0; k < method_generic_args.Length; k++){
+ if (method_generic_args [k] == p_return_type){
+ inferred_types [k] = lambda_inferred_type;
+
+ lambdas.RemoveAt (i);
+ return true;
+ }
+ }
+ }
+ }
+
+ useless_lambda:
+ lambdas.RemoveAt (i);
+
+ do_continue:
+ ;
+ }
+
+#if false
+ Console.WriteLine ("Inferred types");
+ foreach (Type it in inferred_types){
+ Console.WriteLine (" IT: {0}", it);
+ if (it == null)
+ return false;
+ }
+#endif
+
+ // No inference was made in any of the elements.
+ return false;
+ }
+