public void ParamsMethodMatchesOneArgumentInExpandedForm() { OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[])))); Assert.IsTrue(r.BestCandidateIsExpandedForm); }
public void CallInvalidParamsDeclaration() { OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int[, ]))); Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int)))); Assert.IsFalse(r.BestCandidateIsExpandedForm); }
public void ParamsMethodMatchesInUnexpandedForm() { OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int[]))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[])))); Assert.IsFalse(r.BestCandidateIsExpandedForm); }
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); }
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); }
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); }
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); }
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); }
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); }
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; }
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); }
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); }
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); }
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); }
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); }
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); }
public void CallInvalidParamsDeclaration() { OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[,]))); Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int)))); Assert.IsFalse(r.BestCandidateIsExpandedForm); }
public void ParamsMethodMatchesInUnexpandedForm() { OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[]))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[])))); Assert.IsFalse(r.BestCandidateIsExpandedForm); }
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); }
OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null) { var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions); or.CheckForOverflow = checkForOverflow; return or; }
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); }
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); }
/// <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; } }
ResolveResult CreateResolveResultForUserDefinedOperator(OverloadResolution r) { return r.CreateResolveResult(null); }
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); }
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); }
/// <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); } }
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); }
public ConstraintValidatingSubstitution(IType[] typeArguments, OverloadResolution overloadResolution) : base(typeArguments) { this.overloadResolution = overloadResolution; }
public ConstraintValidatingSubstitution(IList <IType> classTypeArguments, IList <IType> methodTypeArguments, OverloadResolution overloadResolution) : base(classTypeArguments, methodTypeArguments) { this.conversions = overloadResolution.conversions; }
public void ParamsMethodMatchesOneArgumentInExpandedForm() { OverloadResolution r = new OverloadResolution(context, MakeArgumentList(typeof(int))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[])))); Assert.IsTrue(r.BestCandidateIsExpandedForm); }
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); } }
public ConstraintValidatingSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments, OverloadResolution overloadResolution) : base(classTypeArguments, methodTypeArguments) { this.conversions = overloadResolution.conversions; }
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); } }
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()); }
/// <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; }