void CheckApplicability(Candidate candidate)
		{
			// C# 4.0 spec: §7.5.3.1 Applicable function member
			
			// Test whether parameters were mapped the correct number of arguments:
			int[] argumentCountPerParameter = new int[candidate.ParameterTypes.Length];
			foreach (int parameterIndex in candidate.ArgumentToParameterMap) {
				if (parameterIndex >= 0)
					argumentCountPerParameter[parameterIndex]++;
			}
			for (int i = 0; i < argumentCountPerParameter.Length; i++) {
				if (candidate.IsExpandedForm && i == argumentCountPerParameter.Length - 1)
					continue; // any number of arguments is fine for the params-array
				if (argumentCountPerParameter[i] == 0) {
					if (candidate.Parameters[i].IsOptional)
						candidate.HasUnmappedOptionalParameters = true;
					else
						candidate.AddError(OverloadResolutionErrors.MissingArgumentForRequiredParameter);
				} else if (argumentCountPerParameter[i] > 1) {
					candidate.AddError(OverloadResolutionErrors.MultipleArgumentsForSingleParameter);
				}
			}
			
			candidate.ArgumentConversions = new Conversion[arguments.Length];
			// Test whether argument passing mode matches the parameter passing mode
			for (int i = 0; i < arguments.Length; i++) {
				int parameterIndex = candidate.ArgumentToParameterMap[i];
				if (parameterIndex < 0) continue;
				
				ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
				if (brrr != null) {
					if ((brrr.IsOut && !candidate.Parameters[parameterIndex].IsOut) || (brrr.IsRef && !candidate.Parameters[parameterIndex].IsRef))
						candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
				} else {
					if (candidate.Parameters[parameterIndex].IsOut || candidate.Parameters[parameterIndex].IsRef)
						candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
				}
				IType parameterType = candidate.ParameterTypes[parameterIndex];
				Conversion c = conversions.ImplicitConversion(arguments[i], parameterType);
				candidate.ArgumentConversions[i] = c;
				if (IsExtensionMethodInvocation && parameterIndex == 0) {
					// First parameter to extension method must be an identity, reference or boxing conversion
					if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
						candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
				} else {
					if (!c.IsValid)
						candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
				}
			}
		}
Esempio n. 2
0
        IList <IType> FindTypesInBounds(IList <IType> lowerBounds, IList <IType> upperBounds)
        {
            // If there's only a single type; return that single type.
            // If both inputs are empty, return the empty list.
            if (lowerBounds.Count == 0 && upperBounds.Count <= 1)
            {
                return(upperBounds);
            }
            if (upperBounds.Count == 0 && lowerBounds.Count <= 1)
            {
                return(lowerBounds);
            }
            if (nestingLevel > maxNestingLevel)
            {
                return(EmptyList <IType> .Instance);
            }

            // Finds a type X so that "LB <: X <: UB"
            Log.WriteCollection("FindTypesInBound, LowerBounds=", lowerBounds);
            Log.WriteCollection("FindTypesInBound, UpperBounds=", upperBounds);

            // First try the Fixing algorithm from the C# spec (§7.5.2.11)
            List <IType> candidateTypes = lowerBounds.Union(upperBounds)
                                          .Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c).IsValid))
                                          .Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b).IsValid))
                                          .ToList(); // evaluate the query only once

            candidateTypes = candidateTypes.Where(
                c => candidateTypes.All(o => conversions.ImplicitConversion(c, o).IsValid)
                ).ToList();
            // If the specified algorithm produces a single candidate, we return
            // that candidate.
            // We also return the whole candidate list if we're not using the improved
            // algorithm.
            if (candidateTypes.Count == 1 || !(algorithm == TypeInferenceAlgorithm.Improved || algorithm == TypeInferenceAlgorithm.ImprovedReturnAllResults))
            {
                return(candidateTypes);
            }
            candidateTypes.Clear();

            // Now try the improved algorithm
            Log.Indent();
            List <ITypeDefinition> candidateTypeDefinitions;

            if (lowerBounds.Count > 0)
            {
                // Find candidates by using the lower bounds:
                var hashSet = new HashSet <ITypeDefinition>(lowerBounds[0].GetAllBaseTypeDefinitions());
                for (int i = 1; i < lowerBounds.Count; i++)
                {
                    hashSet.IntersectWith(lowerBounds[i].GetAllBaseTypeDefinitions());
                }
                candidateTypeDefinitions = hashSet.ToList();
            }
            else
            {
                // Find candidates by looking at all classes in the project:
                candidateTypeDefinitions = compilation.GetAllTypeDefinitions().ToList();
            }

            // Now filter out candidates that violate the upper bounds:
            foreach (IType ub in upperBounds)
            {
                ITypeDefinition ubDef = ub.GetDefinition();
                if (ubDef != null)
                {
                    candidateTypeDefinitions.RemoveAll(c => !c.IsDerivedFrom(ubDef));
                }
            }

            foreach (ITypeDefinition candidateDef in candidateTypeDefinitions)
            {
                // determine the type parameters for the candidate:
                IType candidate;
                if (candidateDef.TypeParameterCount == 0)
                {
                    candidate = candidateDef;
                }
                else
                {
                    Log.WriteLine("Inferring arguments for candidate type definition: " + candidateDef);
                    bool    success;
                    IType[] result = InferTypeArgumentsFromBounds(
                        candidateDef.TypeParameters,
                        new ParameterizedType(candidateDef, candidateDef.TypeParameters),
                        lowerBounds, upperBounds,
                        out success);
                    if (success)
                    {
                        candidate = new ParameterizedType(candidateDef, result);
                    }
                    else
                    {
                        Log.WriteLine("Inference failed; ignoring candidate");
                        continue;
                    }
                }
                Log.WriteLine("Candidate type: " + candidate);

                if (lowerBounds.Count > 0)
                {
                    // if there were lower bounds, we aim for the most specific candidate:

                    // if this candidate isn't made redundant by an existing, more specific candidate:
                    if (!candidateTypes.Any(c => c.GetDefinition().IsDerivedFrom(candidateDef)))
                    {
                        // remove all existing candidates made redundant by this candidate:
                        candidateTypes.RemoveAll(c => candidateDef.IsDerivedFrom(c.GetDefinition()));
                        // add new candidate
                        candidateTypes.Add(candidate);
                    }
                }
                else
                {
                    // if there only were upper bounds, we aim for the least specific candidate:

                    // if this candidate isn't made redundant by an existing, less specific candidate:
                    if (!candidateTypes.Any(c => candidateDef.IsDerivedFrom(c.GetDefinition())))
                    {
                        // remove all existing candidates made redundant by this candidate:
                        candidateTypes.RemoveAll(c => c.GetDefinition().IsDerivedFrom(candidateDef));
                        // add new candidate
                        candidateTypes.Add(candidate);
                    }
                }
            }
            Log.Unindent();
            return(candidateTypes);
        }