Esempio n. 1
0
		public ResolveResult ResolveBinaryOperator(BinaryOperatorType op, ResolveResult lhs, ResolveResult rhs)
		{
			if (lhs.Type.Kind == TypeKind.Dynamic || rhs.Type.Kind == TypeKind.Dynamic) {
				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, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
			}
			
			if (lhsType.Kind == TypeKind.Null && rhsType.IsReferenceType == false
			    || lhsType.IsReferenceType == false && rhsType.Kind == TypeKind.Null)
			{
				isNullable = true;
			}
			if (op == BinaryOperatorType.ShiftLeft || op == BinaryOperatorType.ShiftRight) {
				// special case: the shift operators allow "var x = null << null", producing int?.
				if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
					isNullable = true;
				// for shift operators, do unary promotion independently on both arguments
				lhs = UnaryNumericPromotion(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<CppOperators.OperatorMethod> methodGroup;
			CppOperators operators = CppOperators.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 (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
							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 (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null)
							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);
						}
						if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.InEquality) {
							if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true) {
								// If it's a reference comparison
								if (op == BinaryOperatorType.Equality)
									methodGroup = operators.ReferenceEqualityOperators;
								else
									methodGroup = operators.ReferenceInequalityOperators;
								break;
							} else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type)
							           || IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null) {
								// compare type parameter or nullable type with the null literal
								return BinaryOperatorResolveResult(compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs);
							}
						}
						switch (op) {
							case BinaryOperatorType.Equality:
								methodGroup = operators.ValueEqualityOperators;
								break;
							case BinaryOperatorType.InEquality:
								methodGroup = operators.ValueInequalityOperators;
								break;
							case BinaryOperatorType.LessThan:
								methodGroup = operators.LessThanOperators;
								break;
							case BinaryOperatorType.GreaterThan:
								methodGroup = operators.GreaterThanOperators;
								break;
							case BinaryOperatorType.LessThanOrEqual:
								methodGroup = operators.LessThanOrEqualOperators;
								break;
							case BinaryOperatorType.GreaterThanOrEqual:
								methodGroup = operators.GreaterThanOrEqualOperators;
								break;
							default:
								throw new InvalidOperationException();
						}
					}
					break;
				case BinaryOperatorType.BitwiseAnd:
				case BinaryOperatorType.BitwiseOr:
				case BinaryOperatorType.ExclusiveOr:
					{
						if (lhsType.Kind == TypeKind.Enum && 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);
			}
			CppOperators.BinaryOperatorMethod m = (CppOperators.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, BinaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
				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);
			}
		}
Esempio n. 2
0
		/// <summary>
		/// Resolves an object creation.
		/// </summary>
		/// <param name="type">Type of the object to create.</param>
		/// <param name="arguments">
		/// Arguments passed to the constructor.
		/// The resolver may mutate this array to wrap elements in <see cref="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);
			}
		}
Esempio n. 3
0
		public ResolveResult ResolveUnaryOperator(UnaryOperatorType op, ResolveResult expression)
		{
			if (expression.Type.Kind == TypeKind.Dynamic)
				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, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
			}
			
			expression = UnaryNumericPromotion(op, ref type, isNullable, expression);
			CppOperators.OperatorMethod[] methodGroup;
			CppOperators operators = CppOperators.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.Char && 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 && expression.ConstantValue != null) {
							// 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);
			}
			CppOperators.UnaryOperatorMethod m = (CppOperators.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 CreateResolveResultForUserDefinedOperator(userDefinedOperatorOR, UnaryOperatorExpression.GetLinqNodeType(op, this.CheckForOverflow));
				} 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 ErrorResolveResult(expression.Type);
				} 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);
			}
		}
Esempio n. 4
0
		/// <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;
			}
		}
Esempio n. 5
0
		/// <summary>
		/// Resolves an invocation.
		/// </summary>
		/// <param name="target">The target of the invocation. Usually a MethodGroupResolveResult.</param>
		/// <param name="arguments">
		/// Arguments passed to the method.
		/// The resolver may mutate this array to wrap elements in <see cref="ConversionResolveResult"/>s!
		/// </param>
		/// <param name="argumentNames">
		/// The argument names. Pass the null string for positional arguments.
		/// </param>
		/// <returns>InvocationResolveResult or UnknownMethodResolveResult</returns>
		public ResolveResult ResolveInvocation(ResolveResult target, ResolveResult[] arguments, string[] argumentNames = null)
		{
			// C# 4.0 spec: §7.6.5
			
			if (target.Type.Kind == TypeKind.Dynamic)
				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 CppInvocationResolveResult(
					target, invokeMethod, //invokeMethod.ReturnType.Resolve(context),
					or.GetArgumentsWithConversions(), or.BestCandidateErrors,
					isExpandedForm: or.BestCandidateIsExpandedForm,
					isDelegateInvocation: true,
					argumentToParameterMap: or.GetArgumentToParameterMap());
			}
			return ErrorResult;
		}
Esempio n. 6
0
		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());
		}
Esempio n. 7
0
        public OverloadResolution PerformOverloadResolution(ICompilation compilation, 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(compilation, 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.Any())
                {
                    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(compilation, 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);
        }
			public ConstraintValidatingSubstitution(IList<IType> classTypeArguments, IList<IType> methodTypeArguments, OverloadResolution overloadResolution)
				: base(classTypeArguments, methodTypeArguments)
			{
				this.conversions = overloadResolution.conversions;
			}