2005-05-31 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / mcs / statement.cs
index c09a0a74b4cdda5e746c2317c9593b052a7fff47..94f3c98fd52672ad8260b827deea05935aaa1297 100644 (file)
@@ -917,7 +917,7 @@ namespace Mono.CSharp {
                        } else if (ec.CurrentBranching.InTryOrCatch (false))
                                ec.CurrentBranching.AddFinallyVector (
                                        ec.CurrentBranching.CurrentUsageVector);
-                       else if (ec.CurrentBranching.InLoop ())
+                       else if (ec.CurrentBranching.InLoop () || ec.CurrentBranching.InSwitch ())
                                ec.CurrentBranching.AddBreakVector (
                                        ec.CurrentBranching.CurrentUsageVector);
 
@@ -1012,7 +1012,14 @@ namespace Mono.CSharp {
                        AddressTaken = 32
                }
 
+               public enum ReadOnlyContext: byte {
+                       Using,
+                       Foreach,
+                       Fixed
+               }
+
                Flags flags;
+               ReadOnlyContext ro_context;
                
                public LocalInfo (Expression type, string name, Block block, Location l)
                {
@@ -1126,9 +1133,28 @@ namespace Mono.CSharp {
                        get {
                                return (flags & Flags.ReadOnly) != 0;
                        }
-                       set {
-                               flags = value ? (flags | Flags.ReadOnly) : (unchecked (flags & ~Flags.ReadOnly));
+               }
+
+               public void SetReadOnlyContext (ReadOnlyContext context)
+               {
+                       flags |= Flags.ReadOnly;
+                       ro_context = context;
+               }
+
+               public string GetReadOnlyContext ()
+               {
+                       if (!ReadOnly)
+                               throw new InternalErrorException ("Variable is not readonly");
+
+                       switch (ro_context) {
+                               case ReadOnlyContext.Fixed:
+                                       return "fixed variable";
+                               case ReadOnlyContext.Foreach:
+                                       return "foreach iteration variable";
+                               case ReadOnlyContext.Using:
+                                       return "using variable";
                        }
+                       throw new NotImplementedException ();
                }
 
                //
@@ -1548,7 +1574,7 @@ namespace Mono.CSharp {
                        int idx;
                        Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
                        if (p != null) {
-                               Report.SymbolRelatedToPreviousError (Toplevel.Parameters.Location, name);
+                               Report.SymbolRelatedToPreviousError (p.Location, name);
                                Report.Error (136, l, "'{0}' hides a method parameter", name);
                                return null;
                        }
@@ -1631,49 +1657,6 @@ namespace Mono.CSharp {
                        return e != null;
                }
 
-               //
-               // Returns a `ParameterReference' for the given name, or null if there
-               // is no such parameter
-               //
-               public ParameterReference GetParameterReference (string name, Location loc)
-               {
-                       Parameter par;
-                       int idx;
-
-                       for (Block b = this; b != null; b = b.Toplevel.Parent) {
-                               Parameters pars = b.Toplevel.Parameters;
-                               par = pars.GetParameterByName (name, out idx);
-                               if (par != null)
-                                       return new ParameterReference (pars, this, idx, name, loc);
-                       }
-                       return null;
-               }
-
-               //
-               // Whether the parameter named `name' is local to this block, 
-               // or false, if the parameter belongs to an encompassing block.
-               //
-               public bool IsLocalParameter (string name)
-               {
-                       return Toplevel.Parameters.GetParameterByName (name) != null;
-               }
-               
-               //
-               // Whether the `name' is a parameter reference
-               //
-               public bool IsParameterReference (string name)
-               {
-                       Parameter par;
-                       int idx;
-
-                       for (Block b = this; b != null; b = b.Toplevel.Parent) {
-                               par = b.Toplevel.Parameters.GetParameterByName (name, out idx);
-                               if (par != null)
-                                       return true;
-                       }
-                       return false;
-               }
-               
                /// <returns>
                ///   A list of labels that were not used within this block
                /// </returns>
@@ -1931,42 +1914,42 @@ namespace Mono.CSharp {
 
                        Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
 
-                       //
-                       // This flag is used to notate nested statements as unreachable from the beginning of this block.
-                       // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
-                       // from the beginning of the function.  The outer Resolve() that detected the unreachability is
-                       // responsible for handling the situation.
-                       //
                        int statement_count = statements.Count;
                        for (int ix = 0; ix < statement_count; ix++){
                                Statement s = (Statement) statements [ix];
 
-                               if (unreachable && !(s is LabeledStatement)) {
-                                       if (s == EmptyStatement.Value)
-                                               s.loc = EndLocation;
-
-                                       if (!s.ResolveUnreachable (ec, !unreachable_shown))
-                                               ok = false;
+                               //
+                               // Warn if we detect unreachable code.
+                               //
+                               if (unreachable) {
+                                       if (s is Block)
+                                               ((Block) s).unreachable = true;
 
-                                       if (s != EmptyStatement.Value)
+                                       if (!unreachable_shown && (RootContext.WarningLevel >= 2)) {
+                                               Report.Warning (
+                                                       162, loc, "Unreachable code detected");
                                                unreachable_shown = true;
-                                       else
-                                               s.loc = Location.Null;
-
-                                       if (ok && !(s is Block)) {
-                                               statements [ix] = EmptyStatement.Value;
-                                               continue;
                                        }
                                }
 
-                               if (s.Resolve (ec) == false) {
-                                       ok = false;
+                               //
+                               // Note that we're not using ResolveUnreachable() for unreachable
+                               // statements here.  ResolveUnreachable() creates a temporary
+                               // flow branching and kills it afterwards.  This leads to problems
+                               // if you have two unreachable statements where the first one
+                               // assigns a variable and the second one tries to access it.
+                               //
+
+                               if (!s.Resolve (ec)) {
+                                       ok = false;
                                        statements [ix] = EmptyStatement.Value;
                                        continue;
                                }
 
-                               num_statements = ix + 1;
+                               if (unreachable && !(s is LabeledStatement) && !(s is Block))
+                                       statements [ix] = EmptyStatement.Value;
 
+                               num_statements = ix + 1;
                                if (s is LabeledStatement)
                                        unreachable = false;
                                else
@@ -2013,15 +1996,11 @@ namespace Mono.CSharp {
                public override bool ResolveUnreachable (EmitContext ec, bool warn)
                {
                        unreachable_shown = true;
+                       unreachable = true;
 
                        if (warn && (RootContext.WarningLevel >= 2))
                                Report.Warning (162, loc, "Unreachable code detected");
 
-                       if (Implicit)
-                               return Resolve (ec);
-
-                       unreachable = true;
-
                        ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
                        bool ok = Resolve (ec);
                        ec.KillFlowBranching ();
@@ -2198,6 +2177,48 @@ namespace Mono.CSharp {
                        }
                }
 
+               //
+               // Returns a `ParameterReference' for the given name, or null if there
+               // is no such parameter
+               //
+               public ParameterReference GetParameterReference (string name, Location loc)
+               {
+                       Parameter par;
+                       int idx;
+
+                       for (ToplevelBlock t = this; t != null; t = t.Container) {
+                               Parameters pars = t.Parameters;
+                               par = pars.GetParameterByName (name, out idx);
+                               if (par != null)
+                                       return new ParameterReference (pars, this, idx, name, loc);
+                       }
+                       return null;
+               }
+
+               //
+               // Whether the parameter named `name' is local to this block, 
+               // or false, if the parameter belongs to an encompassing block.
+               //
+               public bool IsLocalParameter (string name)
+               {
+                       return Parameters.GetParameterByName (name) != null;
+               }
+               
+               //
+               // Whether the `name' is a parameter reference
+               //
+               public bool IsParameterReference (string name)
+               {
+                       Parameter par;
+                       int idx;
+
+                       for (ToplevelBlock t = this; t != null; t = t.Container) {
+                               if (t.IsLocalParameter (name))
+                                       return true;
+                       }
+                       return false;
+               }
+
                public bool ResolveMeta (EmitContext ec, InternalParameters ip)
                {
                        int errors = Report.Errors;
@@ -3417,7 +3438,7 @@ namespace Mono.CSharp {
                                Expression e = (Expression) p.Second;
 
                                vi.VariableInfo.SetAssigned (ec);
-                               vi.ReadOnly = true;
+                               vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
 
                                //
                                // The rules for the possible declarators are pretty wise,
@@ -3855,7 +3876,7 @@ namespace Mono.CSharp {
                        foreach (DictionaryEntry e in var_list){
                                Expression var = (Expression) e.Key;
 
-                               var = var.ResolveLValue (ec, new EmptyExpression ());
+                               var = var.ResolveLValue (ec, new EmptyExpression (), loc);
                                if (var == null)
                                        return false;
 
@@ -4201,7 +4222,7 @@ namespace Mono.CSharp {
                        if (conv == null)
                                ok = false;
 
-                       variable = variable.ResolveLValue (ec, empty);
+                       variable = variable.ResolveLValue (ec, empty, loc);
                        if (variable == null)
                                ok = false;
 
@@ -4794,7 +4815,7 @@ namespace Mono.CSharp {
                                ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
                                ec.CurrentBranching.CreateSibling ();
 
-                               variable = variable.ResolveLValue (ec, conv);
+                               variable = variable.ResolveLValue (ec, conv, loc);
                                if (variable == null)
                                        ok = false;