Expression UnaryNumericPromotion(ResolveContext rc, UnaryOperatorType op, ref IType type, bool isNullable, Expression expression) { // V# 4.0 spec: §7.3.6.1 TypeCode code = ReflectionHelper.GetTypeCode(type); if (isNullable && type.Kind == TypeKind.Null) { code = TypeCode.SByte; // cause promotion of null to int32 } switch (op) { case UnaryOperatorType.UnaryNegation: if (code == TypeCode.UInt32) { type = rc.compilation.FindType(KnownTypeCode.Int64); return(rc.Convert(expression, MakeNullable(rc, type, isNullable), isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion)); } goto case UnaryOperatorType.UnaryPlus; case UnaryOperatorType.UnaryPlus: case UnaryOperatorType.OnesComplement: if (code >= TypeCode.Char && code <= TypeCode.UInt16) { type = rc.compilation.FindType(KnownTypeCode.Int32); return(rc.Convert(expression, MakeNullable(rc, type, isNullable), isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion)); } break; } return(expression); }
// // Converts `source' to an int, uint, long or ulong. // protected Expression ConvertExpressionToArrayIndex(ResolveContext ec, Expression source, bool pointerArray = false) { Expression converted; using (ec.Set(ResolveContext.Options.CheckedScope)) { converted = ec.Convert(source, KnownTypeReference.Int32.Resolve(ec)); if (converted == null) { converted = ec.Convert(source, KnownTypeReference.UInt32.Resolve(ec)); } if (converted == null) { converted = ec.Convert(source, KnownTypeReference.Int64.Resolve(ec)); } if (converted == null) { converted = ec.Convert(source, KnownTypeReference.UInt64.Resolve(ec)); } if (converted == null) { ec.Report.Error(0, loc, "Cannot convert type `{0}' to `{1}'", source.Type.ToString(), KnownTypeReference.Int32.ToString()); return(null); } } if (pointerArray) { return(converted); } // // Only positive constants are allowed at compile time // Constant c = converted as Constant; if (c != null && c.IsNegative) { ec.Report.Error(0, source.Location, "Cannot create an array with a negative size"); } // No conversion needed to array index if (converted.Type.IsKnownType(KnownTypeCode.Int32)) { return(converted); } return(new CastExpression(KnownTypeReference.Int32.Resolve(ec), converted).DoResolve(ec)); }
Expression CastTo(ResolveContext rc, TypeCode targetType, bool isNullable, Expression expression, bool allowNullableConstants) { IType elementType = rc.compilation.FindType(targetType); IType nullableType = MakeNullable(rc, elementType, isNullable); if (nullableType.Equals(expression.Type)) { return(expression); } if (allowNullableConstants && expression.IsCompileTimeConstant) { if (expression.ConstantValue == null) { return(Constant.CreateConstantFromValue(rc, nullableType, null, loc)); } Expression rr = new CastExpression(elementType, expression).DoResolve(rc); if (rr.IsError) { return(rr); } Debug.Assert(rr.IsCompileTimeConstant); return(Constant.CreateConstantFromValue(rc, nullableType, rr.ConstantValue, loc)); } else { return(rc.Convert(expression, nullableType, isNullable ? Conversion.ImplicitNullableConversion : Conversion.ImplicitNumericConversion)); } }
// // Converts static initializer only // void UnifyInitializerElement(ResolveContext ec) { for (int i = 0; i < array_data.Count; ++i) { Expression e = array_data[i]; if (e != null) { array_data[i] = ec.Convert(e, array_element_type); } } }
/// <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); } }
void AdjustArrayAccessArguments(ResolveContext rc, Expression[] arguments) { for (int i = 0; i < arguments.Length; i++) { if (!(rc.TryConvert(ref arguments[i], rc.compilation.FindType(KnownTypeCode.Int32)) || rc.TryConvert(ref arguments[i], rc.compilation.FindType(KnownTypeCode.UInt32)) || rc.TryConvert(ref arguments[i], rc.compilation.FindType(KnownTypeCode.Int64)) || rc.TryConvert(ref arguments[i], rc.compilation.FindType(KnownTypeCode.UInt64)))) { // conversion failed arguments[i] = rc.Convert(arguments[i], rc.compilation.FindType(KnownTypeCode.Int32), Conversion.None); } } }
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 Expression ResolveBinaryOperator(ResolveContext rc, BinaryOperatorType op, Expression lhs, Expression rhs) { // V# 4.0 spec: §7.3.4 Binary operator overload resolution string overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(op); if (overloadableOperatorName == null) { // Handle logical and/or exactly as bitwise and/or: // - If the user overloads a bitwise operator, that implicitly creates the corresponding logical operator. // - If both inputs are compile-time constants, it doesn't matter that we don't short-circuit. // - If inputs aren't compile-time constants, we don't evaluate anything, so again it doesn't matter that we don't short-circuit if (op == BinaryOperatorType.LogicalAnd) { overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(BinaryOperatorType.BitwiseAnd); } else if (op == BinaryOperatorType.LogicalOr) { overloadableOperatorName = ResolveContext.GetOverloadableOperatorName(BinaryOperatorType.BitwiseOr); } else if (op == BinaryOperatorType.NullCoalescing) { // null coalescing operator is not overloadable and needs to be handled separately return(ResolveNullCoalescingOperator(rc, lhs, rhs)); } else { return(ErrorExpression.UnknownError); } } // If the type is nullable, get the underlying type: bool isNullable = NullableType.IsNullable(lhs.Type) || NullableType.IsNullable(rhs.Type); IType lhsType = NullableType.GetUnderlyingType(lhs.Type); IType rhsType = NullableType.GetUnderlyingType(rhs.Type); // the operator is overloadable: OverloadResolution userDefinedOperatorOR = rc.CreateOverloadResolution(new[] { lhs, rhs }); HashSet <IParameterizedMember> userOperatorCandidates = new HashSet <IParameterizedMember>(); userOperatorCandidates.UnionWith(rc.GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName)); userOperatorCandidates.UnionWith(rc.GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName)); foreach (var candidate in userOperatorCandidates) { userDefinedOperatorOR.AddCandidate(candidate); } if (userDefinedOperatorOR.FoundApplicableCandidate) { return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR)); } if (lhsType.Kind == TypeKind.Null && rhsType.IsReferenceType == false || lhsType.IsReferenceType == false && rhsType.Kind == TypeKind.Null) { isNullable = true; } if (op == BinaryOperatorType.LeftShift || op == BinaryOperatorType.RightShift) { // special case: the shift operators allow "var x = null << null", producing int?. if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) { isNullable = true; } // for shift operators, do unary promotion independently on both arguments lhs = UnaryNumericPromotion(rc, UnaryOperatorType.UnaryPlus, ref lhsType, isNullable, lhs); rhs = UnaryNumericPromotion(rc, UnaryOperatorType.UnaryPlus, ref rhsType, isNullable, rhs); } else { bool allowNullableConstants = op == BinaryOperatorType.Equality || op == BinaryOperatorType.Inequality; if (!BinaryNumericPromotion(rc, isNullable, ref lhs, ref rhs, allowNullableConstants)) { return(new ErrorExpression(lhs.Type)); } } // re-read underlying types after numeric promotion lhsType = NullableType.GetUnderlyingType(lhs.Type); rhsType = NullableType.GetUnderlyingType(rhs.Type); IEnumerable <VSharpOperators.OperatorMethod> methodGroup; VSharpOperators operators = VSharpOperators.Get(rc.compilation); switch (op) { case BinaryOperatorType.Multiply: methodGroup = operators.MultiplicationOperators; break; case BinaryOperatorType.Division: methodGroup = operators.DivisionOperators; break; case BinaryOperatorType.Modulus: methodGroup = operators.RemainderOperators; break; case BinaryOperatorType.Addition: methodGroup = operators.AdditionOperators; { if (lhsType.Kind == TypeKind.Enum) { // E operator +(E x, U y); IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(lhsType), isNullable); if (rc.TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs)) { return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs)); } } if (rhsType.Kind == TypeKind.Enum) { // E operator +(U x, E y); IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(rhsType), isNullable); if (rc.TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs)) { return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs)); } } if (lhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref rhs, lhsType)) { return(SetOperationInformations(rc, lhsType, lhs, op, rhs)); } else if (rhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref lhs, rhsType)) { return(SetOperationInformations(rc, rhsType, lhs, op, rhs)); } if (lhsType is PointerTypeSpec) { methodGroup = new[] { PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int32), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt32), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int64), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt64) }; } else if (rhsType is PointerTypeSpec) { methodGroup = new[] { PointerArithmeticOperator(rc, rhsType, KnownTypeCode.Int32, rhsType), PointerArithmeticOperator(rc, rhsType, KnownTypeCode.UInt32, rhsType), PointerArithmeticOperator(rc, rhsType, KnownTypeCode.Int64, rhsType), PointerArithmeticOperator(rc, rhsType, KnownTypeCode.UInt64, rhsType) }; } if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) { return(new ErrorExpression(SpecialTypeSpec.NullType)); } } break; case BinaryOperatorType.Subtraction: methodGroup = operators.SubtractionOperators; { if (lhsType.Kind == TypeKind.Enum) { // U operator –(E x, E y); if (rc.TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs, allowConversionFromConstantZero: false)) { return(HandleEnumSubtraction(rc, isNullable, lhsType, lhs, rhs)); } // E operator –(E x, U y); IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(lhsType), isNullable); if (rc.TryConvertEnum(ref rhs, underlyingType, ref isNullable, ref lhs)) { return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs)); } } if (rhsType.Kind == TypeKind.Enum) { // U operator –(E x, E y); if (rc.TryConvertEnum(ref lhs, rhs.Type, ref isNullable, ref rhs, allowConversionFromConstantZero: false)) { return(HandleEnumSubtraction(rc, isNullable, rhsType, lhs, rhs)); } // E operator -(U x, E y); IType underlyingType = MakeNullable(rc, ResolveContext.GetEnumUnderlyingType(rhsType), isNullable); if (rc.TryConvertEnum(ref lhs, underlyingType, ref isNullable, ref rhs)) { return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs)); } } if (lhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref rhs, lhsType)) { return(SetOperationInformations(rc, lhsType, lhs, op, rhs)); } else if (rhsType.Kind == TypeKind.Delegate && rc.TryConvert(ref lhs, rhsType)) { return(SetOperationInformations(rc, rhsType, lhs, op, rhs)); } if (lhsType is PointerTypeSpec) { if (rhsType is PointerTypeSpec) { IType int64 = rc.compilation.FindType(KnownTypeCode.Int64); if (lhsType.Equals(rhsType)) { return(SetOperationInformations(rc, int64, lhs, op, rhs)); } else { return(new ErrorExpression(int64)); } } methodGroup = new[] { PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int32), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt32), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.Int64), PointerArithmeticOperator(rc, lhsType, lhsType, KnownTypeCode.UInt64) }; } if (lhsType.Kind == TypeKind.Null && rhsType.Kind == TypeKind.Null) { return(new ErrorExpression(SpecialTypeSpec.NullType)); } } break; case BinaryOperatorType.LeftShift: methodGroup = operators.ShiftLeftOperators; break; case BinaryOperatorType.RightShift: methodGroup = operators.ShiftRightOperators; break; case BinaryOperatorType.RotateRight: methodGroup = operators.RotateRightOperators; break; case BinaryOperatorType.RotateLeft: methodGroup = operators.RotateLeftOperators; break; case BinaryOperatorType.Equality: case BinaryOperatorType.Inequality: case BinaryOperatorType.LessThan: case BinaryOperatorType.GreaterThan: case BinaryOperatorType.LessThanOrEqual: case BinaryOperatorType.GreaterThanOrEqual: { if (lhsType.Kind == TypeKind.Enum && rc.TryConvert(ref rhs, lhs.Type)) { // bool operator op(E x, E y); return(HandleEnumComparison(rc, op, lhsType, isNullable, lhs, rhs)); } else if (rhsType.Kind == TypeKind.Enum && rc.TryConvert(ref lhs, rhs.Type)) { // bool operator op(E x, E y); return(HandleEnumComparison(rc, op, rhsType, isNullable, lhs, rhs)); } else if (lhsType is PointerTypeSpec && rhsType is PointerTypeSpec) { return(SetOperationInformations(rc, rc.compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs)); } if (op == BinaryOperatorType.Equality || op == BinaryOperatorType.Inequality) { if (lhsType.IsReferenceType == true && rhsType.IsReferenceType == true) { // If it's a reference comparison if (op == BinaryOperatorType.Equality) { methodGroup = operators.ReferenceEqualityOperators; } else { methodGroup = operators.ReferenceInequalityOperators; } break; } else if (lhsType.Kind == TypeKind.Null && IsNullableTypeOrNonValueType(rhs.Type) || IsNullableTypeOrNonValueType(lhs.Type) && rhsType.Kind == TypeKind.Null) { // compare type parameter or nullable type with the null literal return(SetOperationInformations(rc, rc.compilation.FindType(KnownTypeCode.Boolean), lhs, op, rhs)); } } switch (op) { case BinaryOperatorType.Equality: methodGroup = operators.ValueEqualityOperators; break; case BinaryOperatorType.Inequality: methodGroup = operators.ValueInequalityOperators; break; case BinaryOperatorType.LessThan: methodGroup = operators.LessThanOperators; break; case BinaryOperatorType.GreaterThan: methodGroup = operators.GreaterThanOperators; break; case BinaryOperatorType.LessThanOrEqual: methodGroup = operators.LessThanOrEqualOperators; break; case BinaryOperatorType.GreaterThanOrEqual: methodGroup = operators.GreaterThanOrEqualOperators; break; default: throw new InvalidOperationException(); } } break; case BinaryOperatorType.BitwiseAnd: case BinaryOperatorType.BitwiseOr: case BinaryOperatorType.ExclusiveOr: { if (lhsType.Kind == TypeKind.Enum) { // bool operator op(E x, E y); if (rc.TryConvertEnum(ref rhs, lhs.Type, ref isNullable, ref lhs)) { return(HandleEnumOperator(rc, isNullable, lhsType, op, lhs, rhs)); } } if (rhsType.Kind == TypeKind.Enum) { // bool operator op(E x, E y); if (rc.TryConvertEnum(ref lhs, rhs.Type, ref isNullable, ref rhs)) { return(HandleEnumOperator(rc, isNullable, rhsType, op, lhs, rhs)); } } switch (op) { case BinaryOperatorType.BitwiseAnd: methodGroup = operators.BitwiseAndOperators; break; case BinaryOperatorType.BitwiseOr: methodGroup = operators.BitwiseOrOperators; break; case BinaryOperatorType.ExclusiveOr: methodGroup = operators.BitwiseXorOperators; break; default: throw new InvalidOperationException(); } } break; case BinaryOperatorType.LogicalAnd: methodGroup = operators.LogicalAndOperators; break; case BinaryOperatorType.LogicalOr: methodGroup = operators.LogicalOrOperators; break; default: throw new InvalidOperationException(); } OverloadResolution builtinOperatorOR = rc.CreateOverloadResolution(new[] { lhs, rhs }); foreach (var candidate in methodGroup) { builtinOperatorOR.AddCandidate(candidate); } VSharpOperators.BinaryOperatorMethod m = (VSharpOperators.BinaryOperatorMethod)builtinOperatorOR.BestCandidate; IType resultType = m.ReturnType; if (builtinOperatorOR.BestCandidateErrors != OverloadResolutionErrors.None) { // If there are any user-defined operators, prefer those over the built-in operators. // It'll be a more informative error. if (userDefinedOperatorOR.BestCandidate != null) { return(SetUserDefinedOperationInformations(rc, userDefinedOperatorOR)); } else { return(new ErrorExpression(resultType)); } } else if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && m.CanEvaluateAtCompileTime) { object val; try { val = m.Invoke(rc, lhs.ConstantValue, rhs.ConstantValue); } catch (ArithmeticException) { return(new ErrorExpression(resultType)); } return(Constant.CreateConstantFromValue(rc, resultType, val, loc)); } else { lhs = rc.Convert(lhs, m.Parameters[0].Type, builtinOperatorOR.ArgumentConversions[0]); rhs = rc.Convert(rhs, m.Parameters[1].Type, builtinOperatorOR.ArgumentConversions[1]); return(SetOperationInformations(rc, resultType, lhs, op, rhs, builtinOperatorOR.BestCandidate is OverloadResolution.ILiftedOperator)); } }