Bug 15574. XML deserialization recursion: add array type to known_types?
[mono.git] / mcs / mcs / iterators.cs
index 705599f8d1796c4b5ba5176669f50cd8988d93e8..0d3c19af9a7de9d59a3a7280ef022ff61b73d8f8 100644 (file)
 // Copyright 2011 Xamarin Inc.
 //
 
-// TODO:
-//    Flow analysis for Yield.
-//
-
 using System;
 using System.Collections.Generic;
 using Mono.CompilerServices.SymbolWriter;
@@ -33,6 +29,7 @@ namespace Mono.CSharp
                protected bool unwind_protect;
                protected T machine_initializer;
                int resume_pc;
+               ExceptionStatement inside_try_block;
 
                protected YieldStatement (Expression expr, Location l)
                {
@@ -55,6 +52,15 @@ namespace Mono.CSharp
                        machine_initializer.InjectYield (ec, expr, resume_pc, unwind_protect, resume_point);
                }
 
+               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysis (fc);
+
+                       RegisterResumePoint ();
+
+                       return false;
+               }
+
                public override bool Resolve (BlockContext bc)
                {
                        expr = expr.Resolve (bc);
@@ -62,12 +68,20 @@ namespace Mono.CSharp
                                return false;
 
                        machine_initializer = bc.CurrentAnonymousMethod as T;
-
-                       if (!bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
-                               unwind_protect = bc.CurrentBranching.AddResumePoint (this, out resume_pc);
-
+                       inside_try_block = bc.CurrentTryBlock;
                        return true;
                }
+
+               public void RegisterResumePoint ()
+               {
+                       if (inside_try_block == null) {
+                               resume_pc = machine_initializer.AddResumePoint (this);
+                       } else {
+                               resume_pc = inside_try_block.AddResumePoint (this, resume_pc, machine_initializer);
+                               unwind_protect = true;
+                               inside_try_block = null;
+                       }
+               }
        }
 
        public class Yield : YieldStatement<Iterator>
@@ -77,14 +91,19 @@ namespace Mono.CSharp
                {
                }
 
-               public static bool CheckContext (ResolveContext ec, Location loc)
+               public static bool CheckContext (BlockContext bc, Location loc)
                {
-                       if (!ec.CurrentAnonymousMethod.IsIterator) {
-                               ec.Report.Error (1621, loc,
+                       if (!bc.CurrentAnonymousMethod.IsIterator) {
+                               bc.Report.Error (1621, loc,
                                        "The yield statement cannot be used inside anonymous method blocks");
                                return false;
                        }
 
+                       if (bc.HasSet (ResolveContext.Options.FinallyScope)) {
+                               bc.Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
+                               return false;
+                       }
+
                        return true;
                }
 
@@ -93,6 +112,14 @@ namespace Mono.CSharp
                        if (!CheckContext (bc, loc))
                                return false;
 
+                       if (bc.HasAny (ResolveContext.Options.TryWithCatchScope)) {
+                               bc.Report.Error (1626, loc, "Cannot yield a value in the body of a try block with a catch clause");
+                       }
+
+                       if (bc.HasSet (ResolveContext.Options.CatchScope)) {
+                               bc.Report.Error (1631, loc, "Cannot yield a value in the body of a catch clause");
+                       }
+
                        if (!base.Resolve (bc))
                                return false;
 
@@ -121,9 +148,10 @@ namespace Mono.CSharp
                        loc = l;
                }
 
-               public override void Error_FinallyClause (Report Report)
-               {
-                       Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
+               protected override bool IsLocalExit {
+                       get {
+                               return false;
+                       }
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -131,16 +159,27 @@ namespace Mono.CSharp
                        throw new NotSupportedException ();
                }
 
-               protected override bool DoResolve (BlockContext ec)
+               protected override bool DoResolve (BlockContext bc)
                {
-                       iterator = ec.CurrentIterator;
-                       return Yield.CheckContext (ec, loc);
+                       iterator = bc.CurrentIterator;
+                       return Yield.CheckContext (bc, loc);
                }
 
                protected override void DoEmit (EmitContext ec)
                {
                        iterator.EmitYieldBreak (ec, unwind_protect);
                }
+
+               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+               {
+                       return true;
+               }
+
+               public override Reachability MarkReachable (Reachability rc)
+               {
+                       base.MarkReachable (rc);
+                       return Reachability.CreateUnreachable ();
+               }
                
                public override object Accept (StructuralVisitor visitor)
                {
@@ -249,7 +288,7 @@ namespace Mono.CSharp
 
                                                for (int i = 0; i < host.hoisted_params.Count; ++i) {
                                                        HoistedParameter hp = host.hoisted_params [i];
-                                                       HoistedParameter hp_cp = host.hoisted_params_copy [i];
+                                                       HoistedParameter hp_cp = host.hoisted_params_copy [i] ?? hp;
 
                                                        FieldExpr from = new FieldExpr (hp_cp.Field, loc);
                                                        from.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
@@ -269,7 +308,6 @@ namespace Mono.CSharp
                                        if (new_storey != null)
                                                new_storey = Convert.ImplicitConversionRequired (ec, new_storey, host_method.MemberType, loc);
 
-                                       ec.CurrentBranching.CurrentUsageVector.Goto ();
                                        return true;
                                }
 
@@ -297,10 +335,21 @@ namespace Mono.CSharp
                                        new_storey.Emit (ec);
                                        ec.Emit (OpCodes.Ret);
                                }
+
+                               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                               {
+                                       throw new NotImplementedException ();
+                               }
+
+                               public override Reachability MarkReachable (Reachability rc)
+                               {
+                                       base.MarkReachable (rc);
+                                       return Reachability.CreateUnreachable ();
+                               }
                        }
 
                        GetEnumeratorMethod (IteratorStorey host, FullNamedExpression returnType, MemberName name)
-                               : base (host, null, returnType, Modifiers.DEBUGGER_HIDDEN, name)
+                               : base (host, null, returnType, Modifiers.DEBUGGER_HIDDEN, name, ToplevelBlock.Flags.CompilerGenerated | ToplevelBlock.Flags.NoFlowAnalysis)
                        {
                        }
 
@@ -314,7 +363,6 @@ namespace Mono.CSharp
                                var m = new GetEnumeratorMethod (host, returnType, name);
                                var stmt = statement ?? new GetEnumeratorStatement (host, m);
                                m.block.AddStatement (stmt);
-                               m.block.IsCompilerGenerated = true;
                                return m;
                        }
                }
@@ -346,16 +394,20 @@ namespace Mono.CSharp
                                        ec.CurrentAnonymousMethod = iterator;
                                        iterator.EmitDispose (ec);
                                }
+
+                               protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                               {
+                                       throw new NotImplementedException ();
+                               }
                        }
 
                        public DisposeMethod (IteratorStorey host)
                                : base (host, null, new TypeExpression (host.Compiler.BuiltinTypes.Void, host.Location), Modifiers.PUBLIC | Modifiers.DEBUGGER_HIDDEN,
-                                       new MemberName ("Dispose", host.Location))
+                                       new MemberName ("Dispose", host.Location), ToplevelBlock.Flags.CompilerGenerated | ToplevelBlock.Flags.NoFlowAnalysis)
                        {
                                host.Members.Add (this);
 
                                Block.AddStatement (new DisposeMethodStatement (host.Iterator));
-                               Block.IsCompilerGenerated = true;
                        }
                }
 
@@ -435,6 +487,13 @@ namespace Mono.CSharp
                        get { return hoisted_params; }
                }
 
+               protected override Constructor DefineDefaultConstructor (bool is_static)
+               {
+                       var ctor = base.DefineDefaultConstructor (is_static);
+                       ctor.ModFlags |= Modifiers.DEBUGGER_HIDDEN;
+                       return ctor;
+               }
+
                protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
                {
                        var mtype = Iterator.OriginalIteratorType;
@@ -473,17 +532,26 @@ namespace Mono.CSharp
                        current_field = AddCompilerGeneratedField ("$current", iterator_type_expr);
                        disposing_field = AddCompilerGeneratedField ("$disposing", new TypeExpression (Compiler.BuiltinTypes.Bool, Location));
 
-                       if (hoisted_params != null) {
+                       if (Iterator.IsEnumerable && hoisted_params != null) {
                                //
                                // Iterators are independent, each GetEnumerator call has to
                                // create same enumerator therefore we have to keep original values
                                // around for re-initialization
                                //
-                               // TODO: Do it for assigned/modified parameters only
-                               //
                                hoisted_params_copy = new List<HoistedParameter> (hoisted_params.Count);
                                foreach (HoistedParameter hp in hoisted_params) {
-                                       hoisted_params_copy.Add (new HoistedParameter (hp, "<$>" + hp.Field.Name));
+
+                                       //
+                                       // Don't create field copy for unmodified captured parameters
+                                       //
+                                       HoistedParameter hp_copy;
+                                       if (hp.IsAssigned) {
+                                               hp_copy = new HoistedParameter (hp, "<$>" + hp.Field.Name);
+                                       } else {
+                                               hp_copy = null;
+                                       }
+
+                                       hoisted_params_copy.Add (hp_copy);
                                }
                        }
 
@@ -534,9 +602,8 @@ namespace Mono.CSharp
 
                        var name = new MemberName ("Current", null, explicit_iface, Location);
 
-                       ToplevelBlock get_block = new ToplevelBlock (Compiler, Location) {
-                               IsCompilerGenerated = true
-                       };
+                       ToplevelBlock get_block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location,
+                               Block.Flags.CompilerGenerated | Block.Flags.NoFlowAnalysis);
                        get_block.AddStatement (new Return (new DynamicFieldExpr (CurrentField, Location), Location));
                                
                        Property current = new Property (this, type, Modifiers.DEBUGGER_HIDDEN | Modifiers.COMPILER_GENERATED, name, null);
@@ -555,9 +622,8 @@ namespace Mono.CSharp
                                ParametersCompiled.EmptyReadOnlyParameters, null);
                        Members.Add (reset);
 
-                       reset.Block = new ToplevelBlock (Compiler, Location) {
-                               IsCompilerGenerated = true
-                       };
+                       reset.Block = new ToplevelBlock (Compiler, reset.ParameterInfo, Location,
+                               Block.Flags.CompilerGenerated | Block.Flags.NoFlowAnalysis);
 
                        TypeSpec ex_type = Module.PredefinedTypes.NotSupportedException.Resolve ();
                        if (ex_type == null)
@@ -566,10 +632,11 @@ namespace Mono.CSharp
                        reset.Block.AddStatement (new Throw (new New (new TypeExpression (ex_type, Location), null, Location), Location));
                }
 
-               protected override void EmitHoistedParameters (EmitContext ec, IList<HoistedParameter> hoisted)
+               protected override void EmitHoistedParameters (EmitContext ec, List<HoistedParameter> hoisted)
                {
                        base.EmitHoistedParameters (ec, hoisted);
-                       base.EmitHoistedParameters (ec, hoisted_params_copy);
+                       if (hoisted_params_copy != null)
+                               base.EmitHoistedParameters (ec, hoisted_params_copy);
                }
        }
 
@@ -577,12 +644,13 @@ namespace Mono.CSharp
        {
                readonly StateMachineInitializer expr;
 
-               public StateMachineMethod (StateMachine host, StateMachineInitializer expr, FullNamedExpression returnType, Modifiers mod, MemberName name)
+               public StateMachineMethod (StateMachine host, StateMachineInitializer expr, FullNamedExpression returnType,
+                       Modifiers mod, MemberName name, ToplevelBlock.Flags blockFlags)
                        : base (host, returnType, mod | Modifiers.COMPILER_GENERATED,
                          name, ParametersCompiled.EmptyReadOnlyParameters, null)
                {
                        this.expr = expr;
-                       Block = new ToplevelBlock (host.Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
+                       Block = new ToplevelBlock (host.Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null, blockFlags);
                }
 
                public override EmitContext CreateEmitContext (ILGenerator ig, SourceMethodBuilder sourceMethod)
@@ -629,6 +697,21 @@ namespace Mono.CSharp
                                // Don't create sequence point
                                DoEmit (ec);
                        }
+
+                       protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                       {
+                               return state_machine.ReturnType.Kind != MemberKind.Void;
+                       }
+
+                       public override Reachability MarkReachable (Reachability rc)
+                       {
+                               base.MarkReachable (rc);
+
+                               if (state_machine.ReturnType.Kind != MemberKind.Void)
+                                       rc = Reachability.CreateUnreachable ();
+
+                               return rc;
+                       }
                }
 
                public readonly TypeDefinition Host;
@@ -693,34 +776,33 @@ namespace Mono.CSharp
                        throw new NotSupportedException ("ET");
                }
 
-               protected virtual BlockContext CreateBlockContext (ResolveContext rc)
+               protected virtual BlockContext CreateBlockContext (BlockContext bc)
                {
-                       var ctx = new BlockContext (rc, block, ((BlockContext) rc).ReturnType);
+                       var ctx = new BlockContext (bc, block, bc.ReturnType);
                        ctx.CurrentAnonymousMethod = this;
+
+                       ctx.AssignmentInfoOffset = bc.AssignmentInfoOffset;
+                       ctx.EnclosingLoop = bc.EnclosingLoop;
+                       ctx.EnclosingLoopOrSwitch = bc.EnclosingLoopOrSwitch;
+                       ctx.Switch = bc.Switch;
+
                        return ctx;
                }
 
-               protected override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext rc)
                {
-                       var ctx = CreateBlockContext (ec);
+                       var bc = (BlockContext) rc;
+                       var ctx = CreateBlockContext (bc);
 
                        Block.Resolve (ctx);
 
-                       //
-                       // Explicit return is required for Task<T> state machine
-                       //
-                       var task_storey = storey as AsyncTaskStorey;
-                       if (task_storey == null || (task_storey.ReturnType != null && !task_storey.ReturnType.IsGenericTask))
-                               ctx.CurrentBranching.CurrentUsageVector.Goto ();
-
-                       ctx.EndFlowBranching ();
-
-                       if (!ec.IsInProbingMode) {
-                               var move_next = new StateMachineMethod (storey, this, new TypeExpression (ReturnType, loc), Modifiers.PUBLIC, new MemberName ("MoveNext", loc));
+                       if (!rc.IsInProbingMode) {
+                               var move_next = new StateMachineMethod (storey, this, new TypeExpression (ReturnType, loc), Modifiers.PUBLIC, new MemberName ("MoveNext", loc), 0);
                                move_next.Block.AddStatement (new MoveNextBodyStatement (this));
                                storey.AddEntryMethod (move_next);
                        }
 
+                       bc.AssignmentInfoOffset = ctx.AssignmentInfoOffset;
                        eclass = ExprClass.Value;
                        return this;
                }
@@ -923,6 +1005,11 @@ namespace Mono.CSharp
                                throw new NotSupportedException ();
                        }
 
+                       protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+                       {
+                               throw new NotSupportedException ();
+                       }
+
                        protected override void DoEmit (EmitContext ec)
                        {
                                //
@@ -930,7 +1017,7 @@ namespace Mono.CSharp
                                //
                                ec.CurrentAnonymousMethod = iterator;
 
-                               using (ec.With (BuilderContext.Options.OmitDebugInfo, false)) {
+                               using (ec.With (BuilderContext.Options.OmitDebugInfo, !ec.HasMethodSymbolBuilder)) {
                                        block.EmitFinallyBody (ec);
                                }
                        }
@@ -972,11 +1059,13 @@ namespace Mono.CSharp
                                Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedContainer.MakeName (null, null, "Finally", finally_hosts_counter++), loc),
                                ParametersCompiled.EmptyReadOnlyParameters, null);
 
-                       method.Block = new ToplevelBlock (method.Compiler, method.ParameterInfo, loc);
-                       method.Block.IsCompilerGenerated = true;
+                       method.Block = new ToplevelBlock (method.Compiler, method.ParameterInfo, loc,
+                               ToplevelBlock.Flags.CompilerGenerated | ToplevelBlock.Flags.NoFlowAnalysis);
                        method.Block.AddStatement (new TryFinallyBlockProxyStatement (this, block));
 
-                       storey.AddMember (method);
+                       // Cannot it add to storey because it'd be emitted before nested
+                       // anonoymous methods which could capture shared variable
+
                        return method;
                }
 
@@ -1015,11 +1104,13 @@ namespace Mono.CSharp
 
                public void EmitDispose (EmitContext ec)
                {
+                       if (resume_points == null)
+                               return;
+
                        Label end = ec.DefineLabel ();
 
                        Label[] labels = null;
-                       int n_resume_points = resume_points == null ? 0 : resume_points.Count;
-                       for (int i = 0; i < n_resume_points; ++i) {
+                       for (int i = 0; i < resume_points.Count; ++i) {
                                ResumableStatement s = resume_points[i];
                                Label ret = s.PrepareForDispose (ec, end);
                                if (ret.Equals (end) && labels == null)
@@ -1080,13 +1171,6 @@ namespace Mono.CSharp
                        ec.MarkLabel (resume_point);
                }
 
-               protected override BlockContext CreateBlockContext (ResolveContext rc)
-               {
-                       var bc = base.CreateBlockContext (rc);
-                       bc.StartFlowBranching (this, rc.CurrentBranching);
-                       return bc;
-               }
-
                public static void CreateIterator (IMethodData method, TypeDefinition parent, Modifiers modifiers)
                {
                        bool is_enumerable;
@@ -1101,7 +1185,7 @@ namespace Mono.CSharp
                                              "The body of `{0}' cannot be an iterator block " +
                                              "because `{1}' is not an iterator interface type",
                                              method.GetSignatureForError (),
-                                             TypeManager.CSharpName (ret));
+                                             ret.GetSignatureForError ());
                                return;
                        }