C# overload resolution (C# 4.0 spec: §7.5).
コード例 #1
0
        public void ParamsMethodMatchesOneArgumentInExpandedForm()
        {
            OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int)));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
            Assert.IsTrue(r.BestCandidateIsExpandedForm);
        }
コード例 #2
0
        public void CallInvalidParamsDeclaration()
        {
            OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int[, ])));

            Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int))));
            Assert.IsFalse(r.BestCandidateIsExpandedForm);
        }
コード例 #3
0
        public void ParamsMethodMatchesInUnexpandedForm()
        {
            OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int[])));

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
            Assert.IsFalse(r.BestCandidateIsExpandedForm);
        }
コード例 #4
0
 public void LessArgumentsPassedToParamsIsBetter()
 {
     OverloadResolution r = new OverloadResolution(context, 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);
 }
コード例 #5
0
        public void LessArgumentsPassedToParamsIsBetter()
        {
            OverloadResolution r = new OverloadResolution(context, 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);
        }
コード例 #6
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);
		}
コード例 #7
0
        public void PreferIntOverUInt()
        {
            OverloadResolution r = new OverloadResolution(context, 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);
        }
コード例 #8
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);
        }
コード例 #9
0
        public void PreferMethodWithoutOptionalParameters()
        {
            var m1 = MakeMethod();
            var m2 = MakeMethod(1);

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

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
            Assert.IsFalse(r.IsAmbiguous);
            Assert.AreSame(m1, r.BestCandidate);
        }
コード例 #10
0
        public void NullableIntAndNullableUIntIsAmbiguous()
        {
            OverloadResolution r = new OverloadResolution(context, 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);
        }
コード例 #11
0
        public void NullableIntAndNullableUIntIsAmbiguous()
        {
            OverloadResolution r = new OverloadResolution(context, 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);
        }
コード例 #12
0
        public InvocationResolveResult(ResolveResult targetResult, OverloadResolution or, ITypeResolveContext context)
            : base(
                or.IsExtensionMethodInvocation ? null : targetResult,
                or.GetBestCandidateWithSubstitutedTypeArguments(),
                context)
        {
            this.OverloadResolutionErrors = or.BestCandidateErrors;
            this.argumentToParameterMap   = or.GetArgumentToParameterMap();
            this.Arguments = or.GetArgumentsWithConversions();

            this.IsExtensionMethodInvocation = or.IsExtensionMethodInvocation;
            this.IsExpandedForm             = or.BestCandidateIsExpandedForm;
            this.IsLiftedOperatorInvocation = or.BestCandidate is OverloadResolution.ILiftedOperator;
        }
コード例 #13
0
		public InvocationResolveResult(ResolveResult targetResult, OverloadResolution or, ITypeResolveContext context)
			: base(
				or.IsExtensionMethodInvocation ? null : targetResult,
				or.GetBestCandidateWithSubstitutedTypeArguments(),
				context)
		{
			this.OverloadResolutionErrors = or.BestCandidateErrors;
			this.argumentToParameterMap = or.GetArgumentToParameterMap();
			this.Arguments = or.GetArgumentsWithConversions();
			
			this.IsExtensionMethodInvocation = or.IsExtensionMethodInvocation;
			this.IsExpandedForm = or.BestCandidateIsExpandedForm;
			this.IsLiftedOperatorInvocation = or.BestCandidate is OverloadResolution.ILiftedOperator;
		}
コード例 #14
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);
        }
コード例 #15
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(KnownTypeReference.Int32.Resolve(context))
            };

            OverloadResolution r = new OverloadResolution(context, args);

            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
            Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors);
        }
コード例 #16
0
        public void BetterConversionByLambdaReturnValue()
        {
            var m1 = MakeMethod(typeof(Func <long>));
            var m2 = MakeMethod(typeof(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);
        }
コード例 #17
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(KnownTypeReference.Byte.Resolve(context))
            };

            OverloadResolution r = new OverloadResolution(context, 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);
        }
コード例 #18
0
		public void SkeetEvilOverloadResolution()
		{
			// http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx
			
			// static void Foo<T>(T? ignored = default(T?)) where T : struct
			var m1 = MakeUnresolvedMethod();
			m1.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, 0, "T") { HasValueTypeConstraint = true });
			m1.Parameters.Add(MakeOptionalParameter(
				NullableType.Create(new TypeParameterReference(SymbolKind.Method, 0)),
				"ignored"
			));
			
			// class ClassConstraint<T> where T : class {}
			var classConstraint = new DefaultUnresolvedTypeDefinition(string.Empty, "ClassConstraint");
			classConstraint.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.TypeDefinition, 0, "T") { HasReferenceTypeConstraint = true });
			
			// static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
			// where T : class
			var m2 = MakeUnresolvedMethod();
			m2.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, 0, "T") { HasReferenceTypeConstraint = true });
			m2.Parameters.Add(MakeOptionalParameter(
				new ParameterizedTypeReference(classConstraint, new[] { new TypeParameterReference(SymbolKind.Method, 0) }),
				"ignored"
			));
			
			// static void Foo<T>()
			var m3 = MakeUnresolvedMethod();
			m3.TypeParameters.Add(new DefaultUnresolvedTypeParameter(SymbolKind.Method, 0, "T"));
			
			ICompilation compilation = TypeSystemHelper.CreateCompilation(classConstraint);
			var context = new SimpleTypeResolveContext(compilation.MainAssembly);
			IMethod resolvedM1 = (IMethod)m1.CreateResolved(context);
			IMethod resolvedM2 = (IMethod)m2.CreateResolved(context);
			IMethod resolvedM3 = (IMethod)m3.CreateResolved(context);
			
			// 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);
		}
コード例 #19
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);
		}
コード例 #20
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);
		}
コード例 #21
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);
		}
コード例 #22
0
        public OverloadResolution PerformOverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, Conversions conversions = null)
        {
            Log.WriteLine("Performing overload resolution for " + this);
            Log.WriteCollection("  Arguments: ", arguments);

            var typeArgumentArray = this.TypeArguments.ToArray();
            OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, typeArgumentArray, conversions);

            or.AllowExpandingParams = allowExpandingParams;

            or.AddMethodLists(methodLists);

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

                var extensionMethods = this.GetExtensionMethods();

                if (extensionMethods.Count > 0)
                {
                    Log.WriteLine("No candidate is applicable, trying {0} extension methods groups...", extensionMethods.Count);
                    ResolveResult[] extArguments = new ResolveResult[arguments.Length + 1];
                    extArguments[0] = new ResolveResult(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(context, extArguments, extArgumentNames, typeArgumentArray, conversions);
                    extOr.AllowExpandingParams        = allowExpandingParams;
                    extOr.IsExtensionMethodInvocation = true;

                    foreach (var g in extensionMethods)
                    {
                        foreach (var method in g)
                        {
                            Log.Indent();
                            OverloadResolutionErrors errors = extOr.AddCandidate(method);
                            Log.Unindent();
                            or.LogCandidateAddingResult("  Extension", method, errors);
                        }
                        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;
                    }
                }
            }
            Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.GetBestCandidateWithSubstitutedTypeArguments());
            return(or);
        }
コード例 #23
0
ファイル: CSharpResolver.cs プロジェクト: CSRedRat/NRefactory
 OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null)
 {
     var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions);
     or.CheckForOverflow = checkForOverflow;
     return or;
 }
コード例 #24
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);
		}
コード例 #25
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            // static void Foo<T>(T? ignored = default(T?)) where T : struct
            var m1 = MakeMethod();

            m1.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")
            {
                HasValueTypeConstraint = true
            });
            m1.Parameters.Add(MakeOptionalParameter(
                                  NullableType.Create(m1.TypeParameters[0], context),
                                  "ignored"
                                  ));

            // class ClassConstraint<T> where T : class {}
            DefaultTypeDefinition classConstraint = new DefaultTypeDefinition(dummyClass, "ClassConstraint");

            classConstraint.TypeParameters.Add(new DefaultTypeParameter(EntityType.TypeDefinition, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });

            // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
            // where T : class
            var m2 = MakeMethod();

            m2.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });
            m2.Parameters.Add(MakeOptionalParameter(
                                  new ParameterizedType(classConstraint, new[] { m2.TypeParameters[0] }),
                                  "ignored"
                                  ));

            // static void Foo<T>()
            var m3 = MakeMethod();

            m3.TypeParameters.Add(new DefaultTypeParameter(EntityType.Method, 0, "T"));

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

            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreSame(m1, o.BestCandidate);

            // Call: Foo<string>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(string).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m2));
            Assert.AreSame(m2, o.BestCandidate);

            // Call: Foo<int?>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int?).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m3));
            Assert.AreSame(m3, o.BestCandidate);
        }
コード例 #26
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            // static void Foo<T>(T? ignored = default(T?)) where T : struct
            var m1 = MakeMethod();
            m1.TypeParameters.Add(new DefaultTypeParameter(m1, 0, "T") { HasValueTypeConstraint = true });
            m1.Parameters.Add(MakeOptionalParameter(
                NullableType.Create(m1.TypeParameters[0], context),
                "ignored"
            ));

            // class ClassConstraint<T> where T : class {}
            DefaultTypeDefinition classConstraint = new DefaultTypeDefinition(dummyClass, "ClassConstraint");
            classConstraint.TypeParameters.Add(new DefaultTypeParameter(classConstraint, 0, "T") { HasReferenceTypeConstraint = true });

            // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
            // where T : class
            var m2 = MakeMethod();
            m2.TypeParameters.Add(new DefaultTypeParameter(m2, 0, "T") { HasReferenceTypeConstraint = true });
            m2.Parameters.Add(MakeOptionalParameter(
                new ParameterizedType(classConstraint, new[] { m2.TypeParameters[0] }),
                "ignored"
            ));

            // static void Foo<T>()
            var m3 = MakeMethod();
            m3.TypeParameters.Add(new DefaultTypeParameter(m3, 0, "T"));

            // Call: Foo<int>();
            OverloadResolution o;
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreSame(m1, o.BestCandidate);

            // Call: Foo<string>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(string).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m2));
            Assert.AreSame(m2, o.BestCandidate);

            // Call: Foo<int?>();
            o = new OverloadResolution(context, new ResolveResult[0], typeArguments: new[] { typeof(int?).ToTypeReference().Resolve(context) });
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m1));
            Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(m2));
            Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(m3));
            Assert.AreSame(m3, o.BestCandidate);
        }
コード例 #27
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
        /// <summary>
        /// Resolves an indexer access.
        /// </summary>
        /// <param name="target">Target expression.</param>
        /// <param name="arguments">
        /// Arguments passed to the indexer.
        /// 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>ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult</returns>
        public ResolveResult ResolveIndexer(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
        {
            switch (target.Type.Kind) {
                case TypeKind.Dynamic:
                    for (int i = 0; i < arguments.Length; i++) {
                        arguments[i] = Convert(arguments[i], SpecialType.Dynamic);
                    }
                    return new ArrayAccessResolveResult(SpecialType.Dynamic, target, arguments);

                case TypeKind.Array:
                case TypeKind.Pointer:
                    // §7.6.6.1 Array access / §18.5.3 Pointer element access
                    AdjustArrayAccessArguments(arguments);
                    return new ArrayAccessResolveResult(((TypeWithElementType)target.Type).ElementType, target, arguments);
            }

            // §7.6.6.2 Indexer access
            OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions);
            MemberLookup lookup = CreateMemberLookup();
            var indexers = lookup.LookupIndexers(target.Type);
            or.AddMethodLists(indexers);
            if (or.BestCandidate != null) {
                return or.CreateResolveResult(target);
            } else {
                return ErrorResult;
            }
        }
コード例 #28
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
 ResolveResult CreateResolveResultForUserDefinedOperator(OverloadResolution r)
 {
     return r.CreateResolveResult(null);
 }
コード例 #29
0
		public void BetterConversionByLambdaReturnValue()
		{
			var m1 = MakeMethod(typeof(Func<long>));
			var m2 = MakeMethod(typeof(Func<int>));
			
			// M(() => default(byte));
			ResolveResult[] args = {
				new MockLambda(KnownTypeReference.Byte.Resolve(context))
			};
			
			OverloadResolution r = new OverloadResolution(context, 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);
		}
コード例 #30
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);
		}
コード例 #31
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
 /// <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="ConversionResolveResult"/>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>
 /// <returns>InvocationResolveResult or ErrorResolveResult</returns>
 public ResolveResult ResolveObjectCreation(IType type, ResolveResult[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false)
 {
     if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
         return Convert(arguments[0], type);
     }
     OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions);
     MemberLookup lookup = CreateMemberLookup();
     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.CreateResolveResult(null);
     } else {
         return new ErrorResolveResult(type);
     }
 }
コード例 #32
0
        public void SkeetEvilOverloadResolution()
        {
            // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx

            // static void Foo<T>(T? ignored = default(T?)) where T : struct
            var m1 = MakeUnresolvedMethod();

            m1.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T")
            {
                HasValueTypeConstraint = true
            });
            m1.Parameters.Add(MakeOptionalParameter(
                                  NullableType.Create(new TypeParameterReference(EntityType.Method, 0)),
                                  "ignored"
                                  ));

            // class ClassConstraint<T> where T : class {}
            var classConstraint = new DefaultUnresolvedTypeDefinition(string.Empty, "ClassConstraint");

            classConstraint.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });

            // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
            // where T : class
            var m2 = MakeUnresolvedMethod();

            m2.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T")
            {
                HasReferenceTypeConstraint = true
            });
            m2.Parameters.Add(MakeOptionalParameter(
                                  new ParameterizedTypeReference(classConstraint, new[] { new TypeParameterReference(EntityType.Method, 0) }),
                                  "ignored"
                                  ));

            // static void Foo<T>()
            var m3 = MakeUnresolvedMethod();

            m3.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T"));

            var     context    = new SimpleTypeResolveContext(compilation.MainAssembly);
            IMethod resolvedM1 = (IMethod)m1.CreateResolved(context);
            IMethod resolvedM2 = (IMethod)m2.CreateResolved(context);
            IMethod resolvedM3 = (IMethod)m3.CreateResolved(context);

            // 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);
        }
コード例 #33
0
 public ConstraintValidatingSubstitution(IType[] typeArguments, OverloadResolution overloadResolution)
     : base(typeArguments)
 {
     this.overloadResolution = overloadResolution;
 }
コード例 #34
0
ファイル: OverloadResolution.cs プロジェクト: sq/ILSpy-JSIL
 public ConstraintValidatingSubstitution(IList <IType> classTypeArguments, IList <IType> methodTypeArguments, OverloadResolution overloadResolution)
     : base(classTypeArguments, methodTypeArguments)
 {
     this.conversions = overloadResolution.conversions;
 }
コード例 #35
0
 public void ParamsMethodMatchesOneArgumentInExpandedForm()
 {
     OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int)));
     Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
     Assert.IsTrue(r.BestCandidateIsExpandedForm);
 }
コード例 #36
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
        public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
        {
            if (SpecialType.Dynamic.Equals(expression.Type))
                return UnaryOperatorResolveResult(SpecialType.Dynamic, op, expression);

            // C# 4.0 spec: §7.3.3 Unary operator overload resolution
            string overloadableOperatorName = GetOverloadableOperatorName(op);
            if (overloadableOperatorName == null) {
                switch (op) {
                    case UnaryOperatorType.Dereference:
                        PointerType p = expression.Type as PointerType;
                        if (p != null)
                            return UnaryOperatorResolveResult(p.ElementType, op, expression);
                        else
                            return ErrorResult;
                    case UnaryOperatorType.AddressOf:
                        return UnaryOperatorResolveResult(new PointerType(expression.Type), op, expression);
                    case UnaryOperatorType.Await:
                        ResolveResult getAwaiterMethodGroup = ResolveMemberAccess(expression, "GetAwaiter", EmptyList<IType>.Instance, true);
                        ResolveResult getAwaiterInvocation = ResolveInvocation(getAwaiterMethodGroup, new ResolveResult[0]);
                        var getResultMethodGroup = CreateMemberLookup().Lookup(getAwaiterInvocation, "GetResult", EmptyList<IType>.Instance, true) as MethodGroupResolveResult;
                        if (getResultMethodGroup != null) {
                            var or = getResultMethodGroup.PerformOverloadResolution(compilation, new ResolveResult[0], allowExtensionMethods: false, conversions: conversions);
                            IType awaitResultType = or.GetBestCandidateWithSubstitutedTypeArguments().ReturnType;
                            return UnaryOperatorResolveResult(awaitResultType, UnaryOperatorType.Await, expression);
                        } else {
                            return UnaryOperatorResolveResult(SpecialType.UnknownType, UnaryOperatorType.Await, expression);
                        }
                    default:
                        throw new ArgumentException("Invalid value for UnaryOperatorType", "op");
                }
            }
            // 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 = new OverloadResolution(compilation, new[] { expression }, conversions: conversions);
            foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) {
                userDefinedOperatorOR.AddCandidate(candidate);
            }
            if (userDefinedOperatorOR.FoundApplicableCandidate) {
                return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR);
            }

            expression = UnaryNumericPromotion(op, ref type, isNullable, expression);
            CSharpOperators.OperatorMethod[] methodGroup;
            CSharpOperators operators = CSharpOperators.Get(compilation);
            switch (op) {
                case UnaryOperatorType.Increment:
                case UnaryOperatorType.Decrement:
                case UnaryOperatorType.PostIncrement:
                case UnaryOperatorType.PostDecrement:
                    // C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
                    // C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
                    TypeCode code = ReflectionHelper.GetTypeCode(type);
                    if ((code >= TypeCode.SByte && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer)
                        return UnaryOperatorResolveResult(expression.Type, op, expression);
                    else
                        return new ErrorResolveResult(expression.Type);
                case UnaryOperatorType.Plus:
                    methodGroup = operators.UnaryPlusOperators;
                    break;
                case UnaryOperatorType.Minus:
                    methodGroup = CheckForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators;
                    break;
                case UnaryOperatorType.Not:
                    methodGroup = operators.LogicalNegationOperators;
                    break;
                case UnaryOperatorType.BitNot:
                    if (type.Kind == TypeKind.Enum) {
                        if (expression.IsCompileTimeConstant && !isNullable) {
                            // evaluate as (E)(~(U)x);
                            var U = compilation.FindType(expression.ConstantValue.GetType());
                            var unpackedEnum = new ConstantResolveResult(U, expression.ConstantValue);
                            return CheckErrorAndResolveCast(expression.Type, ResolveUnaryOperator(op, unpackedEnum));
                        } else {
                            return UnaryOperatorResolveResult(expression.Type, op, expression);
                        }
                    } else {
                        methodGroup = operators.BitwiseComplementOperators;
                        break;
                    }
                default:
                    throw new InvalidOperationException();
            }
            OverloadResolution builtinOperatorOR = new OverloadResolution(compilation, new[] { expression }, conversions: conversions);
            foreach (var candidate in methodGroup) {
                builtinOperatorOR.AddCandidate(candidate);
            }
            CSharpOperators.UnaryOperatorMethod m = (CSharpOperators.UnaryOperatorMethod)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 CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR);
                else
                    return new ErrorResolveResult(resultType);
            } else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
                object val;
                try {
                    val = m.Invoke(this, expression.ConstantValue);
                } catch (ArithmeticException) {
                    return new ErrorResolveResult(resultType);
                }
                return new ConstantResolveResult(resultType, val);
            } else {
                expression = Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
                return UnaryOperatorResolveResult(resultType, op, expression);
            }
        }
コード例 #37
0
ファイル: OverloadResolution.cs プロジェクト: Netring/ILSpy
			public ConstraintValidatingSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments, OverloadResolution overloadResolution)
				: base(classTypeArguments, methodTypeArguments)
			{
				this.conversions = overloadResolution.conversions;
			}
コード例 #38
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
        public ResolveResult ResolveBinaryOperator(BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
        {
            if (SpecialType.Dynamic.Equals(lhs.Type) || SpecialType.Dynamic.Equals(rhs.Type)) {
                lhs = Convert(lhs, SpecialType.Dynamic);
                rhs = Convert(rhs, SpecialType.Dynamic);
                return BinaryOperatorResolveResult(SpecialType.Dynamic, lhs, op, rhs);
            }

            // C# 4.0 spec: §7.3.4 Binary operator overload resolution
            string overloadableOperatorName = 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.ConditionalAnd) {
                    overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseAnd);
                } else if (op == BinaryOperatorType.ConditionalOr) {
                    overloadableOperatorName = GetOverloadableOperatorName(BinaryOperatorType.BitwiseOr);
                } else if (op == BinaryOperatorType.NullCoalescing) {
                    // null coalescing operator is not overloadable and needs to be handled separately
                    return ResolveNullCoalescingOperator(lhs, rhs);
                } else {
                    throw new ArgumentException("Invalid value for BinaryOperatorType", "op");
                }
            }

            // 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 = new OverloadResolution(compilation, new[] { lhs, rhs }, conversions: conversions);
            HashSet<IParameterizedMember> userOperatorCandidates = new HashSet<IParameterizedMember>();
            userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName));
            userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName));
            foreach (var candidate in userOperatorCandidates) {
                userDefinedOperatorOR.AddCandidate(candidate);
            }
            if (userDefinedOperatorOR.FoundApplicableCandidate) {
                return CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR);
            }

            if (SpecialType.NullType.Equals(lhsType) && rhsType.IsReferenceType == false
                || lhsType.IsReferenceType == false && SpecialType.NullType.Equals(rhsType))
            {
                isNullable = true;
            }
            if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight) {
                // special case: the shift operators allow "var x = null << null", producing int?.
                if (SpecialType.NullType.Equals(lhsType) && SpecialType.NullType.Equals(rhsType))
                    isNullable = true;
                // for shift operators, do unary promotion independently on both arguments
                lhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref lhsType, isNullable, lhs);
                rhs = UnaryNumericPromotion(UnaryOperatorType.Plus, ref rhsType, isNullable, rhs);
            } else {
                bool allowNullableConstants = op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality;
                if (!BinaryNumericPromotion(isNullable, ref lhs, ref rhs, allowNullableConstants))
                    return new ErrorResolveResult(lhs.Type);
            }
            // re-read underlying types after numeric promotion
            lhsType = NullableType.GetUnderlyingType(lhs.Type);
            rhsType = NullableType.GetUnderlyingType(rhs.Type);

            IEnumerable<CSharpOperators.OperatorMethod> methodGroup;
            CSharpOperators operators = CSharpOperators.Get(compilation);
            switch (op) {
                case BinaryOperatorType.Multiply:
                    methodGroup = operators.MultiplicationOperators;
                    break;
                case BinaryOperatorType.Divide:
                    methodGroup = operators.DivisionOperators;
                    break;
                case BinaryOperatorType.Modulus:
                    methodGroup = operators.RemainderOperators;
                    break;
                case BinaryOperatorType.Add:
                    methodGroup = operators.AdditionOperators;
                    {
                        if (lhsType.Kind == TypeKind.Enum) {
                            // E operator +(E x, U y);
                            IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable);
                            if (TryConvert(ref rhs, underlyingType)) {
                                return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
                            }
                        }
                        if (rhsType.Kind == TypeKind.Enum) {
                            // E operator +(U x, E y);
                            IType underlyingType = MakeNullable(GetEnumUnderlyingType(rhsType), isNullable);
                            if (TryConvert(ref lhs, underlyingType)) {
                                return HandleEnumOperator(isNullable, rhsType, op, lhs, rhs);
                            }
                        }

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

                        if (lhsType is PointerType) {
                            methodGroup = new [] {
                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int32),
                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt32),
                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.Int64),
                                PointerArithmeticOperator(lhsType, lhsType, KnownTypeCode.UInt64)
                            };
                        } else if (rhsType is PointerType) {
                            methodGroup = new [] {
                                PointerArithmeticOperator(rhsType, KnownTypeCode.Int32, rhsType),
                                PointerArithmeticOperator(rhsType, KnownTypeCode.UInt32, rhsType),
                                PointerArithmeticOperator(rhsType, KnownTypeCode.Int64, rhsType),
                                PointerArithmeticOperator(rhsType, KnownTypeCode.UInt64, rhsType)
                            };
                        }
                        if (SpecialType.NullType.Equals(lhsType) && SpecialType.NullType.Equals(rhsType))
                            return new ErrorResolveResult(SpecialType.NullType);
                    }
                    break;
                case BinaryOperatorType.Subtract:
                    methodGroup = operators.SubtractionOperators;
                    {
                        if (lhsType.Kind == TypeKind.Enum) {
                            // E operator –(E x, U y);
                            IType underlyingType = MakeNullable(GetEnumUnderlyingType(lhsType), isNullable);
                            if (TryConvert(ref rhs, underlyingType)) {
                                return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
                            }
                            // U operator –(E x, E y);
                            if (TryConvert(ref rhs, lhs.Type)) {
                                return HandleEnumSubtraction(isNullable, lhsType, lhs, rhs);
                            }
                        }
                        if (rhsType.Kind == TypeKind.Enum) {
                            // U operator –(E x, E y);
                            if (TryConvert(ref lhs, rhs.Type)) {
                                return HandleEnumSubtraction(isNullable, rhsType, lhs, rhs);
                            }
                        }

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

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

                        if (SpecialType.NullType.Equals(lhsType) && SpecialType.NullType.Equals(rhsType))
                            return new ErrorResolveResult(SpecialType.NullType);
                    }
                    break;
                case BinaryOperatorType.ShiftLeft:
                    methodGroup = operators.ShiftLeftOperators;
                    break;
                case BinaryOperatorType.ShiftRight:
                    methodGroup = operators.ShiftRightOperators;
                    break;
                case BinaryOperatorType.Equality:
                case BinaryOperatorType.InEquality:
                case BinaryOperatorType.LessThan:
                case BinaryOperatorType.GreaterThan:
                case BinaryOperatorType.LessThanOrEqual:
                case BinaryOperatorType.GreaterThanOrEqual:
                    {
                        if (lhsType.Kind == TypeKind.Enum && TryConvert(ref rhs, lhs.Type)) {
                            // bool operator op(E x, E y);
                            return HandleEnumComparison(op, lhsType, isNullable, lhs, rhs);
                        } else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
                            // bool operator op(E x, E y);
                            return HandleEnumComparison(op, rhsType, isNullable, lhs, rhs);
                        } else if (lhsType is PointerType && rhsType is PointerType) {
                            return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
                        }
                        switch (op) {
                            case BinaryOperatorType.Equality:
                                methodGroup = operators.EqualityOperators;
                                break;
                            case BinaryOperatorType.InEquality:
                                methodGroup = operators.InequalityOperators;
                                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 && TryConvert(ref rhs, lhs.Type)) {
                            // bool operator op(E x, E y);
                            return HandleEnumOperator(isNullable, lhsType, op, lhs, rhs);
                        } else if (rhsType.Kind == TypeKind.Enum && TryConvert(ref lhs, rhs.Type)) {
                            // bool operator op(E x, E y);
                            return HandleEnumOperator(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.ConditionalAnd:
                    methodGroup = operators.LogicalAndOperators;
                    break;
                case BinaryOperatorType.ConditionalOr:
                    methodGroup = operators.LogicalOrOperators;
                    break;
                default:
                    throw new InvalidOperationException();
            }
            OverloadResolution builtinOperatorOR = new OverloadResolution(compilation, new[] { lhs, rhs }, conversions: conversions);
            foreach (var candidate in methodGroup) {
                builtinOperatorOR.AddCandidate(candidate);
            }
            CSharpOperators.BinaryOperatorMethod m = (CSharpOperators.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 CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR);
                else
                    return new ErrorResolveResult(resultType);
            } else if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) {
                object val;
                try {
                    val = m.Invoke(this, lhs.ConstantValue, rhs.ConstantValue);
                } catch (ArithmeticException) {
                    return new ErrorResolveResult(resultType);
                }
                return new ConstantResolveResult(resultType, val);
            } else {
                lhs = Convert(lhs, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]);
                rhs = Convert(rhs, m.Parameters[1].Type, builtinOperatorOR.ArgumentConversions[1]);
                return BinaryOperatorResolveResult(resultType, lhs, op, rhs);
            }
        }
コード例 #39
0
ファイル: CSharpResolver.cs プロジェクト: nieve/NRefactory
		ResolveResult CreateResolveResultForUserDefinedOperator(OverloadResolution r, System.Linq.Expressions.ExpressionType operatorType)
		{
			if (r.BestCandidateErrors != OverloadResolutionErrors.None)
				return r.CreateResolveResult(null);
			IMethod method = (IMethod)r.BestCandidate;
			return new OperatorResolveResult(method.ReturnType, operatorType, method,
			                                 isLiftedOperator: method is OverloadResolution.ILiftedOperator,
			                                 operands: r.GetArgumentsWithConversions());
		}
コード例 #40
0
ファイル: CSharpResolver.cs プロジェクト: holmak/NRefactory
        /// <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>InvocationResolveResult or UnknownMethodResolveResult</returns>
        public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
        {
            // C# 4.0 spec: §7.6.5

            if (SpecialType.Dynamic.Equals(target.Type))
                return DynamicResult;

            MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
            if (mgrr != null) {
                OverloadResolution or = mgrr.PerformOverloadResolution(compilation, arguments, argumentNames, conversions: conversions);
                if (or.BestCandidate != null) {
                    return or.CreateResolveResult(mgrr.TargetResult);
                } else {
                    // No candidate found at all (not even an inapplicable one).
                    // This can happen with empty method groups (as sometimes used with extension methods)
                    return new UnknownMethodResolveResult(
                        mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames));
                }
            }
            UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult;
            if (umrr != null) {
                return new UnknownMethodResolveResult(umrr.TargetType, umrr.MemberName, umrr.TypeArguments, CreateParameters(arguments, argumentNames));
            }
            UnknownIdentifierResolveResult uirr = target as UnknownIdentifierResolveResult;
            if (uirr != null && CurrentTypeDefinition != null) {
                return new UnknownMethodResolveResult(CurrentTypeDefinition, uirr.Identifier, EmptyList<IType>.Instance, CreateParameters(arguments, argumentNames));
            }
            IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();
            if (invokeMethod != null) {
                OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, conversions: conversions);
                or.AddCandidate(invokeMethod);
                return new CSharpInvocationResolveResult(
                    target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
                    or.GetArgumentsWithConversions(), or.BestCandidateErrors,
                    isExpandedForm: or.BestCandidateIsExpandedForm,
                    isDelegateInvocation: true,
                    argumentToParameterMap: or.GetArgumentToParameterMap());
            }
            return ErrorResult;
        }
コード例 #41
0
 public ConstraintValidatingSubstitution(IType[] typeArguments, OverloadResolution overloadResolution)
     : base(typeArguments)
 {
     this.overloadResolution = overloadResolution;
 }