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); } }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { // Anonymous method expressions without parameter lists are applicable to any parameter list. if (HasParameterList) { if (this.Parameters.Count != parameterTypes.Length) { return(Conversion.None); } for (int i = 0; i < parameterTypes.Length; ++i) { if (!conversions.IdentityConversion(parameterTypes[i], this.Parameters[i].Type)) { if (IsImplicitlyTyped) { // it's possible that different parameter types also lead to a valid conversion return(LambdaConversion.Instance); } else { return(Conversion.None); } } } } if (conversions.IdentityConversion(this.ReturnType, returnType) || conversions.ImplicitConversion(this.InferredReturnType, returnType).IsValid) { return(LambdaConversion.Instance); } else { return(Conversion.None); } }
public override void VisitForeachStatement(ForeachStatement foreachStatement) { base.VisitForeachStatement(foreachStatement); var rr = ctx.Resolve(foreachStatement) as ForEachResolveResult; if (rr == null) { return; } if (rr.ElementType.Kind == TypeKind.Unknown) { return; } if (ReflectionHelper.GetTypeCode(rr.ElementType) == TypeCode.Object) { return; } if (conversions == null) { conversions = CSharpConversions.Get(ctx.Compilation); } Conversion c = conversions.ImplicitConversion(rr.ElementType, rr.ElementVariable.Type); if (c.IsValid) { return; } var csResolver = ctx.GetResolverStateBefore(foreachStatement); var builder = new TypeSystemAstBuilder(csResolver); AstType elementType = builder.ConvertType(rr.ElementType); AstType variableType = foreachStatement.VariableType; string text = ctx.TranslateString("Collection element type '{0}' is not implicitly convertible to '{1}'"); AddIssue(variableType, string.Format(text, elementType.GetText(), variableType.GetText())); }
void VisitTypeCastExpression(AssignmentExpression expression, IType exprType, IType castToType) { if (exprType.Kind == TypeKind.Unknown || castToType.Kind == TypeKind.Unknown) { return; } var foundConversion = conversion.ExplicitConversion(exprType, castToType); if (foundConversion == Conversion.None) { return; } if (!foundConversion.IsExplicit) { return; } var implicitConversion = conversion.ImplicitConversion(exprType, castToType); if (implicitConversion != Conversion.None) { return; } AddIssue(expression, string.Format(ctx.TranslateString("Cast to '{0}'"), castToType.Name), script => { var right = expression.Right.Clone(); var castRight = right.CastTo(CreateShortType(expression, castToType)); script.Replace(expression.Right, castRight); }); }
public override void VisitIsExpression(IsExpression isExpression) { base.VisitIsExpression(isExpression); var type = ctx.Resolve(isExpression.Expression).Type; var providedType = ctx.ResolveType(isExpression.Type); var foundConversion = conversions.ImplicitConversion(type, providedType); if (!IsValidReferenceOrBoxingConversion(type, providedType)) { return; } var action = new CodeAction(ctx.TranslateString("Compare with 'null'"), scrpit => scrpit.Replace(isExpression, new BinaryOperatorExpression( isExpression.Expression.Clone(), BinaryOperatorType.InEquality, new PrimitiveExpression(null)))); AddIssue(isExpression, ctx.TranslateString("Given expression is always of the provided type. " + "Consider comparing with 'null' instead"), new [] { action }); }
bool IsSignatureMatch(IType indexerElementType, IList <IType> indexerParameterTypes) { indexerElementType.GetAllBaseTypes(); if (indexerParameterTypes.Count != argumentTypes.Count) { return(false); } var returnConversion = conversions.ImplicitConversion(indexerElementType, returnType); if (!returnConversion.IsValid) { return(false); } for (int i = 0; i < argumentTypes.Count; i++) { var conversion = conversions.ImplicitConversion(indexerParameterTypes[i], argumentTypes[i]); if (!conversion.IsValid) { return(false); } } return(true); }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { Assert.AreEqual(expectedParameterTypes, parameterTypes); return conversions.ImplicitConversion(inferredReturnType, returnType); }
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 (this.AllowOptionalParameters && 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 && !c.IsUserDefined && !c.IsMethodGroupConversion) && parameterType.Kind != TypeKind.Unknown) { candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch); } } } }
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 Log.WriteCollection("FindTypesInBound, Candidates=", candidateTypes); // According to the C# specification, we need to pick the most specific // of the candidate types. (the type which has conversions to all others) // However, csc actually seems to choose the least specific. candidateTypes = candidateTypes.Where( c => candidateTypes.All(o => conversions.ImplicitConversion(o, c).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 (upperBounds.Count == 0) { // if there were only 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 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); }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { return conversions.ImplicitConversion(inferredReturnType, returnType); }
static bool IsEligibleExtensionMethod(ICompilation compilation, CSharpConversions conversions, IType targetType, IMethod method, bool useTypeInference, out IType[] outInferredTypes) { outInferredTypes = null; if (targetType == null) return true; if (method.Parameters.Count == 0) return false; IType thisParameterType = method.Parameters[0].Type; if (useTypeInference && method.TypeParameters.Count > 0) { // We need to infer type arguments from targetType: TypeInference ti = new TypeInference(compilation, conversions); ResolveResult[] arguments = { new ResolveResult(targetType) }; IType[] parameterTypes = { method.Parameters[0].Type }; bool success; var inferredTypes = ti.InferTypeArguments(method.TypeParameters, arguments, parameterTypes, out success); var substitution = new TypeParameterSubstitution(null, inferredTypes); // Validate that the types that could be inferred (aren't unknown) satisfy the constraints: bool hasInferredTypes = false; for (int i = 0; i < inferredTypes.Length; i++) { if (inferredTypes[i].Kind != TypeKind.Unknown && inferredTypes[i].Kind != TypeKind.UnboundTypeArgument) { hasInferredTypes = true; if (!OverloadResolution.ValidateConstraints(method.TypeParameters[i], inferredTypes[i], substitution, conversions)) return false; } else { inferredTypes[i] = method.TypeParameters[i]; // do not substitute types that could not be inferred } } if (hasInferredTypes) outInferredTypes = inferredTypes; thisParameterType = thisParameterType.AcceptVisitor(substitution); } Conversion c = conversions.ImplicitConversion(targetType, thisParameterType); return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion); }
bool IsValidReferenceOrBoxingConversion(IType fromType, IType toType) { Conversion c = conversions.ImplicitConversion(fromType, toType); return(c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion)); }
public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions) { return(conversions.ImplicitConversion(inferredReturnType, returnType)); }