X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fnullable.cs;h=cd35b319e5985cb26f29215a501a002aaad296eb;hb=240486239dbe5b9084595fbe1dac326e2aad04de;hp=5c9d1940ab2a7e7b025555dc0cc7efd60c080a02;hpb=49d488b4d6babe90def1334edc7a643440c03b8f;p=mono.git diff --git a/mcs/mcs/nullable.cs b/mcs/mcs/nullable.cs index 5c9d1940ab2..cd35b319e59 100644 --- a/mcs/mcs/nullable.cs +++ b/mcs/mcs/nullable.cs @@ -573,7 +573,7 @@ namespace Mono.CSharp.Nullable bool IsBitwiseBoolean { get { - return (Oper & Operator.BitwiseMask) != 0 && + return (Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && ((left_unwrap != null && left_unwrap.Type == TypeManager.bool_type) || (right_unwrap != null && right_unwrap.Type == TypeManager.bool_type)); } @@ -647,14 +647,18 @@ namespace Mono.CSharp.Nullable // Arguments can be lifted for equal operators when the return type is bool and both // arguments are of same type // - if (left_orig.IsNull) { + if (left_orig is NullLiteral) { left = right; state |= State.LeftNullLifted; type = TypeManager.bool_type; } if (right_orig.IsNull) { - right = left; + if ((Oper & Operator.ShiftMask) != 0) + right = new EmptyExpression (TypeManager.int32_type); + else + right = left; + state |= State.RightNullLifted; type = TypeManager.bool_type; } @@ -696,7 +700,7 @@ namespace Mono.CSharp.Nullable } else { if (right_unwrap == null) { right.Emit (ec); - if (right is EmptyConstantCast) + if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { right_unwrap.Load (ec); @@ -710,7 +714,7 @@ namespace Mono.CSharp.Nullable if (right_unwrap == null) { if (Oper == Operator.BitwiseAnd) { right.Emit (ec); - if (right is EmptyConstantCast) + if (right is EmptyConstantCast || right is EmptyCast) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type)); } else { left_unwrap.Load (ec); @@ -885,8 +889,12 @@ namespace Mono.CSharp.Nullable if (lifted_type == null) return null; - if (right is UserCast || right is TypeCast) - right.Type = lifted_type.Type; + var r = right; + if (r is ReducedExpression) + r = ((ReducedExpression) r).OriginalExpression; + + if (r is UserCast || r is TypeCast) + r.Type = lifted_type.Type; else right = EmptyCast.Create (right, lifted_type.Type); } @@ -966,12 +974,37 @@ namespace Mono.CSharp.Nullable return e; } - protected override Expression ResolveUserOperator (ResolveContext ec, TypeSpec l, TypeSpec r) + protected override Expression ResolveUserOperator (ResolveContext ec, Expression left, Expression right) { - Expression expr = base.ResolveUserOperator (ec, l, r); + // + // Try original types first for exact match without unwrapping + // + Expression expr = base.ResolveUserOperator (ec, left_orig, right_orig); + if (expr != null) + return expr; + + State orig_state = state; + + // + // One side is a nullable type, try to match underlying types + // + if (left_unwrap != null || right_unwrap != null || (state & (State.RightNullLifted | State.LeftNullLifted)) != 0) { + expr = base.ResolveUserOperator (ec, left, right); + } + if (expr == null) return null; + // + // Lift the result in the case it can be null and predefined or user operator + // result type is of a value type + // + if (!TypeManager.IsValueType (expr.Type)) + return null; + + if (state != orig_state) + return expr; + expr = LiftResult (ec, expr); if (expr is Constant) return expr; @@ -1036,20 +1069,47 @@ namespace Mono.CSharp.Nullable if (unwrap == null) return null; + // + // Reduce (left ?? null) to left + // + if (right.IsNull) + return ReducedExpression.Create (left, this); + if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) { left = unwrap; - type = left.Type; - right = Convert.ImplicitConversion (ec, right, type, loc); + ltype = left.Type; + + // + // If right is a dynamic expression, the result type is dynamic + // + if (right.Type == InternalType.Dynamic) { + type = right.Type; + + // Need to box underlying value type + left = Convert.ImplicitBoxingConversion (left, ltype, type); + return this; + } + + right = Convert.ImplicitConversion (ec, right, ltype, loc); + type = ltype; return this; } } else if (TypeManager.IsReferenceType (ltype)) { if (Convert.ImplicitConversionExists (ec, right, ltype)) { // - // Reduce (constant ?? expr) to constant + // If right is a dynamic expression, the result type is dynamic + // + if (right.Type == InternalType.Dynamic) { + type = right.Type; + return this; + } + + // + // Reduce ("foo" ?? expr) to expression // Constant lc = left as Constant; if (lc != null && !lc.IsDefaultValue) - return new SideEffectConstant (lc, right, loc).Resolve (ec); + return ReducedExpression.Create (lc, this).Resolve (ec); // // Reduce (left ?? null) to left OR (null-constant ?? right) to right @@ -1058,7 +1118,7 @@ namespace Mono.CSharp.Nullable return ReducedExpression.Create (lc != null ? right : left, this); right = Convert.ImplicitConversion (ec, right, ltype, loc); - type = left.Type; + type = ltype; return this; } } else {