Example #1
0
        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);
            }
        }
Example #2
0
 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()));
            }
Example #4
0
            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);
			}
Example #8
0
        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);
                    }
                }
            }
        }
Example #9
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

            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);
			}
Example #11
0
		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));
            }
Example #13
0
 public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
 {
     return(conversions.ImplicitConversion(inferredReturnType, returnType));
 }