Exemple #1
0
        public static CandidateInfo <T> TypeInference <T>(CandidateInfo <T> candidateInfo, NameResolver resolver) where T : MemberInfo
        {
            var method = candidateInfo.Member as MethodInfo;

            if (method == null || !method.IsGenericMethodDefinition)
            {
                throw new InvalidOperationException("Type inference can only be performed on a generic method definition.");
            }

            var inferer = new TypeInferer(candidateInfo.Parameters, method, resolver);

            if (!inferer.infer())
            {
                return(null);
            }

            var inferredMethod = method.MakeGenericMethod(inferer._inferred);
            // Return the list of parameter types with the generic type parameters substituted
            var parameterTypes = inferredMethod.GetParameters().Select(p => p.ParameterType).ToArray();

            // The inferer may have changed an implicit lambda to a LINQ expression, so return the new version of _arguments
            return(new CandidateInfo <T>((T)(MemberInfo)inferredMethod,
                                         candidateInfo.Parameters.Select((p, i) => new CandidateParameterInfo
            {
                ParameterType = parameterTypes[i],
                Mode = p.Mode,
                Argument = inferer._arguments[i],
                ArgumentIndex = p.ArgumentIndex,
                UninstantiatedParameterType = p.ParameterType
            }).ToArray(), inferredMethod.GetParameters().Length, isLiftedOperator: false, isExpandedForm: candidateInfo.IsExpandedForm));
        }
Exemple #2
0
        public static CandidateInfo <T> ResolveOverloads <T>(List <Tuple <T, ParameterInfo[]> > overloads, IEnumerable <ArgumentInfo> arguments, NameResolver resolver) where T : MemberInfo
        {
            var candidates = overloads.SelectMany(ov => ParserUtil.EvaluateArgumentList(ov.Item1, ov.Item2, arguments, resolver)).ToList();

            // Type inference
            for (int i = 0; i < candidates.Count; i++)
            {
                if (candidates[i].Member is MethodInfo && ((MethodInfo)(MemberInfo)candidates[i].Member).IsGenericMethodDefinition)
                {
                    candidates[i] = TypeInferer.TypeInference(candidates[i], resolver);
                }
            }

            // Remove nulls (entries where type inference failed) and entries that are not applicable (§7.5.3.1 Applicable function member)
            candidates = candidates.Where(c => c != null && c.Parameters.All(p => p.Mode == ArgumentMode.In
                ? Conversion.Implicit(p.Argument, p.ParameterType) != null
                : p.ParameterType == p.Argument.ExpressionType)).ToList();

            if (candidates.Count == 0)
            {
                return(null);
            }
            if (candidates.Count == 1)
            {
                return(candidates[0]);
            }

            // We have more than one candidate, so need to find the “best” one
            bool[] cannot = new bool[candidates.Count];
            for (int i = 0; i < cannot.Length; i++)
            {
                for (int j = i + 1; j < cannot.Length; j++)
                {
                    int compare = candidates[i].Better(candidates[j]);
                    if (compare != 1) // j is not better
                    {
                        cannot[j] = true;
                    }
                    if (compare != -1) // i is not better
                    {
                        cannot[i] = true;
                    }
                }
            }

            CandidateInfo <T> candidate = null;

            for (int i = 0; i < cannot.Length; i++)
            {
                if (!cannot[i])
                {
                    if (candidate == null)
                    {
                        candidate = candidates[i];
                    }
                    else
                    {
                        // There is more than one applicable candidate — method call is ambiguous
                        return(null);
                    }
                }
            }

            // Either candidate == null, in which case no candidate was better than all others, or this is the successful candidate
            return(candidate);
        }