bool Fix(TP tp) { Log.WriteLine(" Trying to fix " + tp); Debug.Assert(!tp.IsFixed); if (tp.ExactBound != null) { // the exact bound will always be the result tp.FixedTo = tp.ExactBound; // check validity if (tp.MultipleDifferentExactBounds) { return(false); } return(tp.LowerBounds.All(b => conversions.ImplicitConversion(b, tp.FixedTo).IsValid) && tp.UpperBounds.All(b => conversions.ImplicitConversion(tp.FixedTo, b).IsValid)); } Log.Indent(); var types = CreateNestedInstance().FindTypesInBounds(tp.LowerBounds.ToArray(), tp.UpperBounds.ToArray()); Log.Unindent(); if (algorithm == TypeInferenceAlgorithm.ImprovedReturnAllResults) { tp.FixedTo = IntersectionType.Create(types); Log.WriteLine(" T was fixed " + (types.Count >= 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); return(types.Count >= 1); } else { tp.FixedTo = GetFirstTypePreferNonInterfaces(types); Log.WriteLine(" T was fixed " + (types.Count == 1 ? "successfully" : "(with errors)") + " to " + tp.FixedTo); return(types.Count == 1); } }
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) { candidate.ArgumentConversions[i] = Conversion.None; 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 && parameterType.Kind != TypeKind.Unknown) { candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch); } } } }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { Assert.AreEqual(expectedParameterTypes, parameterTypes); return(conversions.ImplicitConversion(inferredReturnType, returnType)); }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { return(conversions.ImplicitConversion(inferredReturnType, returnType)); }
Conversion ImplicitConversion(Type from, Type to) { IType from2 = compilation.FindType(from); IType to2 = compilation.FindType(to); return(conversions.ImplicitConversion(from2, to2)); }
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); }