Exemplo n.º 1
0
        public void LessArgumentsPassedToParamsIsBetter()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int), typeof(int), typeof(int)));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int), typeof(int[]))));
            Assert.IsFalse(r.IsAmbiguous);
            Assert.AreEqual(2, r.BestCandidate.Parameters.Count);
        }
Exemplo n.º 2
0
        public void PreferIntOverUInt()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(ushort)));
            var c1 = MakeMethod(typeof(int));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(c1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(uint))));
            Assert.IsFalse(r.IsAmbiguous);
            Assert.AreSame(c1, r.BestCandidate);
        }
Exemplo n.º 3
0
        public void PreferUIntOverLong_FromIntLiteral()
        {
            ResolveResult[]    args = { new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1) };
            OverloadResolution r    = new OverloadResolution(compilation, args);
            var c1 = MakeMethod(typeof(uint));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(c1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(long))));
            Assert.IsFalse(r.IsAmbiguous);
            Assert.AreSame(c1, r.BestCandidate);
        }
Exemplo n.º 4
0
        public void PreferMethodWithoutOptionalParameters()
        {
            var m1 = MakeMethod();
            var m2 = MakeMethod(1);

            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList());

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
            Assert.IsFalse(r.IsAmbiguous);
            Assert.AreSame(m1, r.BestCandidate);
        }
Exemplo n.º 5
0
        public void NullableIntAndNullableUIntIsAmbiguous()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(ushort?)));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(int?))));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(uint?))));
            Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors);

            // then adding a matching overload solves the ambiguity:
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(ushort?))));
            Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors);
            Assert.IsNull(r.BestCandidateAmbiguousWith);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Resolves an object creation.
        /// </summary>
        /// <param name="type">Type of the object to create.</param>
        /// <param name="arguments">
        /// Arguments passed to the constructor.
        /// The resolver may mutate this array to wrap elements in <see cref="CastExpression"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <param name="allowProtectedAccess">
        /// Whether to allow calling protected constructors.
        /// This should be false except when resolving constructor initializers.
        /// </param>
        /// <param name="initializerStatements">
        /// Statements for Objects/Collections initializer.
        /// <see cref="InvocationExpression.InitializerStatements"/>
        /// </param>
        /// <returns>InvocationResolveResult or ErrorResolveResult</returns>
        public static Expression ResolveObjectCreation(ResolveContext rc, Location l, IType type, Expression[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList <Expression> initializerStatements = null)
        {
            if (type.Kind == TypeKind.Delegate)
            {
                if (arguments == null || arguments.Length != 1)
                {
                    rc.Report.Error(0, l, "Method name expected");
                    return(null);
                }
                Expression input  = arguments[0];
                IMethod    invoke = input.Type.GetDelegateInvokeMethod();
                if (invoke != null)
                {
                    input = new MethodGroupExpression(
                        input, invoke.Name,
                        methods: new[] { new MethodListWithDeclaringType(input.Type)
                                         {
                                             invoke
                                         } },
                        typeArguments: EmptyList <IType> .Instance
                        );
                }
                return(rc.Convert(input, type));
            }
            OverloadResolution or            = rc.CreateOverloadResolution(arguments, argumentNames);
            MemberLookup       lookup        = rc.CreateMemberLookup();
            List <IMethod>     allApplicable = null;

            foreach (IMethod ctor in type.GetConstructors())
            {
                if (lookup.IsAccessible(ctor, allowProtectedAccess))
                {
                    or.AddCandidate(ctor);
                }
                else
                {
                    or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible);
                }
            }
            if (or.BestCandidate != null)
            {
                return(or.CreateInvocation(null, initializerStatements));
            }
            else
            {
                rc.Report.Error(0, l,
                                "The type `{0}' does not contain a constructor that takes `{1}' arguments",
                                type.ToString(), arguments != null ? arguments.Length.ToString() : "0");
                return(ErrorResult);
            }
        }
Exemplo n.º 7
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            var     container  = compilation.FindType(typeof(SkeetEvilOverloadResolutionTestCase)).GetDefinition();
            IMethod resolvedM1 = container.GetMethods(m => m.Name == "Foo").First();
            IMethod resolvedM2 = container.GetMethods(m => m.Name == "Foo").Skip(1).First();
            IMethod resolvedM3 = container.GetMethods(m => m.Name == "Foo").Skip(2).First();

            // Call: Foo<int>();
            OverloadResolution o;

            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int)) });
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
            Assert.AreSame(resolvedM1, o.BestCandidate);

            // Call: Foo<string>();
            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(string)) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM2));
            Assert.AreSame(resolvedM2, o.BestCandidate);

            // Call: Foo<int?>();
            o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int?)) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM3));
            Assert.AreSame(resolvedM3, o.BestCandidate);
        }
Exemplo n.º 8
0
        public OverloadResolution PerformOverloadResolution(ICompilation compilation, Expression[] arguments, string[] argumentNames = null,
                                                            bool allowExtensionMethods = true,
                                                            bool allowExpandingParams = true,
                                                            bool allowOptionalParameters = true,
                                                            bool checkForOverflow = false, VSharpConversions conversions = null)
        {

            var typeArgumentArray = this.TypeArguments.ToArray();
            OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
            or.AllowExpandingParams = allowExpandingParams;
            or.AllowOptionalParameters = allowOptionalParameters;
            or.CheckForOverflow = checkForOverflow;

            or.AddMethodLists(methodLists);

            if (allowExtensionMethods && !or.FoundApplicableCandidate)
            {
                // No applicable match found, so let's try extension methods.

                var extensionMethods = this.GetExtensionMethods();

                if (extensionMethods.Any())
                {

                    Expression[] extArguments = new Expression[arguments.Length + 1];
                    extArguments[0] = new AST.Expression(this.TargetType);
                    arguments.CopyTo(extArguments, 1);
                    string[] extArgumentNames = null;
                    if (argumentNames != null)
                    {
                        extArgumentNames = new string[argumentNames.Length + 1];
                        argumentNames.CopyTo(extArgumentNames, 1);
                    }
                    var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
                    extOr.AllowExpandingParams = allowExpandingParams;
                    extOr.AllowOptionalParameters = allowOptionalParameters;
                    extOr.IsExtensionMethodInvocation = true;
                    extOr.CheckForOverflow = checkForOverflow;

                    foreach (var g in extensionMethods)
                    {
                        foreach (var method in g)
                            extOr.AddCandidate(method);

                        if (extOr.FoundApplicableCandidate)
                            break;
                    }
                    // For the lack of a better comparison function (the one within OverloadResolution
                    // cannot be used as it depends on the argument set):
                    if (extOr.FoundApplicableCandidate || or.BestCandidate == null)
                    {
                        // Consider an extension method result better than the normal result only
                        // if it's applicable; or if there is no normal result.
                        or = extOr;
                    }
                }
            }

            return or;
        }
Exemplo n.º 9
0
        public void CallInvalidParamsDeclaration()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[, ])));

            Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int))));
            Assert.IsFalse(r.BestCandidateIsExpandedForm);
        }
Exemplo n.º 10
0
        public void ParamsMethodMatchesInUnexpandedForm()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[])));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
            Assert.IsFalse(r.BestCandidateIsExpandedForm);
        }
Exemplo n.º 11
0
        OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetDetails, IMethod method,
                                                   TranslatedExpression target, IType[] typeArguments, IList <TranslatedExpression> arguments)
        {
            var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly);
            var or     = new OverloadResolution(resolver.Compilation, arguments.SelectArray(a => a.ResolveResult), typeArguments: typeArguments);

            if (expectedTargetDetails.CallOpCode == OpCode.NewObj)
            {
                foreach (IMethod ctor in method.DeclaringType.GetConstructors())
                {
                    if (lookup.IsAccessible(ctor, allowProtectedAccess: resolver.CurrentTypeDefinition == method.DeclaringTypeDefinition))
                    {
                        or.AddCandidate(ctor);
                    }
                }
            }
            else
            {
                var result = lookup.Lookup(target.ResolveResult, method.Name, EmptyList <IType> .Instance, true) as MethodGroupResolveResult;
                if (result == null)
                {
                    return(OverloadResolutionErrors.AmbiguousMatch);
                }
                or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray());
            }
            if (or.BestCandidateErrors != OverloadResolutionErrors.None)
            {
                return(or.BestCandidateErrors);
            }
            if (!IsAppropriateCallTarget(expectedTargetDetails, method, or.GetBestCandidateWithSubstitutedTypeArguments()))
            {
                return(OverloadResolutionErrors.AmbiguousMatch);
            }
            return(OverloadResolutionErrors.None);
        }
Exemplo n.º 12
0
        public void Lambda_DelegateAndExpressionTreeOverloadsAreAmbiguous()
        {
            var m1 = MakeMethod(typeof(Func <int>));
            var m2 = MakeMethod(typeof(Expression <Func <int> >));

            // M(() => default(int));
            ResolveResult[] args =
            {
                new MockLambda(compilation.FindType(KnownTypeCode.Int32))
            };

            OverloadResolution r = new OverloadResolution(compilation, args);

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
            Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors);
        }
Exemplo n.º 13
0
        public void BetterConversionByLambdaReturnValue_ExpressionTree()
        {
            var m1 = MakeMethod(typeof(Func <long>));
            var m2 = MakeMethod(typeof(Expression <Func <int> >));

            // M(() => default(byte));
            ResolveResult[] args =
            {
                new MockLambda(compilation.FindType(KnownTypeCode.Byte))
            };

            OverloadResolution r = new OverloadResolution(compilation, args);

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
            Assert.AreSame(m2, r.BestCandidate);
            Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors);
        }
            bool BaseTypeHasUsableParameterlessConstructor()
            {
                var memberLookup      = new MemberLookup(currentType.GetDefinition(), ctx.Compilation.MainAssembly);
                OverloadResolution or = new OverloadResolution(ctx.Compilation, new ResolveResult[0]);

                foreach (var ctor in baseType.GetConstructors())
                {
                    if (memberLookup.IsAccessible(ctor, allowProtectedAccess: true))
                    {
                        if (or.AddCandidate(ctor) == OverloadResolutionErrors.None)
                        {
                            return(true);
                        }
                    }
                }
                return(false);
            }
Exemplo n.º 15
0
        protected virtual void WritePositionalList(IList <ResolveResult> expressions, IAttribute attr)
        {
            bool needComma   = false;
            int  count       = Emitter.Writers.Count;
            bool expanded    = false;
            int  paramsIndex = -1;

            if (attr.Constructor.Parameters.Any(p => p.IsParams))
            {
                paramsIndex = attr.Constructor.Parameters.IndexOf(attr.Constructor.Parameters.FirstOrDefault(p => p.IsParams));
                var or = new OverloadResolution(Emitter.Resolver.Compilation, expressions.ToArray());
                or.AddCandidate(attr.Constructor);
                expanded = or.BestCandidateIsExpandedForm;
            }

            for (int i = 0; i < expressions.Count; i++)
            {
                var expr = expressions[i];

                if (needComma)
                {
                    WriteComma();
                }

                needComma = true;

                if (expanded && paramsIndex == i)
                {
                    WriteOpenBracket();
                }

                WriteResolveResult(expr, this);

                if (Emitter.Writers.Count != count)
                {
                    PopWriter();
                    count = Emitter.Writers.Count;
                }
            }

            if (expanded)
            {
                WriteCloseBracket();
            }
        }
Exemplo n.º 16
0
        public void BetterFunctionMemberIsNotTransitive()
        {
            var container = compilation.FindType(typeof(BetterFunctionMemberIsNotTransitiveTestCase)).GetDefinition();

            var args = new ResolveResult[] {
                new MockLambda(compilation.FindType(KnownTypeCode.String))
                {
                    parameters = { new DefaultParameter(SpecialType.UnknownType, "arg") }
                }
            };

            OverloadResolution r = new OverloadResolution(compilation, args);

            foreach (var method in container.GetMethods(m => m.Name == "Method"))
            {
                Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(method));
            }

            Assert.AreEqual(container.GetMethods(m => m.Name == "Method").Last(), r.BestCandidate);
        }
Exemplo n.º 17
0
        public Expression ResolveBinaryOperator(ResolveContext rc, BinaryOperatorType op, Expression lhs, Expression rhs)
        {
            // V# 4.0 spec: §7.3.4 Binary operator overload resolution
            string overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(op);

            if (overloadableOperatorName == null)
            {
                // Handle logical and/or exactly as bitwise and/or:
                // - If the user overloads a bitwise operator, that implicitly creates the corresponding logical operator.
                // - If both inputs are compile-time constants, it doesn't matter that we don't short-circuit.
                // - If inputs aren't compile-time constants, we don't evaluate anything, so again it doesn't matter that we don't short-circuit
                if (op == BinaryOperatorType.LogicalAnd)
                {
                    overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(BinaryOperatorType.BitwiseAnd);
                }
                else if (op == BinaryOperatorType.LogicalOr)
                {
                    overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(BinaryOperatorType.BitwiseOr);
                }
                else if (op == BinaryOperatorType.NullCoalescing)
                {
                    // null coalescing operator is not overloadable and needs to be handled separately
                    return(ResolveNullCoalescingOperator(rc, lhs, rhs));
                }
                else
                {
                    return(ErrorExpression.UnknownError);
                }
            }

            // If the type is nullable, get the underlying type:
            bool  isNullable = NullableType.IsNullable(lhs.Type) || NullableType.IsNullable(rhs.Type);
            IType lhsType    = NullableType.GetUnderlyingType(lhs.Type);
            IType rhsType    = NullableType.GetUnderlyingType(rhs.Type);

            // the operator is overloadable:
            OverloadResolution             userDefinedOperatorOR  = rc.CreateOverloadResolution(new[] { lhs, rhs });
            HashSet <IParameterizedMember> userOperatorCandidates = new HashSet <IParameterizedMember>();

            userOperatorCandidates.UnionWith(rc.GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName));
            userOperatorCandidates.UnionWith(rc.GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName));
            foreach (var candidate in userOperatorCandidates)
            {
                userDefinedOperatorOR.AddCandidate(candidate);
            }
            if (userDefinedOperatorOR.FoundApplicableCandidate)
            {
                return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR));
            }

            if (lhsType.Kind == TypeKind.Null && rhsType.IsReferenceType == false ||
                lhsType.IsReferenceType == false && rhsType.Kind == TypeKind.Null)
            {
                isNullable = true;
            }
            if (op == BinaryOperatorType.LeftShift || op == BinaryOperatorType.RightShift)
            {
                // special case: the shift operators allow "var x = null << null", producing int?.
                if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
                {
                    isNullable = true;
                }
                // for shift operators, do unary promotion independently on both arguments
                lhs = UnaryNumericPromotion(rc, UnaryOperatorType.UnaryPlus, ref lhsType, isNullable, lhs);
                rhs = UnaryNumericPromotion(rc, UnaryOperatorType.UnaryPlus, ref rhsType, isNullable, rhs);
            }
            else
            {
                bool allowNullableConstants = op == BinaryOperatorType.Equality || op == BinaryOperatorType.Inequality;
                if (!BinaryNumericPromotion(rc, isNullable, ref lhs, ref rhs, allowNullableConstants))
                {
                    return(new ErrorExpression(lhs.Type));
                }
            }
            // re-read underlying types after numeric promotion
            lhsType = NullableType.GetUnderlyingType(lhs.Type);
            rhsType = NullableType.GetUnderlyingType(rhs.Type);

            IEnumerable <VSharpOperators.OperatorMethod> methodGroup;
            VSharpOperators operators = VSharpOperators.Get(rc.compilation);

            switch (op)
            {
            case BinaryOperatorType.Multiply:
                methodGroup = operators.MultiplicationOperators;
                break;

            case BinaryOperatorType.Division:
                methodGroup = operators.DivisionOperators;
                break;

            case BinaryOperatorType.Modulus:
                methodGroup = operators.RemainderOperators;
                break;

            case BinaryOperatorType.Addition:
                methodGroup = operators.AdditionOperators;
                {
                    if (lhsType.Kind == TypeKind.Enum)
                    {
                        // E operator +(E x, U y);
                        IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(lhsType), isNullable);
                        if (rc.TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs))
                        {
                            return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs));
                        }
                    }
                    if (rhsType.Kind == TypeKind.Enum)
                    {
                        // E operator +(U x, E y);
                        IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(rhsType), isNullable);
                        if (rc.TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs))
                        {
                            return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs));
                        }
                    }

                    if (lhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref rhs, lhsType))
                    {
                        return(SetOperationInformations(rc, lhsType, lhs, op, rhs));
                    }
                    else if (rhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref lhs, rhsType))
                    {
                        return(SetOperationInformations(rc, rhsType, lhs, op, rhs));
                    }

                    if (lhsType is PointerTypeSpec)
                    {
                        methodGroup = new[] {
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int32),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt32),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int64),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt64)
                        };
                    }
                    else if (rhsType is PointerTypeSpec)
                    {
                        methodGroup = new[] {
                            PointerArithmeticOperator(rc, rhsType, KnownTypeCode.Int32, rhsType),
                            PointerArithmeticOperator(rc, rhsType, KnownTypeCode.UInt32, rhsType),
                            PointerArithmeticOperator(rc, rhsType, KnownTypeCode.Int64, rhsType),
                            PointerArithmeticOperator(rc, rhsType, KnownTypeCode.UInt64, rhsType)
                        };
                    }
                    if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
                    {
                        return(new ErrorExpression(SpecialTypeSpec.NullType));
                    }
                }
                break;

            case BinaryOperatorType.Subtraction:
                methodGroup = operators.SubtractionOperators;
                {
                    if (lhsType.Kind == TypeKind.Enum)
                    {
                        // U operator –(E x, E y);
                        if (rc.TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs, allowConversionFromConstantZero: false))
                        {
                            return(HandleEnumSubtraction(rc, isNullable, lhsType, lhs, rhs));
                        }

                        // E operator –(E x, U y);
                        IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(lhsType), isNullable);
                        if (rc.TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs))
                        {
                            return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs));
                        }
                    }
                    if (rhsType.Kind == TypeKind.Enum)
                    {
                        // U operator –(E x, E y);
                        if (rc.TryConvertEnum(ref lhs, rhs.Type, ref isNullable, ref rhs, allowConversionFromConstantZero: false))
                        {
                            return(HandleEnumSubtraction(rc, isNullable, rhsType, lhs, rhs));
                        }

                        // E operator -(U x, E y);
                        IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(rhsType), isNullable);
                        if (rc.TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs))
                        {
                            return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs));
                        }
                    }

                    if (lhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref rhs, lhsType))
                    {
                        return(SetOperationInformations(rc, lhsType, lhs, op, rhs));
                    }
                    else if (rhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref lhs, rhsType))
                    {
                        return(SetOperationInformations(rc, rhsType, lhs, op, rhs));
                    }

                    if (lhsType is PointerTypeSpec)
                    {
                        if (rhsType is PointerTypeSpec)
                        {
                            IType int64 = rc.compilation.FindType(KnownTypeCode.Int64);
                            if (lhsType.Equals(rhsType))
                            {
                                return(SetOperationInformations(rc, int64, lhs, op, rhs));
                            }
                            else
                            {
                                return(new ErrorExpression(int64));
                            }
                        }
                        methodGroup = new[] {
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int32),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt32),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int64),
                            PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt64)
                        };
                    }

                    if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
                    {
                        return(new ErrorExpression(SpecialTypeSpec.NullType));
                    }
                }
                break;

            case BinaryOperatorType.LeftShift:
                methodGroup = operators.ShiftLeftOperators;
                break;

            case BinaryOperatorType.RightShift:
                methodGroup = operators.ShiftRightOperators;
                break;

            case BinaryOperatorType.RotateRight:
                methodGroup = operators.RotateRightOperators;
                break;

            case BinaryOperatorType.RotateLeft:
                methodGroup = operators.RotateLeftOperators;
                break;


            case BinaryOperatorType.Equality:
            case BinaryOperatorType.Inequality:
            case BinaryOperatorType.LessThan:
            case BinaryOperatorType.GreaterThan:
            case BinaryOperatorType.LessThanOrEqual:
            case BinaryOperatorType.GreaterThanOrEqual:
            {
                if (lhsType.Kind == TypeKind.Enum && rc.TryConvert(ref rhs, lhs.Type))
                {
                    // bool operator op(E x, E y);
                    return(HandleEnumComparison(rc, op, lhsType, isNullable, lhs, rhs));
                }
                else if (rhsType.Kind == TypeKind.Enum && rc.TryConvert(ref lhs, rhs.Type))
                {
                    // bool operator op(E x, E y);
                    return(HandleEnumComparison(rc, op, rhsType, isNullable, lhs, rhs));
                }
                else if (lhsType is PointerTypeSpec && rhsType is PointerTypeSpec)
                {
                    return(SetOperationInformations(rc, rc.compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs));
                }
                if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.Inequality)
                {
                    if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true)
                    {
                        // If it's a reference comparison
                        if (op == BinaryOperatorType.Equality)
                        {
                            methodGroup = operators.ReferenceEqualityOperators;
                        }
                        else
                        {
                            methodGroup = operators.ReferenceInequalityOperators;
                        }
                        break;
                    }
                    else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type) ||
                             IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null)
                    {
                        // compare type parameter or nullable type with the null literal
                        return(SetOperationInformations(rc, rc.compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs));
                    }
                }
                switch (op)
                {
                case BinaryOperatorType.Equality:
                    methodGroup = operators.ValueEqualityOperators;
                    break;

                case BinaryOperatorType.Inequality:
                    methodGroup = operators.ValueInequalityOperators;
                    break;

                case BinaryOperatorType.LessThan:
                    methodGroup = operators.LessThanOperators;
                    break;

                case BinaryOperatorType.GreaterThan:
                    methodGroup = operators.GreaterThanOperators;
                    break;

                case BinaryOperatorType.LessThanOrEqual:
                    methodGroup = operators.LessThanOrEqualOperators;
                    break;

                case BinaryOperatorType.GreaterThanOrEqual:
                    methodGroup = operators.GreaterThanOrEqualOperators;
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
            break;

            case BinaryOperatorType.BitwiseAnd:
            case BinaryOperatorType.BitwiseOr:
            case BinaryOperatorType.ExclusiveOr:
            {
                if (lhsType.Kind == TypeKind.Enum)
                {
                    // bool operator op(E x, E y);
                    if (rc.TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs))
                    {
                        return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs));
                    }
                }

                if (rhsType.Kind == TypeKind.Enum)
                {
                    // bool operator op(E x, E y);
                    if (rc.TryConvertEnum(ref lhs, rhs.Type, ref isNullable, ref rhs))
                    {
                        return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs));
                    }
                }

                switch (op)
                {
                case BinaryOperatorType.BitwiseAnd:
                    methodGroup = operators.BitwiseAndOperators;
                    break;

                case BinaryOperatorType.BitwiseOr:
                    methodGroup = operators.BitwiseOrOperators;
                    break;

                case BinaryOperatorType.ExclusiveOr:
                    methodGroup = operators.BitwiseXorOperators;
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
            break;

            case BinaryOperatorType.LogicalAnd:
                methodGroup = operators.LogicalAndOperators;
                break;

            case BinaryOperatorType.LogicalOr:
                methodGroup = operators.LogicalOrOperators;
                break;

            default:
                throw new InvalidOperationException();
            }
            OverloadResolution builtinOperatorOR = rc.CreateOverloadResolution(new[] { lhs, rhs });

            foreach (var candidate in methodGroup)
            {
                builtinOperatorOR.AddCandidate(candidate);
            }
            VSharpOperators.BinaryOperatorMethod m = (VSharpOperators.BinaryOperatorMethod)builtinOperatorOR.BestCandidate;
            IType resultType = m.ReturnType;

            if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None)
            {
                // If there are any user-defined operators, prefer those over the built-in operators.
                // It'll be a more informative error.
                if (userDefinedOperatorOR.BestCandidate != null)
                {
                    return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR));
                }
                else
                {
                    return(new ErrorExpression(resultType));
                }
            }
            else if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && m.CanEvaluateAtCompileTime)
            {
                object val;
                try
                {
                    val = m.Invoke(rc, lhs.ConstantValue, rhs.ConstantValue);
                }
                catch (ArithmeticException)
                {
                    return(new ErrorExpression(resultType));
                }
                return(Constant.CreateConstantFromValue(rc, resultType, val, loc));
            }
            else
            {
                lhs = rc.Convert(lhs, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
                rhs = rc.Convert(rhs, m.Parameters[1].Type, builtinOperatorOR.ArgumentConversions[1]);
                return(SetOperationInformations(rc, resultType, lhs, op, rhs,
                                                builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator));
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Resolves an invocation.
        /// </summary>
        /// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
        /// <param name="arguments">
        /// Arguments passed to the method.
        /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
        /// </param>
        /// <param name="argumentNames">
        /// The argument names. Pass the null string for positional arguments.
        /// </param>
        /// <returns>InvocationExpression</returns>
        private Expression ResolveInvocation(ResolveContext rc, Expression target, Expression[] arguments, string[] argumentNames, bool allowOptionalParameters)
        {
            // C# 4.0 spec: §7.6.5
            MethodGroupExpression mgrr = target as MethodGroupExpression;

            if (mgrr != null)
            {
                OverloadResolution or = mgrr.PerformOverloadResolution(rc.compilation, arguments, argumentNames, checkForOverflow: rc.checkForOverflow, conversions: rc.conversions, allowOptionalParameters: allowOptionalParameters);
                if (or.BestCandidate != null)
                {
                    var m = or.BestCandidate;

                    if (arguments == null && m.Name == DestructorDeclaration.MetadataName)
                    {
                        rc.Report.Error(0, loc, "Destructors cannot be called directly. Consider calling IDisposable.Dispose if available");
                    }

                    CheckSpecialMethod(rc, m);


                    if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeExpression))
                    {
                        return(or.CreateInvocation(new TypeExpression(mgrr.TargetType), returnTypeOverride:  null));
                    }
                    else
                    {
                        return(or.CreateInvocation(mgrr.TargetResult, returnTypeOverride: null));
                    }
                }
                else
                {
                    // No candidate found at all (not even an inapplicable one).
                    // This can happen with empty method groups (as sometimes used with extension methods)
                    rc.Report.Error(0, loc, "`{0}' does not contain a definition for `{1}'",
                                    mgrr.TargetType.ToString(), mgrr.MethodName);
                    return(null);
                }
            }
            if (target == null && expr is SimpleName)
            {
                rc.Report.Error(0, loc, "`{0}' does not contain a definition for `{1}'",
                                rc.CurrentTypeDefinition.ToString(), expr.GetSignatureForError());
                return(null);
            }
            else if (target == null)
            {
                return(null);
            }


            IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();

            if (invokeMethod != null)
            {
                // is it a delegate ?
                if (target.Type.Kind != TypeKind.Delegate)
                {
                    rc.Report.Error(0, loc, "Cannot invoke a non-delegate type `{0}'",
                                    target.Type.ToString());
                    return(null);
                }
                OverloadResolution or = rc.CreateOverloadResolution(arguments, argumentNames);
                or.AddCandidate(invokeMethod);

                return(new Invocation(
                           target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
                           or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors,
                           isExpandedForm: or.BestCandidateIsExpandedForm,
                           isDelegateInvocation: true,
                           argumentToParameterMap: or.GetArgumentToParameterMap(),
                           returnTypeOverride: null));
            }

            rc.Report.Error(0, loc, "The member `{0}' cannot be used as method or delegate",
                            target.GetSignatureForError());

            return(ErrorResult);
        }
Exemplo n.º 19
0
        public Expression ResolveUnaryOperator(ResolveContext rc, UnaryOperatorType op, Expression expression)
        {
            // V# 4.0 spec: §7.3.3 Unary operator overload resolution
            string overloadableOperatorName = GetOverloadableOperatorName(op);

            if (overloadableOperatorName == null)
            {
                switch (op)
                {
                case UnaryOperatorType.Dereference:
                    PointerTypeSpec p = expression.Type as PointerTypeSpec;
                    if (p != null)
                    {
                        return(SetOperationInformations(rc, p.ElementType, op, expression));
                    }
                    else
                    {
                        return(ErrorResult);
                    }

                case UnaryOperatorType.AddressOf:
                    return(SetOperationInformations(rc, new PointerTypeSpec(expression.Type), op, expression));


                default:
                    return(ErrorExpression.UnknownError);
                }
            }
            // If the type is nullable, get the underlying type:
            IType type       = NullableType.GetUnderlyingType(expression.Type);
            bool  isNullable = NullableType.IsNullable(expression.Type);

            // the operator is overloadable:
            OverloadResolution userDefinedOperatorOR = rc.CreateOverloadResolution(new[] { expression });

            foreach (var candidate in rc.GetUserDefinedOperatorCandidates(type, overloadableOperatorName))
            {
                userDefinedOperatorOR.AddCandidate(candidate);
            }
            if (userDefinedOperatorOR.FoundApplicableCandidate)
            {
                return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR));
            }

            expression = UnaryNumericPromotion(rc, op, ref type, isNullable, expression);
            VSharpOperators.OperatorMethod[] methodGroup;
            VSharpOperators operators = VSharpOperators.Get(rc.compilation);

            switch (op)
            {
            case UnaryOperatorType.PreIncrement:
            case UnaryOperatorType.Decrement:
            case UnaryOperatorType.PostIncrement:
            case UnaryOperatorType.PostDecrement:
                // V# 4.0 spec: §7.6.9 Postfix increment and decrement operators
                // V# 4.0 spec: §7.7.5 Prefix increment and decrement operators
                TypeCode code = ReflectionHelper.GetTypeCode(type);
                if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
                {
                    return(SetOperationInformations(rc, expression.Type, op, expression, isNullable));
                }
                else
                {
                    return(new ErrorExpression(expression.Type));
                }

            case UnaryOperatorType.UnaryPlus:
                methodGroup = operators.UnaryPlusOperators;
                break;

            case UnaryOperatorType.UnaryNegation:
                methodGroup = rc.checkForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators;
                break;

            case UnaryOperatorType.LogicalNot:
                methodGroup = operators.LogicalNegationOperators;
                break;

            case UnaryOperatorType.OnesComplement:
                if (type.Kind == TypeKind.Enum)
                {
                    if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null)
                    {
                        // evaluate as (E)(~(U)x);
                        var            U            = rc.compilation.FindType(expression.ConstantValue.GetType());
                        var            unpackedEnum = Constant.CreateConstantFromValue(rc, U, expression.ConstantValue, loc);
                        var            rr           = ResolveUnaryOperator(rc, op, unpackedEnum);
                        ResolveContext ovfrc        = rc.WithCheckForOverflow(false);
                        rr = new CastExpression(type, rr).DoResolve(ovfrc);
                        if (rr.IsCompileTimeConstant)
                        {
                            return(rr);
                        }
                    }
                    return(SetOperationInformations(rc, expression.Type, op, expression, isNullable));
                }
                else
                {
                    methodGroup = operators.BitwiseComplementOperators;
                    break;
                }

            default:
                throw new InvalidOperationException();
            }
            OverloadResolution builtinOperatorOR = rc.CreateOverloadResolution(new[] { expression });

            foreach (var candidate in methodGroup)
            {
                builtinOperatorOR.AddCandidate(candidate);
            }
            VSharpOperators.UnaryOperatorMethod m = (VSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate;
            IType resultType = m.ReturnType;

            if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None)
            {
                if (userDefinedOperatorOR.BestCandidate != null)
                {
                    // If there are any user-defined operators, prefer those over the built-in operators.
                    // It'll be a more informative error.
                    return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR));
                }
                else if (builtinOperatorOR.BestCandidateAmbiguousWith != null)
                {
                    // If the best candidate is ambiguous, just use the input type instead
                    // of picking one of the ambiguous overloads.
                    return(new ErrorExpression(expression.Type));
                }
                else
                {
                    return(new ErrorExpression(resultType));
                }
            }
            else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime)
            {
                object val;
                try
                {
                    val = m.Invoke(rc, expression.ConstantValue);
                }
                catch (ArithmeticException)
                {
                    return(new ErrorExpression(resultType));
                }
                return(Constant.CreateConstantFromValue(rc, resultType, val, loc));
            }
            else
            {
                expression = rc.Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
                return(SetOperationInformations(rc, resultType, op, expression,
                                                builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator));
            }
        }