Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / mcs / context.cs
index 24fedc69d5af002fc03062cfb84cae10857607f7..8cbaeff0c5464d7956eebd1f5039ffa632e52e83 100644 (file)
@@ -13,6 +13,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Security.Cryptography;
 
 namespace Mono.CSharp
 {
@@ -68,11 +69,12 @@ namespace Mono.CSharp
        //
        public class BlockContext : ResolveContext
        {
-               FlowBranching current_flow_branching;
-
                readonly TypeSpec return_type;
 
-               public int FlowOffset;
+               //
+               // Tracks the last offset used by VariableInfo
+               //
+               public int AssignmentInfoOffset;
 
                public BlockContext (IMemberContext mc, ExplicitBlock block, TypeSpec returnType)
                        : base (mc)
@@ -94,108 +96,34 @@ namespace Mono.CSharp
 
                        if (rc.HasSet (ResolveContext.Options.CheckedScope))
                                flags |= ResolveContext.Options.CheckedScope;
-               }
-
-               public override FlowBranching CurrentBranching {
-                       get { return current_flow_branching; }
-               }
 
-               public TypeSpec ReturnType {
-                       get { return return_type; }
-               }
+                       if (!rc.ConstantCheckState)
+                               flags &= ~Options.ConstantCheckState;
 
-               // <summary>
-               //   Starts a new code branching.  This inherits the state of all local
-               //   variables and parameters from the current branching.
-               // </summary>
-               public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
-               {
-                       current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
-                       return current_flow_branching;
-               }
+                       if (rc.IsInProbingMode)
+                               flags |= ResolveContext.Options.ProbingMode;
 
-               // <summary>
-               //   Starts a new code branching for block `block'.
-               // </summary>
-               public FlowBranching StartFlowBranching (Block block)
-               {
-                       Set (Options.DoFlowAnalysis);
+                       if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
+                               flags |= ResolveContext.Options.FieldInitializerScope;
 
-                       current_flow_branching = FlowBranching.CreateBranching (
-                               CurrentBranching, FlowBranching.BranchingType.Block, block, block.StartLocation);
-                       return current_flow_branching;
-               }
+                       if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
+                               flags |= ResolveContext.Options.ExpressionTreeConversion;
 
-               public FlowBranchingTryCatch StartFlowBranching (TryCatch stmt)
-               {
-                       FlowBranchingTryCatch branching = new FlowBranchingTryCatch (CurrentBranching, stmt);
-                       current_flow_branching = branching;
-                       return branching;
+                       if (rc.HasSet (ResolveContext.Options.BaseInitializer))
+                               flags |= ResolveContext.Options.BaseInitializer;
                }
 
-               public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
-               {
-                       FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
-                       current_flow_branching = branching;
-                       return branching;
-               }
+               public ExceptionStatement CurrentTryBlock { get; set; }
 
-               public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
-               {
-                       FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
-                       current_flow_branching = branching;
-                       return branching;
-               }
+               public LoopStatement EnclosingLoop { get; set; }
 
-               public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
-               {
-                       FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
-                       current_flow_branching = branching;
-                       return branching;
-               }
+               public LoopStatement EnclosingLoopOrSwitch { get; set; }
 
-               public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
-               {
-                       var branching = new FlowBranchingAsync (parent, asyncBody);
-                       current_flow_branching = branching;
-                       return branching;
-               }
+               public Switch Switch { get; set; }
 
-               public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
-               {
-                       FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
-                       current_flow_branching = branching;
-                       return branching;
-               }
-
-               // <summary>
-               //   Ends a code branching.  Merges the state of locals and parameters
-               //   from all the children of the ending branching.
-               // </summary>
-               public bool EndFlowBranching ()
-               {
-                       FlowBranching old = current_flow_branching;
-                       current_flow_branching = current_flow_branching.Parent;
-
-                       FlowBranching.UsageVector vector = current_flow_branching.MergeChild (old);
-                       return vector.IsUnreachable;
-               }
-
-               // <summary>
-               //   Kills the current code branching.  This throws away any changed state
-               //   information and should only be used in case of an error.
-               // </summary>
-               // FIXME: this is evil
-               public void KillFlowBranching ()
-               {
-                       current_flow_branching = current_flow_branching.Parent;
-               }
-
-#if !STATIC
-               public void NeedReturnLabel ()
-               {
+               public TypeSpec ReturnType {
+                       get { return return_type; }
                }
-#endif
        }
 
        //
@@ -256,16 +184,9 @@ namespace Mono.CSharp
 
                        LockScope = 1 << 13,
 
-                       /// <summary>
-                       ///   Whether control flow analysis is enabled
-                       /// </summary>
-                       DoFlowAnalysis = 1 << 20,
+                       TryScope = 1 << 14,
 
-                       /// <summary>
-                       ///   Whether control flow analysis is disabled on structs
-                       ///   (only meaningful when DoFlowAnalysis is set)
-                       /// </summary>
-                       OmitStructFlowAnalysis = 1 << 21,
+                       TryWithCatchScope = 1 << 15,
 
                        ///
                        /// Indicates the current context is in probing mode, no errors are reported. 
@@ -290,7 +211,7 @@ namespace Mono.CSharp
                // it's public so that we can use a struct at the callsite
                public struct FlagsHandle : IDisposable
                {
-                       ResolveContext ec;
+                       readonly ResolveContext ec;
                        readonly Options invmask, oldval;
 
                        public FlagsHandle (ResolveContext ec, Options flagsToSet)
@@ -334,11 +255,6 @@ namespace Mono.CSharp
 
                public readonly IMemberContext MemberContext;
 
-               /// <summary>
-               ///   If this is non-null, points to the current switch statement
-               /// </summary>
-               public Switch Switch;
-
                public ResolveContext (IMemberContext mc)
                {
                        if (mc == null)
@@ -378,10 +294,6 @@ namespace Mono.CSharp
                        }
                }
 
-               public virtual FlowBranching CurrentBranching {
-                       get { return null; }
-               }
-
                //
                // The current iterator
                //
@@ -405,10 +317,6 @@ namespace Mono.CSharp
                        get { return (flags & Options.ConstantCheckState) != 0; }
                }
 
-               public bool DoFlowAnalysis {
-                       get { return (flags & Options.DoFlowAnalysis) != 0; }
-               }
-
                public bool IsInProbingMode {
                        get {
                                return (flags & Options.ProbingMode) != 0;
@@ -442,7 +350,7 @@ namespace Mono.CSharp
 
                public bool IsVariableCapturingRequired {
                        get {
-                               return !IsInProbingMode && (CurrentBranching == null || !CurrentBranching.CurrentUsageVector.IsUnreachable);
+                               return !IsInProbingMode;
                        }
                }
 
@@ -452,10 +360,6 @@ namespace Mono.CSharp
                        }
                }
 
-               public bool OmitStructFlowAnalysis {
-                       get { return (flags & Options.OmitStructFlowAnalysis) != 0; }
-               }
-
                public Report Report {
                        get {
                                return Module.Compiler.Report;
@@ -474,14 +378,16 @@ namespace Mono.CSharp
                        // or it's a parameter
                        //
                        if (CurrentAnonymousMethod.IsIterator)
-                               return local.IsParameter || CurrentBlock.Explicit.HasYield;
+                               return local.IsParameter || local.Block.Explicit.HasYield;
 
                        //
                        // Capture only if this or any of child blocks contain await
-                       // or it's a parameter
+                       // or it's a parameter or we need to access variable from 
+                       // different parameter block
                        //
                        if (CurrentAnonymousMethod is AsyncInitializer)
-                               return CurrentBlock.Explicit.HasAwait;
+                               return local.IsParameter || local.Block.Explicit.HasAwait || CurrentBlock.Explicit.HasAwait ||
+                                       local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
 
                        return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
                }
@@ -533,6 +439,72 @@ namespace Mono.CSharp
                #endregion
        }
 
+       public class FlowAnalysisContext
+       {
+               readonly CompilerContext ctx;
+
+               public FlowAnalysisContext (CompilerContext ctx, ParametersBlock parametersBlock, int definiteAssignmentLength)
+               {
+                       this.ctx = ctx;
+                       this.ParametersBlock = parametersBlock;
+
+                       DefiniteAssignment = definiteAssignmentLength == 0 ?
+                               DefiniteAssignmentBitSet.Empty :
+                               new DefiniteAssignmentBitSet (definiteAssignmentLength);
+               }
+
+               public DefiniteAssignmentBitSet DefiniteAssignment { get; set; }
+
+               public DefiniteAssignmentBitSet DefiniteAssignmentOnTrue { get; set; }
+
+               public DefiniteAssignmentBitSet DefiniteAssignmentOnFalse { get; set; }
+
+               public List<LabeledStatement> LabelStack { get; set; }
+
+               public ParametersBlock ParametersBlock { get; set; }
+
+               public Report Report {
+                       get {
+                               return ctx.Report;
+                       }
+               }
+
+               public DefiniteAssignmentBitSet SwitchInitialDefinitiveAssignment { get; set; }
+
+               public TryFinally TryFinally { get; set; }
+
+               public bool UnreachableReported { get; set; }
+
+               public DefiniteAssignmentBitSet BranchDefiniteAssignment ()
+               {
+                       var dat = DefiniteAssignment;
+                       if (dat != DefiniteAssignmentBitSet.Empty)
+                               DefiniteAssignment = new DefiniteAssignmentBitSet (dat);
+                       return dat;
+               }
+
+               public bool IsDefinitelyAssigned (VariableInfo variable)
+               {
+                       return variable.IsAssigned (DefiniteAssignment);
+               }
+
+               public bool IsStructFieldDefinitelyAssigned (VariableInfo variable, string name)
+               {
+                       return variable.IsStructFieldAssigned (DefiniteAssignment, name);
+               }
+
+               public void SetVariableAssigned (VariableInfo variable, bool generatedAssignment = false)
+               {
+                       variable.SetAssigned (DefiniteAssignment, generatedAssignment);
+               }
+
+               public void SetStructFieldAssigned (VariableInfo variable, string name)
+               {
+                       variable.SetStructFieldAssigned (DefiniteAssignment, name);
+               }
+       }
+
+
        //
        // This class is used during the Statement.Clone operation
        // to remap objects that have been cloned.
@@ -586,10 +558,10 @@ namespace Mono.CSharp
 
                Dictionary<string, SourceFile> all_source_files;
 
-               public CompilerContext (CompilerSettings settings, Report report)
+               public CompilerContext (CompilerSettings settings, ReportPrinter reportPrinter)
                {
                        this.settings = settings;
-                       this.report = report;
+                       this.report = new Report (this, reportPrinter);
                        this.builtin_types = new BuiltinTypes ();
                        this.TimeReporter = DisabledTimeReporter;
                }
@@ -620,7 +592,7 @@ namespace Mono.CSharp
                        }
                }
 
-               public List<CompilationSourceFile> SourceFiles {
+               public List<SourceFile> SourceFiles {
                        get {
                                return settings.SourceFiles;
                        }
@@ -646,8 +618,12 @@ namespace Mono.CSharp
 
                        string path;
                        if (!Path.IsPathRooted (name)) {
-                               string root = Path.GetDirectoryName (comp_unit.FullPathName);
-                               path = Path.Combine (root, name);
+                               var loc = comp_unit.SourceFile;
+                               string root = Path.GetDirectoryName (loc.FullPathName);
+                               path = Path.GetFullPath (Path.Combine (root, name));
+                               var dir = Path.GetDirectoryName (loc.Name);
+                               if (!string.IsNullOrEmpty (dir))
+                                       name = Path.Combine (dir, name);
                        } else
                                path = name;
 
@@ -655,7 +631,8 @@ namespace Mono.CSharp
                        if (all_source_files.TryGetValue (path, out retval))
                                return retval;
 
-                       retval = Location.AddFile (name, path);
+                       retval = new SourceFile (name, path, all_source_files.Count + 1);
+                       Location.AddFile (retval);
                        all_source_files.Add (path, retval);
                        return retval;
                }
@@ -681,6 +658,8 @@ namespace Mono.CSharp
                        /// </summary>
                        CheckedScope = 1 << 0,
 
+                       AccurateDebugInfo = 1 << 1,
+
                        OmitDebugInfo = 1 << 2,
 
                        ConstructorScope = 1 << 3,
@@ -692,7 +671,7 @@ namespace Mono.CSharp
                // it's public so that we can use a struct at the callsite
                public struct FlagsHandle : IDisposable
                {
-                       BuilderContext ec;
+                       readonly BuilderContext ec;
                        readonly Options invmask, oldval;
 
                        public FlagsHandle (BuilderContext ec, Options flagsToSet)
@@ -727,4 +706,28 @@ namespace Mono.CSharp
                        return new FlagsHandle (this, options, enable ? options : 0);
                }
        }
+
+       //
+       // Parser session objects. We could recreate all these objects for each parser
+       // instance but the best parser performance the session object can be reused
+       //
+       public class ParserSession
+       {
+               MD5 md5;
+
+               public readonly char[] StreamReaderBuffer = new char[SeekableStreamReader.DefaultReadAheadSize * 2];
+               public readonly Dictionary<char[], string>[] Identifiers = new Dictionary<char[], string>[Tokenizer.MaxIdentifierLength + 1];
+               public readonly List<Parameter> ParametersStack = new List<Parameter> (4);
+               public readonly char[] IDBuilder = new char[Tokenizer.MaxIdentifierLength];
+               public readonly char[] NumberBuilder = new char[Tokenizer.MaxNumberLength];
+
+               public LocationsBag LocationsBag { get; set; }
+               public bool UseJayGlobalArrays { get; set; }
+               public LocatedToken[] LocatedTokens { get; set; }
+
+               public MD5 GetChecksumAlgorithm ()
+               {
+                       return md5 ?? (md5 = MD5.Create ());
+               }
+       }
 }