Merge pull request #5002 from BrzVlad/feature-sgen-modes
[mono.git] / mcs / mcs / expression.cs
index c054330db202f339be76b7a07f01626fd207f7fe..da37657867ed0e59f43a1d9eefdd010e977e9ae8 100644 (file)
@@ -1490,6 +1490,11 @@ namespace Mono.CSharp
                        expr.EmitSideEffect (ec);
                }
 
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       expr.EmitPrepare (ec);
+               }
+
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
                        expr.FlowAnalysis (fc);
@@ -1535,7 +1540,7 @@ namespace Mono.CSharp
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        if (Variable != null)
-                               throw new NotSupportedException ();
+                               ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
 
                        Arguments args = Arguments.CreateForExpressionTree (ec, null,
                                expr.CreateExpressionTree (ec),
@@ -1590,6 +1595,14 @@ namespace Mono.CSharp
                        ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
 
+               public override void EmitPrepare (EmitContext ec)
+               {
+                       base.EmitPrepare (ec);
+
+                       if (Variable != null)
+                               Variable.CreateBuilder (ec);
+               }
+
                void EmitPatternMatch (EmitContext ec)
                {
                        var no_match = ec.DefineLabel ();
@@ -1695,7 +1708,13 @@ namespace Mono.CSharp
                                        value_on_stack = false;
                                }
 
-                               Variable.CreateBuilder (ec);
+                               //
+                               // It's ok to have variable builder create out of order. It simplified emit
+                               // of statements like while (condition) { }
+                               //
+                               if (!Variable.Created)
+                                       Variable.CreateBuilder (ec);
+                               
                                Variable.EmitAssign (ec);
 
                                if (expr_unwrap != null) {
@@ -1739,6 +1758,21 @@ namespace Mono.CSharp
                                fc.SetVariableAssigned (Variable.VariableInfo, true);
                }
 
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       if (Variable == null) {
+                               base.FlowAnalysisConditional (fc);
+                               return;
+                       }
+
+                       expr.FlowAnalysis (fc);
+
+                       fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
+                       fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+
+                       fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
+               }
+
                protected override void ResolveProbeType (ResolveContext rc)
                {
                        if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
@@ -1849,6 +1883,15 @@ namespace Mono.CSharp
 
                Expression ResolveResultExpression (ResolveContext ec)
                {
+                       if (Variable != null) {
+                               if (expr is NullLiteral) {
+                                       ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
+                                       return this;
+                               }
+
+                               CheckExpressionVariable (ec);
+                       }
+
                        TypeSpec d = expr.Type;
                        bool d_is_nullable = false;
 
@@ -1856,7 +1899,7 @@ namespace Mono.CSharp
                        // If E is a method group or the null literal, or if the type of E is a reference
                        // type or a nullable type and the value of E is null, the result is false
                        //
-                       if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
+                       if (expr.IsNull)
                                return CreateConstantResult (ec, false);
 
                        if (d.IsNullableType) {
@@ -1870,6 +1913,11 @@ namespace Mono.CSharp
                        TypeSpec t = probe_type_expr;
                        bool t_is_nullable = false;
                        if (t.IsNullableType) {
+                               if (Variable != null) {
+                                       ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
+                                                                        t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
+                               }
+
                                var ut = Nullable.NullableInfo.GetUnderlyingType (t);
                                if (!ut.IsGenericParameter) {
                                        t = ut;
@@ -1914,9 +1962,13 @@ namespace Mono.CSharp
                                        return ResolveGenericParameter (ec, d, tps);
 
                                if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
-                                       ec.Report.Warning (1981, 3, loc,
-                                               "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
-                                               OperatorName, t.GetSignatureForError ());
+                                       if (Variable != null) {
+                                               ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
+                                       } else {
+                                               ec.Report.Warning (1981, 3, loc,
+                                                       "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+                                                       OperatorName, t.GetSignatureForError ());
+                                       }
                                }
 
                                if (TypeManager.IsGenericParameter (d))
@@ -2562,12 +2614,14 @@ namespace Mono.CSharp
 
                public override Expression CreateExpressionTree (ResolveContext rc)
                {
-                       rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
+                       rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
                        return null;
                }
 
                bool DoResolveCommon (ResolveContext rc)
                {
+                       CheckExpressionVariable (rc);
+
                        var var_expr = VariableType as VarExpr;
                        if (var_expr != null) {
                                type = InternalType.VarOutType;
@@ -7570,14 +7624,21 @@ namespace Mono.CSharp
                        bool is_value_type = type.IsStructOrEnum;
                        VariableReference vr = target as VariableReference;
 
+                       bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
+
                        if (target != null && is_value_type && (vr != null || method == null)) {
+                               if (prepare_await) {
+                                       arguments = arguments.Emit (ec, false, true);
+                                       prepare_await = false;
+                               }
+                               
                                target.AddressOf (ec, AddressOp.Store);
                        } else if (vr != null && vr.IsRef) {
                                vr.EmitLoad (ec);
                        }
 
                        if (arguments != null) {
-                               if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
+                               if (prepare_await)
                                        arguments = arguments.Emit (ec, false, true);
 
                                arguments.Emit (ec);
@@ -12728,4 +12789,68 @@ namespace Mono.CSharp
                        return value;
                }
        }
+
+       class ThrowExpression : ExpressionStatement
+       {
+               Expression expr;
+
+               public ThrowExpression (Expression expr, Location loc)
+               {
+                       this.expr = expr;
+                       this.loc = loc;
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       var target = (ThrowExpression)t;
+                       target.expr = expr.Clone (clonectx);
+               }
+
+               public override bool ContainsEmitWithAwait ()
+               {
+                       return expr.ContainsEmitWithAwait ();
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
+                       return expr;
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+
+                       if (expr == null)
+                               return null;
+
+                       expr = Throw.ConvertType (rc, expr);
+
+                       eclass = ExprClass.Value;
+                       type = InternalType.ThrowExpr;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       EmitStatement (ec);
+               }
+
+               public override void EmitStatement (EmitContext ec)
+               {
+                       expr.Emit (ec);
+
+                       ec.Emit (OpCodes.Throw);
+               }
+
+               public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysis (fc);
+               }
+
+               public override Reachability MarkReachable (Reachability rc)
+               {
+                       return Reachability.CreateUnreachable ();
+               }
+       }
 }