[mcs] nonliteral constants pattern matching
[mono.git] / mcs / mcs / nullable.cs
index 1732a9b9c5c46edda117e4104b1d1637ad617bda..e857e365410152f1613f0675e5fc83ffae1f8b30 100644 (file)
@@ -33,7 +33,7 @@ namespace Mono.CSharp.Nullable
                        this.loc = loc;
                }
 
-               public override TypeSpec ResolveAsType (IMemberContext ec)
+               public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments = false)
                {
                        eclass = ExprClass.Type;
 
@@ -84,9 +84,15 @@ namespace Mono.CSharp.Nullable
                }
 
                public static TypeSpec GetEnumUnderlyingType (ModuleContainer module, TypeSpec nullableEnum)
+               {
+                       return MakeType (module, EnumSpec.GetUnderlyingType (GetUnderlyingType (nullableEnum)));
+               }
+
+               public static TypeSpec MakeType (ModuleContainer module, TypeSpec underlyingType)
                {
                        return module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (module,
-                               new[] { EnumSpec.GetUnderlyingType (GetUnderlyingType (nullableEnum)) });
+                               new[] { underlyingType });
+
                }
        }
 
@@ -187,6 +193,11 @@ namespace Mono.CSharp.Nullable
                        call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
                }
 
+               public override void EmitSideEffect (EmitContext ec)
+               {
+                       expr.EmitSideEffect (ec);
+               }
+
                public override Expression EmitToField (EmitContext ec)
                {
                        if (temp_field == null)
@@ -201,6 +212,11 @@ namespace Mono.CSharp.Nullable
                        return uw != null && expr.Equals (uw.expr);
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysis (fc);
+               }
+
                public Expression Original {
                        get {
                                return expr;
@@ -419,6 +435,12 @@ namespace Mono.CSharp.Nullable
                {
                }
 
+               public override bool IsNull {
+                       get {
+                               return expr.IsNull;
+                       }
+               }
+
                public override bool ContainsEmitWithAwait ()
                {
                        return unwrap.ContainsEmitWithAwait ();
@@ -480,6 +502,11 @@ namespace Mono.CSharp.Nullable
                        ec.MarkLabel (end_label);
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysis (fc);
+               }
+
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
                        unwrap.AddressOf (ec, mode);
@@ -519,6 +546,11 @@ namespace Mono.CSharp.Nullable
                                return null;
 
                        Expression res = base.ResolveOperator (ec, unwrap);
+                       if (res == null) {
+                               Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
+                               return null;
+                       }
+
                        if (res != this) {
                                if (user_operator == null)
                                        return res;
@@ -649,10 +681,10 @@ namespace Mono.CSharp.Nullable
                {
                        if (rc.IsRuntimeBinder) {
                                if (UnwrapLeft == null && !Left.Type.IsNullableType)
-                                       Left = Wrap.Create (Left, rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { Left.Type }));
+                                       Left = LiftOperand (rc, Left);
 
                                if (UnwrapRight == null && !Right.Type.IsNullableType)
-                                       Right = Wrap.Create (Right, rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { Right.Type }));
+                                       Right = LiftOperand (rc, Right);
                        } else {
                                if (UnwrapLeft == null && Left != null && Left.Type.IsNullableType) {
                                        Left = Unwrap.CreateUnwrapped (Left);
@@ -671,6 +703,21 @@ namespace Mono.CSharp.Nullable
                        return this;
                }
 
+               Expression LiftOperand (ResolveContext rc, Expression expr)
+               {
+                       TypeSpec type;
+                       if (expr.IsNull) {
+                               type = Left.IsNull ? Right.Type : Left.Type;
+                       } else {
+                               type = expr.Type;
+                       }
+
+                       if (!type.IsNullableType)
+                               type = NullableInfo.MakeType (rc.Module, type);
+
+                       return Wrap.Create (expr, type);
+               }
+
                public override void Emit (EmitContext ec)
                {
                        if (IsBitwiseBoolean && UserOperator == null) {
@@ -752,6 +799,9 @@ namespace Mono.CSharp.Nullable
                                if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) {
                                        Left = Left.EmitToField (ec);
                                        Right = Right.EmitToField (ec);
+                               } else {
+                                       UnwrapLeft.Store (ec);
+                                       UnwrapRight.Store (ec);
                                }
 
                                Left.Emit (ec);
@@ -1008,6 +1058,11 @@ namespace Mono.CSharp.Nullable
                        ec.MarkLabel (end_label);
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       Binary.FlowAnalysis (fc);
+               }
+
                public override SLE.Expression MakeExpression (BuilderContext ctx)
                {
                        return Binary.MakeExpression (ctx, Left, Right);
@@ -1086,24 +1141,35 @@ namespace Mono.CSharp.Nullable
                                if (right.IsNull)
                                        return ReducedExpression.Create (left, this);
 
-                               if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) {
-                                       left = unwrap;
-                                       ltype = left.Type;
-
-                                       //
-                                       // If right is a dynamic expression, the result type is dynamic
-                                       //
-                                       if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
-                                               type = right.Type;
-
-                                               // Need to box underlying value type
-                                               left = Convert.ImplicitBoxingConversion (left, ltype, type);
+                               Expression conv;
+                               if (right.Type.IsNullableType) {
+                                       conv = right.Type == ltype ? right : Convert.ImplicitNulableConversion (ec, right, ltype);
+                                       if (conv != null) {
+                                               right = conv;
+                                               type = ltype;
+                                               return this;
+                                       }
+                               } else {
+                                       conv = Convert.ImplicitConversion (ec, right, unwrap.Type, loc);
+                                       if (conv != null) {
+                                               left = unwrap;
+                                               ltype = left.Type;
+
+                                               //
+                                               // If right is a dynamic expression, the result type is dynamic
+                                               //
+                                               if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
+                                                       type = right.Type;
+
+                                                       // Need to box underlying value type
+                                                       left = Convert.ImplicitBoxingConversion (left, ltype, type);
+                                                       return this;
+                                               }
+
+                                               right = conv;
+                                               type = ltype;
                                                return this;
                                        }
-
-                                       right = Convert.ImplicitConversion (ec, right, ltype, loc);
-                                       type = ltype;
-                                       return this;
                                }
                        } else if (TypeSpec.IsReferenceType (ltype)) {
                                if (Convert.ImplicitConversionExists (ec, right, ltype)) {
@@ -1120,26 +1186,25 @@ namespace Mono.CSharp.Nullable
                                        //
                                        Constant lc = left as Constant;
                                        if (lc != null && !lc.IsDefaultValue)
-                                               return ReducedExpression.Create (lc, this);
+                                               return ReducedExpression.Create (lc, this, false);
 
                                        //
                                        // Reduce (left ?? null) to left OR (null-constant ?? right) to right
                                        //
-                                       if (right.IsNull || lc != null)
-                                               return ReducedExpression.Create (lc != null ? right : left, this);
+                                       if (right.IsNull || lc != null) {
+                                               //
+                                               // Special case null ?? null
+                                               //
+                                               if (right.IsNull && ltype == right.Type)
+                                                       return null;
+
+                                               return ReducedExpression.Create (lc != null ? right : left, this, false);
+                                       }
 
                                        right = Convert.ImplicitConversion (ec, right, ltype, loc);
                                        type = ltype;
                                        return this;
                                }
-
-                               //
-                               // Special case null ?? null
-                               //
-                               if (ltype == right.Type) {
-                                       type = ltype;
-                                       return this;
-                               }
                        } else {
                                return null;
                        }
@@ -1152,9 +1217,15 @@ namespace Mono.CSharp.Nullable
                        // Reduce (null ?? right) to right
                        //
                        if (left.IsNull)
-                               return ReducedExpression.Create (right, this).Resolve (ec);
+                               return ReducedExpression.Create (right, this, false).Resolve (ec);
 
                        left = Convert.ImplicitConversion (ec, unwrap ?? left, rtype, loc);
+
+                       if (TypeSpec.IsValueType (left.Type) && !left.Type.IsNullableType) {
+                               Warning_UnreachableExpression (ec, right.Location);
+                               return ReducedExpression.Create (left, this, false).Resolve (ec);
+                       }
+
                        type = rtype;
                        return this;
                }
@@ -1196,7 +1267,15 @@ namespace Mono.CSharp.Nullable
                                unwrap.EmitCheck (ec);
                                ec.Emit (OpCodes.Brfalse, is_null_label);
 
-                               left.Emit (ec);
+                               //
+                               // When both expressions are nullable the unwrap
+                               // is needed only for null check not for value uwrap
+                               //
+                               if (type.IsNullableType && TypeSpecComparer.IsEqual (NullableInfo.GetUnderlyingType (type), unwrap.Type))
+                                       unwrap.Load (ec);
+                               else
+                                       left.Emit (ec);
+
                                ec.Emit (OpCodes.Br, end_label);
 
                                ec.MarkLabel (is_null_label);
@@ -1221,6 +1300,14 @@ namespace Mono.CSharp.Nullable
                        ec.MarkLabel (end_label);
                }
 
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       left.FlowAnalysis (fc);
+                       var left_da = fc.BranchDefiniteAssignment ();
+                       right.FlowAnalysis (fc);
+                       fc.DefiniteAssignment = left_da;
+               }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        NullCoalescingOperator target = (NullCoalescingOperator) t;