Ejemplo n.º 1
0
        /// <summary>Checks whether the specified method is applicable given the argument expressions.</summary>
        /// <param name="signature">The candidate function signature to check.</param>
        /// <param name="argumentTypes">The argument types to match.</param>
        /// <returns>An applicable function signature if all argument types can be promoted; 'null' otherwise.</returns>
        private static bool IsApplicable(FunctionSignature signature, ResourceType[] argumentTypes)
        {
            Debug.Assert(signature != null, "signature != null");
            Debug.Assert(argumentTypes != null, "argumentTypes != null");

            if (signature.ArgumentTypes.Length != argumentTypes.Length)
            {
                return false;
            }

            for (int i = 0; i < argumentTypes.Length; ++i)
            {
                if (!CanPromoteTo(argumentTypes[i], signature.ArgumentTypes[i]))
                {
                    return false;
                }
            }

            return true;
        }
Ejemplo n.º 2
0
        /// <summary>Finds the exact fitting function for the specified arguments.</summary>
        /// <param name="functions">Functions to consider.</param>
        /// <param name="argumentTypes">Types of the arguments for the function.</param>
        /// <returns>The exact fitting function; null if no exact match was found.</returns>
        internal static FunctionSignature FindExactFunctionSignature(FunctionSignature[] functions, ResourceType[] argumentTypes)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(functions != null, "functions != null");
            Debug.Assert(argumentTypes != null, "argumentTypes != null");

            for (int functionIndex = 0; functionIndex < functions.Length; functionIndex++)
            {
                FunctionSignature functionSignature = functions[functionIndex];
                bool matchFound = true;

                if (functionSignature.ArgumentTypes.Length != argumentTypes.Length)
                {
                    continue;
                }

                for (int argumentIndex = 0; argumentIndex < argumentTypes.Length; argumentIndex++)
                {
                    ResourceType functionSignatureArgumentType = functionSignature.ArgumentTypes[argumentIndex];
                    ResourceType argumentType = argumentTypes[argumentIndex];
                    Debug.Assert(functionSignatureArgumentType.ResourceTypeKind == ResourceTypeKind.Primitive, "Only primitive arguments are supported for functions.");

                    if (argumentType.ResourceTypeKind != ResourceTypeKind.Primitive)
                    {
                        matchFound = false;
                        break;
                    }

                    // Since we're working on primitive types only we can compare just references since primitive resource types are atomized.
                    if (!object.ReferenceEquals(argumentType, functionSignatureArgumentType))
                    {
                        matchFound = false;
                        break;
                    }
                }

                if (matchFound)
                {
                    return functionSignature;
                }
            }

            return null;
        }
Ejemplo n.º 3
0
        /// <summary>Finds the best methods for the specified arguments given a candidate method enumeration.</summary>
        /// <param name="signatures">The candidate function signatures.</param>
        /// <param name="argumentTypes">The argument types to match.</param>
        /// <returns>The number of "best match" methods.</returns>
        private static int FindBestSignature(FunctionSignature[] signatures, ResourceType[] argumentTypes)
        {
            Debug.Assert(signatures != null, "signatures != null");
            Debug.Assert(argumentTypes != null, "argumentTypes != null");
            Debug.Assert(argumentTypes.All(t => t == null || t.ResourceTypeKind == ResourceTypeKind.Primitive), "All argument types must be primitive or null.");
            Debug.Assert(signatures.All(s => s.ArgumentTypes != null && s.ArgumentTypes.All(t => t.ResourceTypeKind == ResourceTypeKind.Primitive)), "All signatures must have only primitive argument types.");

            List<FunctionSignature> applicableSignatures = signatures.Where(signature => IsApplicable(signature, argumentTypes)).ToList();
            if (applicableSignatures.Count > 1)
            {
                applicableSignatures = FindBestApplicableSignatures(applicableSignatures, argumentTypes);
            }

            int result = applicableSignatures.Count;
            if (result == 1)
            {
                // TODO: deal with the situation that we started off with all non-open types
                //       and end up with all open types; see RequestQueryParser.FindBestMethod. 
                //       Ignored for now since we don't support open types yet.
                FunctionSignature signature = applicableSignatures[0];
                for (int i = 0; i < argumentTypes.Length; i++)
                {
                    argumentTypes[i] = signature.ArgumentTypes[i];
                }

                result = 1;
            }
            else if (result > 1)
            {
                // We may have the case for operators (which C# doesn't) in which we have a nullable operand
                // and a non-nullable operand. We choose to convert the one non-null operand to nullable in that
                // case (the binary expression will lift to null).
                if (argumentTypes.Length == 2 && result == 2 &&
                    TypeUtils.GetNonNullableType(applicableSignatures[0].ArgumentTypes[0].InstanceType) ==
                    TypeUtils.GetNonNullableType(applicableSignatures[1].ArgumentTypes[0].InstanceType))
                {
                    FunctionSignature nullableMethod =
                        TypeUtils.TypeAllowsNull(applicableSignatures[0].ArgumentTypes[0].InstanceType) ?
                        applicableSignatures[0] :
                        applicableSignatures[1];
                    argumentTypes[0] = nullableMethod.ArgumentTypes[0];
                    argumentTypes[1] = nullableMethod.ArgumentTypes[1];

                    // TODO: why is this necessary? We keep it here for now since the product has it but assert
                    //       that nothing new was found.
                    int signatureCount = FindBestSignature(signatures, argumentTypes);
                    Debug.Assert(signatureCount == 1, "signatureCount == 1");
                    Debug.Assert(argumentTypes[0] == nullableMethod.ArgumentTypes[0], "argumentTypes[0] == nullableMethod.ArgumentTypes[0]");
                    Debug.Assert(argumentTypes[1] == nullableMethod.ArgumentTypes[1], "argumentTypes[1] == nullableMethod.ArgumentTypes[1]");
                    return signatureCount;
                }
            }

            return result;
        }
Ejemplo n.º 4
0
        /// <summary>Finds the best fitting function for the specified arguments.</summary>
        /// <param name="functions">Functions to consider.</param>
        /// <param name="argumentTypes">Types of the arguments for the function.</param>
        /// <returns>The best fitting function; null if none found or ambiguous.</returns>
        internal static FunctionSignature FindBestFunctionSignature(FunctionSignature[] functions, ResourceType[] argumentTypes)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(functions != null, "functions != null");
            Debug.Assert(argumentTypes != null, "argumentTypes != null");
            List<FunctionSignature> applicableFunctions = new List<FunctionSignature>(functions.Length);

            // Build a list of applicable functions (and cache their promoted arguments).
            foreach (FunctionSignature candidate in functions)
            {
                if (candidate.ArgumentTypes.Length != argumentTypes.Length)
                {
                    continue;
                }

                bool argumentsMatch = true;
                for (int i = 0; i < candidate.ArgumentTypes.Length; i++)
                {
                    if (!CanPromoteTo(argumentTypes[i], candidate.ArgumentTypes[i]))
                    {
                        argumentsMatch = false;
                        break;
                    }
                }

                if (argumentsMatch)
                {
                    applicableFunctions.Add(candidate);
                }
            }

            // Return the best applicable function.
            if (applicableFunctions.Count == 0)
            {
                // No matching function.
                return null;
            }
            else if (applicableFunctions.Count == 1)
            {
                return applicableFunctions[0];
            }
            else
            {
                // Find a single function which is better than all others.
                int bestFunctionIndex = -1;
                for (int i = 0; i < applicableFunctions.Count; i++)
                {
                    bool betterThanAllOthers = true;
                    for (int j = 0; j < applicableFunctions.Count; j++)
                    {
                        if (i != j && MatchesArgumentTypesBetterThan(argumentTypes, applicableFunctions[j].ArgumentTypes, applicableFunctions[i].ArgumentTypes))
                        {
                            betterThanAllOthers = false;
                            break;
                        }
                    }

                    if (betterThanAllOthers)
                    {
                        if (bestFunctionIndex == -1)
                        {
                            bestFunctionIndex = i;
                        }
                        else
                        {
                            // Ambiguous.
                            return null;
                        }
                    }
                }

                if (bestFunctionIndex == -1)
                {
                    return null;
                }

                return applicableFunctions[bestFunctionIndex];
            }
        }