[mcs] Allows shadowing of probing pattern variables
[mono.git] / mcs / mcs / statement.cs
index 4f67eb3240f38407e24a36fc3c384b3f60714489..369343a5df7703515bec4e4f8963e4f71772467e 100644 (file)
@@ -269,7 +269,7 @@ namespace Mono.CSharp {
 
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
-                       fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
+                       fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
                        var labels = fc.CopyLabelStack ();
 
                        var res = TrueStatement.FlowAnalysis (fc);
@@ -558,6 +558,8 @@ namespace Mono.CSharp {
                                ec.Emit (OpCodes.Br, ec.LoopBegin);
                                ec.MarkLabel (while_loop);
 
+                               expr.EmitPrepare (ec);
+
                                Statement.Emit (ec);
                        
                                ec.MarkLabel (ec.LoopBegin);
@@ -576,9 +578,10 @@ namespace Mono.CSharp {
                {
                        expr.FlowAnalysisConditional (fc);
 
-                       fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
+                       fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
+
                        Statement.FlowAnalysis (fc);
 
                        //
@@ -1114,6 +1117,7 @@ namespace Mono.CSharp {
        public class Return : ExitStatement
        {
                Expression expr;
+               bool expr_returns;
 
                public Return (Expression expr, Location l)
                {
@@ -1268,16 +1272,38 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
+                       if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
+                               ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
+                               return false;
+                       }
+
                        if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
-                               expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+                               if (block_return_type.Kind == MemberKind.ByRef) {
+                                       var ref_expr = Expr as ReferenceExpression;
+                                       if (ref_expr == null) {
+                                               ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
+                                               return false;
+                                       }
+
+                                       var byref_return = (ReferenceContainer)block_return_type;
 
-                               if (expr == null) {
-                                       if (am != null && block_return_type == ec.ReturnType) {
-                                               ec.Report.Error (1662, loc,
-                                                       "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
-                                                       am.ContainerType, am.GetSignatureForError ());
+                                       if (expr.Type != byref_return.Element) {
+                                               ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
+                                                                                byref_return.GetSignatureForError ());
+                                               return false;
+                                       }
+                               } else {
+
+                                       expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+
+                                       if (expr == null) {
+                                               if (am != null && block_return_type == ec.ReturnType) {
+                                                       ec.Report.Error (1662, loc,
+                                                               "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+                                                               am.ContainerType, am.GetSignatureForError ());
+                                               }
+                                               return false;
                                        }
-                                       return false;
                                }
                        }
 
@@ -1339,7 +1365,9 @@ namespace Mono.CSharp {
                        if (expr != null)
                                expr.FlowAnalysis (fc);
 
-                       base.DoFlowAnalysis (fc);
+                       if (!expr_returns)
+                               base.DoFlowAnalysis (fc);
+                       
                        return true;
                }
 
@@ -1352,6 +1380,12 @@ namespace Mono.CSharp {
                public override Reachability MarkReachable (Reachability rc)
                {
                        base.MarkReachable (rc);
+
+                       if (Expr != null) {
+                               rc = Expr.MarkReachable (rc);
+                               expr_returns = rc.IsUnreachable;
+                       }
+
                        return Reachability.CreateUnreachable ();
                }
 
@@ -1767,6 +1801,19 @@ namespace Mono.CSharp {
                        }
                }
 
+               public static Expression ConvertType (ResolveContext rc, Expression expr)
+               {
+                       var et = rc.BuiltinTypes.Exception;
+                       if (Convert.ImplicitConversionExists (rc, expr, et))
+                               expr = Convert.ImplicitConversion (rc, expr, et, expr.Location);
+                       else {
+                               rc.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
+                               expr = EmptyCast.Create (expr, et);
+                       }
+
+                       return expr;
+               }
+
                public override bool Resolve (BlockContext ec)
                {
                        if (expr == null) {
@@ -1790,11 +1837,7 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
-                       var et = ec.BuiltinTypes.Exception;
-                       if (Convert.ImplicitConversionExists (ec, expr, et))
-                               expr = Convert.ImplicitConversion (ec, expr, et, loc);
-                       else
-                               ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
+                       expr = ConvertType (ec, expr);
 
                        return true;
                }
@@ -2164,7 +2207,7 @@ namespace Mono.CSharp {
                                }
 
                                if (type == null) {
-                                       type = type_expr.ResolveAsType (bc);
+                                       type = ResolveTypeExpression (bc);
                                        if (type == null)
                                                return false;
 
@@ -2187,6 +2230,25 @@ namespace Mono.CSharp {
                        }
 
                        if (initializer != null) {
+                               if (li.IsByRef) {
+                                       if (!(initializer is ReferenceExpression)) {
+                                               bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
+                                               return false;
+                                       }
+
+                                       if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+                                               bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
+                                       } else if (bc.CurrentIterator != null) {
+                                               bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
+                                       }
+
+                               } else {
+                                       if (initializer is ReferenceExpression) {
+                                               bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
+                                               return false;
+                                       }
+                               }
+
                                initializer = ResolveInitializer (bc, li, initializer);
                                // li.Variable.DefinitelyAssigned 
                        }
@@ -2216,6 +2278,11 @@ namespace Mono.CSharp {
                        return a.ResolveStatement (bc);
                }
 
+               protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+               {
+                       return type_expr.ResolveAsType (bc);
+               }
+
                protected override void DoEmit (EmitContext ec)
                {
                        li.CreateBuilder (ec);
@@ -2251,11 +2318,8 @@ namespace Mono.CSharp {
 
                public override Reachability MarkReachable (Reachability rc)
                {
-                       var init = initializer as ExpressionStatement;
-                       if (init != null)
-                               init.MarkReachable (rc);
-
-                       return base.MarkReachable (rc);
+                       base.MarkReachable (rc);
+                       return initializer == null ? rc : initializer.MarkReachable (rc);
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -2346,6 +2410,7 @@ namespace Mono.CSharp {
                        UsingVariable = 1 << 7,
                        IsLocked = 1 << 8,
                        SymbolFileHidden = 1 << 9,
+                       ByRef = 1 << 10,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -2418,12 +2483,20 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool Created {
+                       get {
+                               return builder != null;
+                       }
+               }
+
                public bool IsDeclared {
                        get {
                                return type != null;
                        }
                }
 
+               public bool IsByRef => (flags & Flags.ByRef) != 0;
+
                public bool IsCompilerGenerated {
                        get {
                                return (flags & Flags.CompilerGenerated) != 0;
@@ -2526,10 +2599,15 @@ namespace Mono.CSharp {
                                throw new InternalErrorException ("Already created variable `{0}'", name);
                        }
 
-                       //
-                       // All fixed variabled are pinned, a slot has to be alocated
-                       //
-                       builder = ec.DeclareLocal (Type, IsFixed);
+                       if (IsByRef) {
+                               builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
+                       } else {
+                               //
+                               // All fixed variabled are pinned, a slot has to be alocated
+                               //
+                               builder = ec.DeclareLocal(Type, IsFixed);
+                       }
+
                        if ((flags & Flags.SymbolFileHidden) == 0)
                                ec.DefineLocalVariable (name, builder);
                }
@@ -2578,7 +2656,10 @@ namespace Mono.CSharp {
                        if ((flags & Flags.CompilerGenerated) != 0)
                                CreateBuilder (ec);
 
-                       ec.Emit (OpCodes.Ldloca, builder);
+                       if (IsByRef)
+                               ec.Emit (OpCodes.Ldloc, builder);
+                       else
+                               ec.Emit (OpCodes.Ldloca, builder);
                }
 
                public static string GetCompilerGeneratedName (Block block)
@@ -2797,9 +2878,9 @@ namespace Mono.CSharp {
                        AddLocalName (li.Name, li);
                }
 
-               public void AddLocalName (string name, INamedBlockVariable li)
+               public virtual void AddLocalName (string name, INamedBlockVariable li, bool canShadowChildrenBlockName = false)
                {
-                       ParametersBlock.TopBlock.AddLocalName (name, li, false);
+                       ParametersBlock.TopBlock.AddLocalName (name, li, canShadowChildrenBlockName);
                }
 
                public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
@@ -4176,7 +4257,7 @@ namespace Mono.CSharp {
                        }
                }
 
-               public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
+               public override void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
                {
                        if (names == null)
                                names = new Dictionary<string, object> ();
@@ -6357,7 +6438,7 @@ namespace Mono.CSharp {
                public override bool Resolve (BlockContext ec)
                {
                        if (ec.CurrentIterator != null)
-                               ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
+                               Expression.UnsafeInsideIteratorError (ec, loc);
 
                        using (ec.Set (ResolveContext.Options.UnsafeScope))
                                return Block.Resolve (ec);
@@ -7459,6 +7540,10 @@ namespace Mono.CSharp {
                                                ec.Emit (OpCodes.Br, end);
 
                                        ec.MarkLabel (labels [i + 1]);
+
+                                       ec.EmitInt (0);
+                                       ec.Emit (OpCodes.Stloc, state_variable);
+
                                        c = catch_sm [i];
                                        ec.AsyncThrowVariable = c.Variable;
                                        c.Block.Emit (ec);