internal object InvokeMethod(Symbols.Method TargetProcedure, object[] Arguments, bool[] CopyBack, BindingFlags Flags) { object obj3; MethodBase callTarget = NewLateBinding.GetCallTarget(TargetProcedure, Flags); object[] parameters = NewLateBinding.ConstructCallArguments(TargetProcedure, Arguments, Flags); if ((this.m_Instance == null) && !Symbols.IsShared(callTarget)) { throw new NullReferenceException(Utils.GetResourceString("NullReference_InstanceReqToAccessMember1", new string[] { TargetProcedure.ToString() })); } if (Symbols.IsNonPublicRuntimeMember(callTarget)) { throw new MissingMemberException(); } try { obj3 = callTarget.Invoke(this.m_Instance, parameters); } catch (TargetInvocationException exception) { throw exception.InnerException; } OverloadResolution.ReorderArgumentArray(TargetProcedure, parameters, Arguments, CopyBack, Flags); return(obj3); }
public void SkeetEvilOverloadResolution() { // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx var container = compilation.FindType(typeof(SkeetEvilOverloadResolutionTestCase)).GetDefinition(); IMethod resolvedM1 = container.GetMethods(m => m.Name == "Foo").First(); IMethod resolvedM2 = container.GetMethods(m => m.Name == "Foo").Skip(1).First(); IMethod resolvedM3 = container.GetMethods(m => m.Name == "Foo").Skip(2).First(); // Call: Foo<int>(); OverloadResolution o; o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int)) }); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2)); Assert.AreSame(resolvedM1, o.BestCandidate); // Call: Foo<string>(); o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(string)) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM2)); Assert.AreSame(resolvedM2, o.BestCandidate); // Call: Foo<int?>(); o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int?)) }); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1)); Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2)); Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM3)); Assert.AreSame(resolvedM3, o.BestCandidate); }
public OverloadResolution PerformOverloadResolution(ICompilation compilation, Expression[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, bool allowOptionalParameters = true, bool checkForOverflow = false, VSharpConversions conversions = null) { var typeArgumentArray = this.TypeArguments.ToArray(); OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions); or.AllowExpandingParams = allowExpandingParams; or.AllowOptionalParameters = allowOptionalParameters; or.CheckForOverflow = checkForOverflow; or.AddMethodLists(methodLists); if (allowExtensionMethods && !or.FoundApplicableCandidate) { // No applicable match found, so let's try extension methods. var extensionMethods = this.GetExtensionMethods(); if (extensionMethods.Any()) { Expression[] extArguments = new Expression[arguments.Length + 1]; extArguments[0] = new AST.Expression(this.TargetType); arguments.CopyTo(extArguments, 1); string[] extArgumentNames = null; if (argumentNames != null) { extArgumentNames = new string[argumentNames.Length + 1]; argumentNames.CopyTo(extArgumentNames, 1); } var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions); extOr.AllowExpandingParams = allowExpandingParams; extOr.AllowOptionalParameters = allowOptionalParameters; extOr.IsExtensionMethodInvocation = true; extOr.CheckForOverflow = checkForOverflow; foreach (var g in extensionMethods) { foreach (var method in g) extOr.AddCandidate(method); if (extOr.FoundApplicableCandidate) break; } // For the lack of a better comparison function (the one within OverloadResolution // cannot be used as it depends on the argument set): if (extOr.FoundApplicableCandidate || or.BestCandidate == null) { // Consider an extension method result better than the normal result only // if it's applicable; or if there is no normal result. or = extOr; } } } return or; }
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); }
OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, TranslatedExpression target, IType[] typeArguments, IList <TranslatedExpression> arguments) { var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, arguments.SelectArray(a => a.ResolveResult), typeArguments: typeArguments); if (expectedTargetDetails.CallOpCode == OpCode.NewObj) { foreach (IMethod ctor in method.DeclaringType.GetConstructors()) { if (lookup.IsAccessible(ctor, allowProtectedAccess: resolver.CurrentTypeDefinition == method.DeclaringTypeDefinition)) { or.AddCandidate(ctor); } } } else { var result = lookup.Lookup(target.ResolveResult, method.Name, EmptyList <IType> .Instance, true) as MethodGroupResolveResult; if (result == null) { return(OverloadResolutionErrors.AmbiguousMatch); } or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray()); } if (or.BestCandidateErrors != OverloadResolutionErrors.None) { return(or.BestCandidateErrors); } if (!IsAppropriateCallTarget(expectedTargetDetails, method, or.GetBestCandidateWithSubstitutedTypeArguments())) { return(OverloadResolutionErrors.AmbiguousMatch); } return(OverloadResolutionErrors.None); }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: method = (IMethod)typeSystem.Resolve(((ILFunction)func).Method); break; } var target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); var result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, true) as MethodGroupResolveResult; if (result == null) { target = target.ConvertTo(method.DeclaringType, expressionBuilder); } else { or.AddMethodLists(result.MethodsGroupedByDeclaringType.ToArray()); if (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(method, or.BestCandidate, func.OpCode == OpCode.LdVirtFtn)) { target = target.ConvertTo(method.DeclaringType, expressionBuilder); } } var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), mre) // .WithAnnotation(new DelegateConstruction.Annotation(func.OpCode == OpCode.LdVirtFtn, target, method.Name)) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), // TODO handle extension methods capturing the first argument Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); if (func is ILFunction) { return(expressionBuilder.TranslateFunction(oce, target, (ILFunction)func)); } else { return(oce); } }
public void LessArgumentsPassedToParamsIsBetter() { OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int), typeof(int), typeof(int))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[])))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int), typeof(int[])))); Assert.IsFalse(r.IsAmbiguous); Assert.AreEqual(2, r.BestCandidate.Parameters.Count); }
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 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(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 NullableIntAndNullableUIntIsAmbiguous() { OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(ushort?))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(int?)))); Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(uint?)))); Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors); // then adding a matching overload solves the ambiguity: Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(ushort?)))); Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors); Assert.IsNull(r.BestCandidateAmbiguousWith); }
IInsightWindow ShowInsight(ITextEditor editor, IList <IInsightItem> insightItems, ICollection <ResolveResult> parameters, char charTyped) { int paramCount = parameters.Count; if (insightItems == null || insightItems.Count == 0) { return(null); } bool overloadIsSure; int defaultIndex; if (insightItems.Count == 1) { overloadIsSure = true; defaultIndex = 0; } else { var methods = insightItems.Select(item => GetMethodFromInsightItem(item)).ToList(); IReturnType[] argumentTypes = new IReturnType[paramCount + 1]; int i = 0; foreach (ResolveResult rr in parameters) { if (rr != null) { argumentTypes[i] = rr.ResolvedType; } i++; } IMethodOrProperty result = OverloadResolution.FindOverload(methods.Where(m => m != null), argumentTypes, true, false, out overloadIsSure); defaultIndex = methods.IndexOf(result); } IInsightWindow insightWindow = editor.ShowInsightWindow(insightItems); if (insightWindow != null) { InitializeOpenedInsightWindow(editor, insightWindow); insightWindow.SelectedItem = insightItems[defaultIndex]; } if (overloadIsSure) { IMethodOrProperty method = GetMethodFromInsightItem(insightItems[defaultIndex]); if (method != null && paramCount < method.Parameters.Count) { IParameter param = method.Parameters[paramCount]; ProvideContextCompletion(editor, param.ReturnType, charTyped); } } return(insightWindow); }
/// <summary> /// Resolves an object creation. /// </summary> /// <param name="type">Type of the object to create.</param> /// <param name="arguments"> /// Arguments passed to the constructor. /// The resolver may mutate this array to wrap elements in <see cref="CastExpression"/>s! /// </param> /// <param name="argumentNames"> /// The argument names. Pass the null string for positional arguments. /// </param> /// <param name="allowProtectedAccess"> /// Whether to allow calling protected constructors. /// This should be false except when resolving constructor initializers. /// </param> /// <param name="initializerStatements"> /// Statements for Objects/Collections initializer. /// <see cref="InvocationExpression.InitializerStatements"/> /// </param> /// <returns>InvocationResolveResult or ErrorResolveResult</returns> public static Expression ResolveObjectCreation(ResolveContext rc, Location l, IType type, Expression[] arguments, string[] argumentNames = null, bool allowProtectedAccess = false, IList <Expression> initializerStatements = null) { if (type.Kind == TypeKind.Delegate) { if (arguments == null || arguments.Length != 1) { rc.Report.Error(0, l, "Method name expected"); return(null); } Expression input = arguments[0]; IMethod invoke = input.Type.GetDelegateInvokeMethod(); if (invoke != null) { input = new MethodGroupExpression( input, invoke.Name, methods: new[] { new MethodListWithDeclaringType(input.Type) { invoke } }, typeArguments: EmptyList <IType> .Instance ); } return(rc.Convert(input, type)); } OverloadResolution or = rc.CreateOverloadResolution(arguments, argumentNames); MemberLookup lookup = rc.CreateMemberLookup(); List <IMethod> allApplicable = null; foreach (IMethod ctor in type.GetConstructors()) { if (lookup.IsAccessible(ctor, allowProtectedAccess)) { or.AddCandidate(ctor); } else { or.AddCandidate(ctor, OverloadResolutionErrors.Inaccessible); } } if (or.BestCandidate != null) { return(or.CreateInvocation(null, initializerStatements)); } else { rc.Report.Error(0, l, "The type `{0}' does not contain a constructor that takes `{1}' arguments", type.ToString(), arguments != null ? arguments.Length.ToString() : "0"); return(ErrorResult); } }
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); }
bool BaseTypeHasUsableParameterlessConstructor() { var memberLookup = new MemberLookup(currentType.GetDefinition(), ctx.Compilation.MainAssembly); OverloadResolution or = new OverloadResolution(ctx.Compilation, new ResolveResult[0]); foreach (var ctor in baseType.GetConstructors()) { if (memberLookup.IsAccessible(ctor, allowProtectedAccess: true)) { if (or.AddCandidate(ctor) == OverloadResolutionErrors.None) { return(true); } } } return(false); }
protected virtual void WritePositionalList(IList <ResolveResult> expressions, IAttribute attr) { bool needComma = false; int count = Emitter.Writers.Count; bool expanded = false; int paramsIndex = -1; if (attr.Constructor.Parameters.Any(p => p.IsParams)) { paramsIndex = attr.Constructor.Parameters.IndexOf(attr.Constructor.Parameters.FirstOrDefault(p => p.IsParams)); var or = new OverloadResolution(Emitter.Resolver.Compilation, expressions.ToArray()); or.AddCandidate(attr.Constructor); expanded = or.BestCandidateIsExpandedForm; } for (int i = 0; i < expressions.Count; i++) { var expr = expressions[i]; if (needComma) { WriteComma(); } needComma = true; if (expanded && paramsIndex == i) { WriteOpenBracket(); } WriteResolveResult(expr, this); if (Emitter.Writers.Count != count) { PopWriter(); count = Emitter.Writers.Count; } } if (expanded) { WriteCloseBracket(); } }
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); }
/// <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="CastExpression"/>s! /// </param> /// <param name="argumentNames"> /// The argument names. Pass the null string for positional arguments. /// </param> /// <returns>ArrayAccessResolveResult, InvocationResolveResult, or ErrorResolveResult</returns> public Expression ResolveIndexer(ResolveContext rc, Expression target, Expression[] arguments, string[] argumentNames = null) { switch (target.Type.Kind) { case TypeKind.Array: // �6.6.1 Array access if (argumentNames != null && argumentNames.Length > 0) { rc.Report.Error(0, Arguments.args.Where(x => x is NamedArgument).First().loc, "An element access expression cannot use named argument"); } return(new ArrayAccessExpression(((ElementTypeSpec)target.Type).ElementType, target, arguments)); case TypeKind.Pointer: // �.5.3 Pointer element access if (argumentNames != null && argumentNames.Length > 0) { rc.Report.Error(0, Arguments.args.Where(x => x is NamedArgument).First().loc, "An element access expression cannot use named argument"); } return(new PointerArithmeticExpression(((ElementTypeSpec)target.Type).ElementType, target, arguments)); } // �6.6.2 Indexer access MemberLookup lookup = rc.CreateMemberLookup(); var indexers = lookup.LookupIndexers(target); OverloadResolution or = rc.CreateOverloadResolution(arguments, argumentNames); or.AddMethodLists(indexers); if (or.BestCandidate != null) { return(or.CreateInvocation(target)); } else { rc.Report.Error(0, loc, "Cannot apply indexing with [] to an expression of type `{0}'", target.Type.ToString()); return(null); } }
public void BetterFunctionMemberIsNotTransitive() { var container = compilation.FindType(typeof(BetterFunctionMemberIsNotTransitiveTestCase)).GetDefinition(); var args = new ResolveResult[] { new MockLambda(compilation.FindType(KnownTypeCode.String)) { parameters = { new DefaultParameter(SpecialType.UnknownType, "arg") } } }; OverloadResolution r = new OverloadResolution(compilation, args); foreach (var method in container.GetMethods(m => m.Name == "Method")) { Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(method)); } Assert.AreEqual(container.GetMethods(m => m.Name == "Method").Last(), r.BestCandidate); }
Expression SetUserDefinedOperationInformations(ResolveContext rc, OverloadResolution r) {//TODO:Is It OK if (r.BestCandidateErrors != OverloadResolutionErrors.None) { rc.Report.Error(0, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'", OperName(Oper), Expr.Type.ToString()); return(r.CreateInvocation(null)); } IMethod method = (IMethod)r.BestCandidate; var operands = r.GetArgumentsWithConversions(); this.operatortype = ResolveContext.GetLinqNodeType(this.Oper, rc.checkForOverflow); this.isLiftedOperator = method is OverloadResolution.ILiftedOperator; this.ResolvedType = method.ReturnType; this.Expr = operands[0]; this.userDefinedOperatorMethod = method; _resolved = true; return(this); }
internal static object[] ConstructCallArguments(Symbols.Method TargetProcedure, object[] Arguments, BindingFlags LookupFlags) { ParameterInfo[] parameters = GetCallTarget(TargetProcedure, LookupFlags).GetParameters(); object[] matchedArguments = new object[(parameters.Length - 1) + 1]; int length = Arguments.Length; object argument = null; if (Symbols.HasFlag(LookupFlags, BindingFlags.SetProperty)) { object[] sourceArray = Arguments; Arguments = new object[(length - 2) + 1]; Array.Copy(sourceArray, Arguments, Arguments.Length); argument = sourceArray[length - 1]; } OverloadResolution.MatchArguments(TargetProcedure, Arguments, matchedArguments); if (Symbols.HasFlag(LookupFlags, BindingFlags.SetProperty)) { ParameterInfo parameter = parameters[parameters.Length - 1]; matchedArguments[parameters.Length - 1] = OverloadResolution.PassToParameter(argument, parameter, parameter.ParameterType); } return(matchedArguments); }
private static void InsertInOperatorListIfLessGenericThanExisting(Symbols.Method OperatorToInsert, List <Symbols.Method> OperatorList, ref bool GenericMembersExistInList) { if (Symbols.IsGeneric(OperatorToInsert.DeclaringType)) { GenericMembersExistInList = true; } if (GenericMembersExistInList) { for (int i = OperatorList.Count - 1; i >= 0; i += -1) { Symbols.Method left = OperatorList[i]; Symbols.Method method2 = OverloadResolution.LeastGenericProcedure(left, OperatorToInsert); if (method2 == left) { return; } if (method2 != null) { OperatorList.Remove(left); } } } OperatorList.Add(OperatorToInsert); }
public Expression ResolveUnaryOperator(ResolveContext rc, UnaryOperatorType op, Expression expression) { // V# 4.0 spec: §7.3.3 Unary operator overload resolution string overloadableOperatorName = GetOverloadableOperatorName(op); if (overloadableOperatorName == null) { switch (op) { case UnaryOperatorType.Dereference: PointerTypeSpec p = expression.Type as PointerTypeSpec; if (p != null) { return(SetOperationInformations(rc, p.ElementType, op, expression)); } else { return(ErrorResult); } case UnaryOperatorType.AddressOf: return(SetOperationInformations(rc, new PointerTypeSpec(expression.Type), op, expression)); default: return(ErrorExpression.UnknownError); } } // If the type is nullable, get the underlying type: IType type = NullableType.GetUnderlyingType(expression.Type); bool isNullable = NullableType.IsNullable(expression.Type); // the operator is overloadable: OverloadResolution userDefinedOperatorOR = rc.CreateOverloadResolution(new[] { expression }); foreach (var candidate in rc.GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) { userDefinedOperatorOR.AddCandidate(candidate); } if (userDefinedOperatorOR.FoundApplicableCandidate) { return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR)); } expression = UnaryNumericPromotion(rc, op, ref type, isNullable, expression); VSharpOperators.OperatorMethod[] methodGroup; VSharpOperators operators = VSharpOperators.Get(rc.compilation); switch (op) { case UnaryOperatorType.PreIncrement: case UnaryOperatorType.Decrement: case UnaryOperatorType.PostIncrement: case UnaryOperatorType.PostDecrement: // V# 4.0 spec: §7.6.9 Postfix increment and decrement operators // V# 4.0 spec: §7.7.5 Prefix increment and decrement operators TypeCode code = ReflectionHelper.GetTypeCode(type); if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer) { return(SetOperationInformations(rc, expression.Type, op, expression, isNullable)); } else { return(new ErrorExpression(expression.Type)); } case UnaryOperatorType.UnaryPlus: methodGroup = operators.UnaryPlusOperators; break; case UnaryOperatorType.UnaryNegation: methodGroup = rc.checkForOverflow ? operators.CheckedUnaryMinusOperators : operators.UncheckedUnaryMinusOperators; break; case UnaryOperatorType.LogicalNot: methodGroup = operators.LogicalNegationOperators; break; case UnaryOperatorType.OnesComplement: if (type.Kind == TypeKind.Enum) { if (expression.IsCompileTimeConstant && !isNullable && expression.ConstantValue != null) { // evaluate as (E)(~(U)x); var U = rc.compilation.FindType(expression.ConstantValue.GetType()); var unpackedEnum = Constant.CreateConstantFromValue(rc, U, expression.ConstantValue, loc); var rr = ResolveUnaryOperator(rc, op, unpackedEnum); ResolveContext ovfrc = rc.WithCheckForOverflow(false); rr = new CastExpression(type, rr).DoResolve(ovfrc); if (rr.IsCompileTimeConstant) { return(rr); } } return(SetOperationInformations(rc, expression.Type, op, expression, isNullable)); } else { methodGroup = operators.BitwiseComplementOperators; break; } default: throw new InvalidOperationException(); } OverloadResolution builtinOperatorOR = rc.CreateOverloadResolution(new[] { expression }); foreach (var candidate in methodGroup) { builtinOperatorOR.AddCandidate(candidate); } VSharpOperators.UnaryOperatorMethod m = (VSharpOperators.UnaryOperatorMethod)builtinOperatorOR.BestCandidate; IType resultType = m.ReturnType; if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) { if (userDefinedOperatorOR.BestCandidate != null) { // If there are any user-defined operators, prefer those over the built-in operators. // It'll be a more informative error. return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR)); } else if (builtinOperatorOR.BestCandidateAmbiguousWith != null) { // If the best candidate is ambiguous, just use the input type instead // of picking one of the ambiguous overloads. return(new ErrorExpression(expression.Type)); } else { return(new ErrorExpression(resultType)); } } else if (expression.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) { object val; try { val = m.Invoke(rc, expression.ConstantValue); } catch (ArithmeticException) { return(new ErrorExpression(resultType)); } return(Constant.CreateConstantFromValue(rc, resultType, val, loc)); } else { expression = rc.Convert(expression, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]); return(SetOperationInformations(rc, resultType, op, expression, builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator)); } }
public ConstraintValidatingSubstitution(IList <IType> classTypeArguments, IList <IType> methodTypeArguments, OverloadResolution overloadResolution) : base(classTypeArguments, methodTypeArguments) { this.conversions = overloadResolution.conversions; }
public void SetupDataProvider(string fileName, TextArea textArea) { FActiveTextArea = textArea; FMethods.Clear(); var document = textArea.Document; var csDoc = FEditor.TextDocument as CSDocument; var parseInfo = csDoc.ParseInfo; var finder = csDoc.ExpressionFinder; var compilationUnit = parseInfo.MostRecentCompilationUnit; var projectContent = compilationUnit.ProjectContent; var language = projectContent.Language; var expressionResult = finder.FindExpression(document.TextContent, FOffset); Debug.WriteLine(string.Format("Generating C# method insight data for expression: {0}", expressionResult)); var resolver = new NRefactoryResolver(language); var resolveResult = resolver.Resolve(expressionResult, parseInfo, csDoc.TextContent); if (resolveResult != null) { Debug.WriteLine(string.Format("Resolve result: {0}", resolveResult)); var methodGroupResolveResult = resolveResult as MethodGroupResolveResult; if (methodGroupResolveResult == null) { return; } bool classIsInInheritanceTree = false; var callingClass = methodGroupResolveResult.CallingClass; if (callingClass != null) { classIsInInheritanceTree = callingClass.IsTypeInInheritanceTree(methodGroupResolveResult.ContainingType.GetUnderlyingClass()); } foreach (var methodGroup in methodGroupResolveResult.Methods) { foreach (var method in methodGroup) { if (language.NameComparer.Equals(method.Name, methodGroupResolveResult.Name)) { if (method.IsAccessible(methodGroupResolveResult.CallingClass, classIsInInheritanceTree)) { FMethods.Add(method); } } } } // Set default index dependant on parameters. var arguments = new List <IReturnType>(); foreach (var commaOffset in FCommaOffsets) { var argumentExpression = finder.FindExpression(document.TextContent, commaOffset); var argResolveResult = resolver.Resolve(argumentExpression, parseInfo, document.TextContent); if (argResolveResult != null) { arguments.Add(argResolveResult.ResolvedType); Debug.WriteLine(string.Format("Parameter: {0}", argResolveResult)); } } bool overloadIsSure; var bestMatchingMethod = OverloadResolution.FindOverload(FMethods, arguments.ToArray(), true, false, out overloadIsSure); DefaultIndex = FMethods.IndexOf(bestMatchingMethod); } }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { target = expressionBuilder.Translate(inst.Arguments[0]); targetType = method.Parameters[0].Type; } else { target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); targetType = method.DeclaringType; } var lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); var result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); bool needsCast = true; if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); var expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = inst.OpCode }; needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } if (needsCast) { target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), mre) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }
/// <summary> /// Resolves an invocation. /// </summary> /// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param> /// <param name="arguments"> /// Arguments passed to the method. /// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s! /// </param> /// <param name="argumentNames"> /// The argument names. Pass the null string for positional arguments. /// </param> /// <returns>InvocationExpression</returns> private Expression ResolveInvocation(ResolveContext rc, Expression target, Expression[] arguments, string[] argumentNames, bool allowOptionalParameters) { // C# 4.0 spec: §7.6.5 MethodGroupExpression mgrr = target as MethodGroupExpression; if (mgrr != null) { OverloadResolution or = mgrr.PerformOverloadResolution(rc.compilation, arguments, argumentNames, checkForOverflow: rc.checkForOverflow, conversions: rc.conversions, allowOptionalParameters: allowOptionalParameters); if (or.BestCandidate != null) { var m = or.BestCandidate; if (arguments == null && m.Name == DestructorDeclaration.MetadataName) { rc.Report.Error(0, loc, "Destructors cannot be called directly. Consider calling IDisposable.Dispose if available"); } CheckSpecialMethod(rc, m); if (or.BestCandidate.IsStatic && !or.IsExtensionMethodInvocation && !(mgrr.TargetResult is TypeExpression)) { return(or.CreateInvocation(new TypeExpression(mgrr.TargetType), returnTypeOverride: null)); } else { return(or.CreateInvocation(mgrr.TargetResult, returnTypeOverride: null)); } } else { // No candidate found at all (not even an inapplicable one). // This can happen with empty method groups (as sometimes used with extension methods) rc.Report.Error(0, loc, "`{0}' does not contain a definition for `{1}'", mgrr.TargetType.ToString(), mgrr.MethodName); return(null); } } if (target == null && expr is SimpleName) { rc.Report.Error(0, loc, "`{0}' does not contain a definition for `{1}'", rc.CurrentTypeDefinition.ToString(), expr.GetSignatureForError()); return(null); } else if (target == null) { return(null); } IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); if (invokeMethod != null) { // is it a delegate ? if (target.Type.Kind != TypeKind.Delegate) { rc.Report.Error(0, loc, "Cannot invoke a non-delegate type `{0}'", target.Type.ToString()); return(null); } OverloadResolution or = rc.CreateOverloadResolution(arguments, argumentNames); or.AddCandidate(invokeMethod); return(new Invocation( target, invokeMethod, //invokeMethod.ReturnType.Resolve(context), or.GetArgumentsWithConversionsAndNames(), or.BestCandidateErrors, isExpandedForm: or.BestCandidateIsExpandedForm, isDelegateInvocation: true, argumentToParameterMap: or.GetArgumentToParameterMap(), returnTypeOverride: null)); } rc.Report.Error(0, loc, "The member `{0}' cannot be used as method or delegate", target.GetSignatureForError()); return(ErrorResult); }
TranslatedExpression HandleDelegateConstruction(CallInstruction inst) { ILInstruction func = inst.Arguments[1]; IMethod method; switch (func.OpCode) { case OpCode.LdFtn: method = ((LdFtn)func).Method; break; case OpCode.LdVirtFtn: method = ((LdVirtFtn)func).Method; break; default: throw new ArgumentException($"Unknown instruction type: {func.OpCode}"); } var invokeMethod = inst.Method.DeclaringType.GetDelegateInvokeMethod(); TranslatedExpression target; IType targetType; bool requireTarget; if (method.IsExtensionMethod && invokeMethod != null && method.Parameters.Count - 1 == invokeMethod.Parameters.Count) { targetType = method.Parameters[0].Type; target = expressionBuilder.Translate(inst.Arguments[0], targetType); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = true; } else { targetType = method.DeclaringType; target = expressionBuilder.TranslateTarget(method, inst.Arguments[0], func.OpCode == OpCode.LdFtn); target = ExpressionBuilder.UnwrapBoxingConversion(target); requireTarget = expressionBuilder.HidesVariableWithName(method.Name) || (method.IsStatic ? !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition) : !(target.Expression is ThisReferenceExpression)); } var expectedTargetDetails = new ExpectedTargetDetails { CallOpCode = inst.OpCode }; bool needsCast = false; ResolveResult result = null; var or = new OverloadResolution(resolver.Compilation, method.Parameters.SelectArray(p => new TypeResolveResult(p.Type))); if (!requireTarget) { result = resolver.ResolveSimpleName(method.Name, method.TypeArguments, isInvocationTarget: false); if (result is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); requireTarget = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } else { requireTarget = true; } } MemberLookup lookup = null; if (requireTarget) { lookup = new MemberLookup(resolver.CurrentTypeDefinition, resolver.CurrentTypeDefinition.ParentAssembly); var rr = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); needsCast = true; result = rr; if (rr is MethodGroupResolveResult mgrr) { or.AddMethodLists(mgrr.MethodsGroupedByDeclaringType.ToArray()); needsCast = (or.BestCandidateErrors != OverloadResolutionErrors.None || !IsAppropriateCallTarget(expectedTargetDetails, method, or.BestCandidate)); } } if (needsCast) { Debug.Assert(requireTarget); target = target.ConvertTo(targetType, expressionBuilder); result = lookup.Lookup(target.ResolveResult, method.Name, method.TypeArguments, false); } Expression targetExpression; if (requireTarget) { var mre = new MemberReferenceExpression(target, method.Name); mre.TypeArguments.AddRange(method.TypeArguments.Select(expressionBuilder.ConvertType)); mre.WithRR(result); targetExpression = mre; } else { var ide = new IdentifierExpression(method.Name) .WithRR(result); targetExpression = ide; } var oce = new ObjectCreateExpression(expressionBuilder.ConvertType(inst.Method.DeclaringType), targetExpression) .WithILInstruction(inst) .WithRR(new ConversionResolveResult( inst.Method.DeclaringType, new MemberResolveResult(target.ResolveResult, method), Conversion.MethodGroupConversion(method, func.OpCode == OpCode.LdVirtFtn, false))); return(oce); }
internal static Symbols.Method ResolveCall(Symbols.Container BaseReference, string MethodName, MemberInfo[] Members, object[] Arguments, string[] ArgumentNames, Type[] TypeArguments, BindingFlags LookupFlags, bool ReportErrors, ref OverloadResolution.ResolutionFailure Failure) { Failure = OverloadResolution.ResolutionFailure.None; if ((Members[0].MemberType != MemberTypes.Method) && (Members[0].MemberType != MemberTypes.Property)) { Failure = OverloadResolution.ResolutionFailure.InvalidTarget; if (ReportErrors) { throw new ArgumentException(Utils.GetResourceString("ExpressionNotProcedure", new string[] { MethodName, BaseReference.VBFriendlyName })); } return(null); } int length = Arguments.Length; object argument = null; if (Symbols.HasFlag(LookupFlags, BindingFlags.SetProperty)) { if (Arguments.Length == 0) { Failure = OverloadResolution.ResolutionFailure.InvalidArgument; if (ReportErrors) { throw new InvalidCastException(Utils.GetResourceString("PropertySetMissingArgument1", new string[] { MethodName })); } return(null); } object[] sourceArray = Arguments; Arguments = new object[(length - 2) + 1]; Array.Copy(sourceArray, Arguments, Arguments.Length); argument = sourceArray[length - 1]; } Symbols.Method targetProcedure = OverloadResolution.ResolveOverloadedCall(MethodName, Members, Arguments, ArgumentNames, TypeArguments, LookupFlags, ReportErrors, ref Failure); if (Failure != OverloadResolution.ResolutionFailure.None) { return(null); } if (!targetProcedure.ArgumentsValidated && !OverloadResolution.CanMatchArguments(targetProcedure, Arguments, ArgumentNames, TypeArguments, false, null)) { Failure = OverloadResolution.ResolutionFailure.InvalidArgument; if (!ReportErrors) { return(null); } string str = ""; List <string> list = new List <string>(); bool flag = OverloadResolution.CanMatchArguments(targetProcedure, Arguments, ArgumentNames, TypeArguments, false, list); foreach (string str2 in list) { str = str + "\r\n " + str2; } throw new InvalidCastException(Utils.GetResourceString("MatchArgumentFailure2", new string[] { targetProcedure.ToString(), str })); } if (targetProcedure.IsProperty) { if (MatchesPropertyRequirements(targetProcedure, LookupFlags) == null) { Failure = OverloadResolution.ResolutionFailure.InvalidTarget; if (ReportErrors) { throw ReportPropertyMismatch(targetProcedure, LookupFlags); } return(null); } } else if (Symbols.HasFlag(LookupFlags, BindingFlags.SetProperty)) { Failure = OverloadResolution.ResolutionFailure.InvalidTarget; if (ReportErrors) { throw new MissingMemberException(Utils.GetResourceString("MethodAssignment1", new string[] { targetProcedure.AsMethod().Name })); } return(null); } if (!Symbols.HasFlag(LookupFlags, BindingFlags.SetProperty)) { return(targetProcedure); } ParameterInfo[] parameters = GetCallTarget(targetProcedure, LookupFlags).GetParameters(); ParameterInfo parameter = parameters[parameters.Length - 1]; bool requiresNarrowingConversion = false; bool allNarrowingIsFromObject = false; if (OverloadResolution.CanPassToParameter(targetProcedure, argument, parameter, false, false, null, ref requiresNarrowingConversion, ref allNarrowingIsFromObject)) { return(targetProcedure); } Failure = OverloadResolution.ResolutionFailure.InvalidArgument; if (!ReportErrors) { return(null); } string str3 = ""; List <string> errors = new List <string>(); allNarrowingIsFromObject = false; requiresNarrowingConversion = false; bool flag2 = OverloadResolution.CanPassToParameter(targetProcedure, argument, parameter, false, false, errors, ref allNarrowingIsFromObject, ref requiresNarrowingConversion); foreach (string str4 in errors) { str3 = str3 + "\r\n " + str4; } throw new InvalidCastException(Utils.GetResourceString("MatchArgumentFailure2", new string[] { targetProcedure.ToString(), str3 })); }
OverloadResolution CreateOverloadResolution(ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null) { var or = new OverloadResolution(compilation, arguments, argumentNames, typeArguments, conversions); or.CheckForOverflow = checkForOverflow; return or; }
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()); }