/// <summary> /// Handle the case where an enum value is compared with another enum value /// bool operator op(E x, E y); /// </summary> Expression HandleEnumComparison(ResolveContext rc, BinaryOperatorType op, IType enumType, bool isNullable, Expression lhs, Expression rhs) { // evaluate as ((U)x op (U)y) IType elementType = ResolveContext.GetEnumUnderlyingType(enumType); if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable && elementType.Kind != TypeKind.Enum) { var rr = ResolveBinaryOperator(rc, op, new CastExpression(elementType, lhs).DoResolve(rc), new CastExpression(elementType, rhs).DoResolve(rc)); if (rr.IsCompileTimeConstant) { return(rr); } } IType resultType = rc.compilation.FindType(KnownTypeCode.Boolean); return(SetOperationInformations(rc, resultType, lhs, op, rhs, isNullable)); }
/// <summary> /// Handle the case where an enum value is subtracted from another enum value /// U operator –(E x, E y); /// </summary> Expression HandleEnumSubtraction(ResolveContext rc, bool isNullable, IType enumType, Expression lhs, Expression rhs) { // evaluate as (U)((U)x – (U)y) IType elementType = ResolveContext.GetEnumUnderlyingType(enumType); if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable && elementType.Kind != TypeKind.Enum) { var rr = ResolveBinaryOperator(rc, BinaryOperatorType.Subtraction, new CastExpression(elementType, lhs).DoResolve(rc), new CastExpression(elementType, rhs).DoResolve(rc)); rr = new CastExpression(elementType, rr).DoResolve(rc.WithCheckForOverflow(false)); if (rr.IsCompileTimeConstant) { return(rr); } } IType resultType = MakeNullable(rc, elementType, isNullable); return(SetOperationInformations(rc, resultType, lhs, BinaryOperatorType.Subtraction, rhs, isNullable)); }
/// <summary> /// Handle the following enum operators: /// E operator +(E x, U y); /// E operator +(U x, E y); /// E operator –(E x, U y); /// E operator &(E x, E y); /// E operator |(E x, E y); /// E operator ^(E x, E y); /// </summary> Expression HandleEnumOperator(ResolveContext rc, bool isNullable, IType enumType, BinaryOperatorType op, Expression lhs, Expression rhs) { // evaluate as (E)((U)x op (U)y) if (lhs.IsCompileTimeConstant && rhs.IsCompileTimeConstant && !isNullable) { IType elementType = ResolveContext.GetEnumUnderlyingType(enumType); if (elementType.Kind != TypeKind.Enum) { var rr = ResolveBinaryOperator(rc, op, new CastExpression(elementType, lhs).DoResolve(rc), new CastExpression(elementType, rhs).DoResolve(rc)); rr = new CastExpression(enumType, rr).DoResolve(rc.WithCheckForOverflow(false)); if (rr.IsCompileTimeConstant) // only report result if it's a constant; use the regular OperatorResolveResult codepath otherwise { return(rr); } } } IType resultType = MakeNullable(rc, enumType, isNullable); return(SetOperationInformations(rc, resultType, lhs, op, rhs, isNullable)); }
public override Expression DoResolve(ResolveContext rc) { referencedType = (texpr as ITypeReference).Resolve(rc); if (referencedType == null) { return(null); } if (referencedType.Kind == TypeKind.Enum) { referencedType = ResolveContext.GetEnumUnderlyingType(referencedType); } int size_of = ResolveSizeOfBuiltin(rc, referencedType); if (size_of > 0) { return(new IntConstant(size_of, loc).DoResolve(rc)); } _resolved = true; eclass = ExprClass.Value; return(this); }
public override Expression DoResolve(ResolveContext rc) { if (_resolved) { return(this); } expr = expr.DoResolve(rc); if (expr == null) { return(null); } eclass = ExprClass.Value; if (ResolvedType == null) { ResolvedType = target_type.ResolveAsType(rc); if (ResolvedType == null) { return(null); } } if (rc.IsStaticType(ResolvedType)) { rc.Report.Error(246, loc, "Cannot convert to static type `{0}'", ResolvedType.ToString()); return(null); } // V# 4.0 spec: §7.7.6 Cast expressions Conversion c = rc.conversions.ExplicitConversion(expr, ResolvedType); if (!c.IsValid) { rc.Report.Error(196, Location, "Cannot convert source type `{0}' to target type `{1}'", expr.Type.ToString(), ResolvedType.ToString()); return(ErrorResult); } if (expr.IsCompileTimeConstant && !c.IsUserDefined) { TypeCode code = ReflectionHelper.GetTypeCode(ResolvedType); if (code >= TypeCode.Boolean && code <= TypeCode.Decimal && expr.ConstantValue != null) { try { return(Constant.CreateConstantFromValue(rc, ResolvedType, rc.VSharpPrimitiveCast(code, expr.ConstantValue), loc)); } catch (OverflowException) { return(new ErrorExpression(ResolvedType, loc)); } catch (InvalidCastException) { return(new ErrorExpression(ResolvedType, loc)); } } else if (code == TypeCode.String) { if (expr.ConstantValue == null || expr.ConstantValue is string) { return(Constant.CreateConstantFromValue(rc, ResolvedType, expr.ConstantValue, loc)); } else { return(new ErrorExpression(ResolvedType, loc)); } } else if (ResolvedType.Kind == TypeKind.Enum) { code = ReflectionHelper.GetTypeCode(ResolveContext.GetEnumUnderlyingType(ResolvedType)); if (code >= TypeCode.SByte && code <= TypeCode.UInt64 && expr.ConstantValue != null) { try { return(Constant.CreateConstantFromValue(rc, ResolvedType, rc.VSharpPrimitiveCast(code, expr.ConstantValue), loc)); } catch (OverflowException) { return(new ErrorExpression(ResolvedType, loc)); } catch (InvalidCastException) { return(new ErrorExpression(ResolvedType, loc)); } } } } return(new CastExpression(ResolvedType, expr, c, rc.checkForOverflow)); }
public override Expression DoResolve(ResolveContext rc) { if (_resolved) { return(this); } expr = expr.DoResolve(rc); if (expr == null) { return(null); } eclass = ExprClass.Value; if (ResolvedType == null) { ResolvedType = target_type.ResolveAsType(rc); if (ResolvedType == null) { return(null); } } if (rc.IsStaticType(ResolvedType)) { rc.Report.Error(246, loc, "Cannot convert to static type `{0}'", ResolvedType.ToString()); return(null); } Conversion c = rc.conversions.ExplicitConversion(expr, ResolvedType); if (c.IsValid) { var cv = rc.conversions.ImplicitConversion(expr, rc.CurrentTypeDefinition.EnumUnderlyingType); if (!cv.IsValid) { rc.Report.Error(0, loc, "Cannot implicitly convert type `{0}' to enum underlying `{1}'. An explicit conversion exists (are you missing a cast?)", expr.Type.ToString(), ResolvedType.ToString()); return(ErrorResult); } } if (!c.IsValid && !c.IsNumericConversion) { c = rc.conversions.ExplicitConversion(expr, ResolvedType); if (c.IsValid) { rc.Report.Error(0, loc, "Cannot implicitly convert type `{0}' to enum underlying `{1}'. An explicit conversion exists (are you missing a cast?)", expr.Type.ToString(), ResolvedType.ToString()); } else { rc.Report.Error(0, loc, "Cannot implicitly convert type `{0}' to enum underlying type `{1}'", expr.Type.ToString(), ResolvedType.ToString()); } return(ErrorResult); } //else if (!c.IsValid && c.IsNumericConversion) // rc.Report.Warning(0, 4 ,loc, "Implicit conversion from type `{0}' to `{1}' was performed", // expr.Type.ToString(), ResolvedType.ToString()); if (expr.IsCompileTimeConstant && !c.IsUserDefined) { TypeCode code = ReflectionHelper.GetTypeCode(ResolvedType); if (code >= TypeCode.Boolean && code <= TypeCode.Decimal && expr.ConstantValue != null) { try { return(Constant.CreateConstantFromValue(rc, ResolvedType, rc.VSharpPrimitiveCast(code, expr.ConstantValue), loc)); } catch (OverflowException) { return(new ErrorExpression(ResolvedType, loc)); } catch (InvalidCastException) { return(new ErrorExpression(ResolvedType, loc)); } } else if (code == TypeCode.String) { if (expr.ConstantValue == null || expr.ConstantValue is string) { return(Constant.CreateConstantFromValue(rc, ResolvedType, expr.ConstantValue, loc)); } else { return(new ErrorExpression(ResolvedType, loc)); } } else if (ResolvedType.Kind == TypeKind.Enum) { code = ReflectionHelper.GetTypeCode(ResolveContext.GetEnumUnderlyingType(ResolvedType)); if (code >= TypeCode.SByte && code <= TypeCode.UInt64 && expr.ConstantValue != null) { try { return(Constant.CreateConstantFromValue(rc, ResolvedType, rc.VSharpPrimitiveCast(code, expr.ConstantValue), loc)); } catch (OverflowException) { return(new ErrorExpression(ResolvedType, loc)); } catch (InvalidCastException) { return(new ErrorExpression(ResolvedType, loc)); } } } } return(new CastExpression(ResolvedType, expr, c, rc.checkForOverflow)); }
public static Constant CreateConstantFromValue(ICompilation rc, IType t, object v, Location loc) { Constant c = null; switch ((t as ITypeDefinition).KnownTypeCode) { case KnownTypeCode.Int32: c = new IntConstant((int)v, loc); break; case KnownTypeCode.String: c = new StringConstant((string)v, loc); break; case KnownTypeCode.UInt32: c = new UIntConstant((uint)v, loc); break; case KnownTypeCode.Int64: c = new LongConstant((long)v, loc); break; case KnownTypeCode.UInt64: c = new ULongConstant((ulong)v, loc); break; case KnownTypeCode.Single: c = new FloatConstant((float)v, loc); break; case KnownTypeCode.Double: c = new DoubleConstant((double)v, loc); break; case KnownTypeCode.Int16: c = new ShortConstant((short)v, loc); break; case KnownTypeCode.UInt16: c = new UShortConstant((ushort)v, loc); break; case KnownTypeCode.SByte: c = new SByteConstant((sbyte)v, loc); break; case KnownTypeCode.Byte: c = new ByteConstant((byte)v, loc); break; case KnownTypeCode.Char: c = new CharConstant((char)v, loc); break; case KnownTypeCode.Boolean: c = new BoolConstant((bool)v, loc); break; } if (t.Kind == TypeKind.Enum) { var real_type = ResolveContext.GetEnumUnderlyingType(t); return(CreateConstantFromValue(rc, real_type, v, loc)); } if (v == null) { // TODO:Support nullable constant ? if (t.IsReferenceType.HasValue && t.IsReferenceType.Value) { c = new NullConstant(t, loc); } } if (c != null) { c = ((Constant)c).ResolveType(rc); } return(c); }
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)); } }