target.child = child.Clone (clonectx);
}
+
+ public override bool IsNull {
+ get {
+ return child.IsNull;
+ }
+ }
}
public class EmptyCast : TypeCast {
+ bool is_implicit;
+
EmptyCast (Expression child, Type target_type)
: base (child, target_type)
{
}
-
+
+ //
+ // HACK: This is just temporary hack before real EmptyCast clean-up required by expression trees
+ //
+ public static Expression Create (Expression child, Type type, bool is_implicit)
+ {
+ EmptyCast e = new EmptyCast (child, type);
+ e.is_implicit = true;
+ return e;
+ }
+
public static Expression Create (Expression child, Type type)
{
Constant c = child as Constant;
return new EmptyCast (child, type);
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ if (is_implicit)
+ return child.CreateExpressionTree (ec);
+ else
+ return base.CreateExpressionTree (ec);
+ }
+
public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
{
child.EmitBranchable (ec, label, on_true);
readonly Operator oper;
protected Expression left, right;
readonly bool is_compound;
+ Expression enum_conversion;
// This must be kept in sync with Operator!!!
public static readonly string [] oper_names;
Expression expr;
bool primitives_only = false;
+ if (standard_operators == null)
+ CreateStandardOperatorsTable ();
+
//
// Handles predefined primitive types
//
}
}
- if (standard_operators == null)
- CreateStandardOperatorsTable ();
-
- return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
+ return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
}
// at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
if (ltype != int32) {
Constant c = left as Constant;
if (c != null)
- temp = c.ImplicitConversionRequired (int32, loc);
+ temp = c.ConvertImplicitly (int32);
else
temp = Convert.ImplicitNumericConversion (left, int32);
if (rtype != int32) {
Constant c = right as Constant;
if (c != null)
- temp = c.ImplicitConversionRequired (int32, loc);
+ temp = c.ConvertImplicitly (int32);
else
temp = Convert.ImplicitNumericConversion (right, int32);
//
// Enumeration operators
//
- Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
+ Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
{
Expression temp;
//
if (oper == Operator.Addition || oper == Operator.Subtraction) {
underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
- temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
- if (temp == null)
+ temp = left;
+ left = EmptyCast.Create (left, underlying_type, true);
+ if (!DoBinaryOperatorPromotion (ec)) {
+ left = temp;
return null;
+ }
- right = temp;
- type = ltype;
- return this;
+ enum_conversion = Convert.ExplicitNumericConversion (
+ new EmptyExpression (left.Type), underlying_type);
+
+ return ResolveOperatorPredefined (ec, standard_operators, true, ltype);
}
return null;
if (pointer_operators == null)
CreatePointerOperatorsTable ();
- return ResolveOperatorPredefined (ec, pointer_operators, false);
+ return ResolveOperatorPredefined (ec, pointer_operators, false, null);
}
//
// Build-in operators method overloading
//
- protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
+ protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
{
PredefinedOperator best_operator = null;
Type l = left.Type;
if (best_operator == null)
return null;
- return best_operator.ConvertResult (ec, this);
+ Expression expr = best_operator.ConvertResult (ec, this);
+ if (enum_type == null)
+ return expr;
+
+ //
+ // HACK: required by enum_conversion
+ //
+ expr.Type = enum_type;
+ return EmptyCast.Create (expr, enum_type);
}
//
}
ig.Emit (opcode);
+
+ //
+ // Nullable enum could require underlying type cast and we cannot simply wrap binary
+ // expression because that would wrap lifted binary operation
+ //
+ if (enum_conversion != null)
+ enum_conversion.Emit (ec);
}
public override void EmitSideEffect (EmitContext ec)
//
// Either left or right is null
//
- if (left_unwrap != null && right.IsNull) {
+ if (left_unwrap != null && (right_null_lifted || right.IsNull)) {
left_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
ig.Emit (OpCodes.Ldc_I4_0);
return true;
}
- if (right_unwrap != null && left.IsNull) {
+ if (right_unwrap != null && (left_null_lifted || left.IsNull)) {
right_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
ig.Emit (OpCodes.Ldc_I4_0);
return null;
wrap_ctor = new NullableInfo (lifted_type.Type).Constructor;
- res_expr.Type = lifted_type.Type;
+ type = res_expr.Type = lifted_type.Type;
}
if (left_null_lifted) {
return res_expr;
}
- protected override Expression ResolveOperatorPredefined (EmitContext ec, Binary.PredefinedOperator [] operators, bool primitives_only)
+ protected override Expression ResolveOperatorPredefined (EmitContext ec, Binary.PredefinedOperator [] operators, bool primitives_only, Type enum_type)
{
- Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only);
+ Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only, enum_type);
- if (e == this)
+ if (e == this || enum_type != null)
return LiftResult (ec, e);
//