[csharp] repl using statement fix + support for --fatal
[mono.git] / mcs / mcs / statement.cs
index 06cfc04ea1f7bbc06dfd93f2699801e9580ad9e3..a639157ca423b056545d341371a7e0bbb9c73f82 100644 (file)
 //
 
 using System;
-using System.Text;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Diagnostics;
 using System.Collections.Generic;
 
+#if STATIC
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection.Emit;
+#endif
+
 namespace Mono.CSharp {
        
        public abstract class Statement {
@@ -1466,6 +1468,7 @@ namespace Mono.CSharp {
                        FixedVariable = 1 << 6,
                        UsingVariable = 1 << 7,
 //                     DefinitelyAssigned = 1 << 8,
+                       IsLocked = 1 << 9,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -1505,6 +1508,11 @@ namespace Mono.CSharp {
 
                #region Properties
 
+               public bool AddressTaken {
+                       get { return (flags & Flags.AddressTaken) != 0; }
+                       set { flags |= Flags.AddressTaken; }
+               }
+
                public Block Block {
                        get {
                                return block;
@@ -1544,6 +1552,15 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsLocked {
+                       get {
+                               return (flags & Flags.IsLocked) != 0;
+                       }
+                       set {
+                               flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
+                       }
+               }
+
                public bool IsThis {
                        get {
                                return (flags & Flags.IsThis) != 0;
@@ -1656,6 +1673,20 @@ namespace Mono.CSharp {
                        ec.Emit (OpCodes.Ldloca, builder);
                }
 
+               public string GetReadOnlyContext ()
+               {
+                       switch (flags & Flags.ReadonlyMask) {
+                       case Flags.FixedVariable:
+                               return "fixed variable";
+                       case Flags.ForeachVariable:
+                               return "foreach iteration variable";
+                       case Flags.UsingVariable:
+                               return "using variable";
+                       }
+
+                       throw new InternalErrorException ("Variable is not readonly");
+               }
+
                public bool IsThisAssigned (BlockContext ec, Block block)
                {
                        if (VariableInfo == null)
@@ -1695,29 +1726,10 @@ namespace Mono.CSharp {
                        flags |= Flags.Used;
                }
 
-               public bool AddressTaken {
-                       get { return (flags & Flags.AddressTaken) != 0; }
-                       set { flags |= Flags.AddressTaken; }
-               }
-
                public override string ToString ()
                {
                        return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
                }
-
-               public string GetReadOnlyContext ()
-               {
-                       switch (flags & Flags.ReadonlyMask) {
-                       case Flags.FixedVariable:
-                               return "fixed variable";
-                       case Flags.ForeachVariable:
-                               return "foreach iteration variable";
-                       case Flags.UsingVariable:
-                               return "using variable";
-                       }
-
-                       throw new InternalErrorException ("Variable is not readonly");
-               }
        }
 
        /// <summary>
@@ -2274,6 +2286,7 @@ namespace Mono.CSharp {
                        readonly ParametersBlock block;
                        readonly int index;
                        public VariableInfo VariableInfo;
+                       bool is_locked;
 
                        public ParameterInfo (ParametersBlock block, int index)
                        {
@@ -2295,6 +2308,15 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       public bool IsLocked {
+                               get {
+                                       return is_locked;
+                               }
+                               set {
+                                       is_locked = value;
+                               }
+                       }
+
                        public Location Location {
                                get {
                                        return Parameter.Location;
@@ -3068,6 +3090,9 @@ namespace Mono.CSharp {
 
                public SwitchLabel Clone (CloneContext clonectx)
                {
+                       if (label == null)
+                               return this;
+
                        return new SwitchLabel (label.Clone (clonectx), loc);
                }
        }
@@ -3086,7 +3111,7 @@ namespace Mono.CSharp {
                {
                        var cloned_labels = new List<SwitchLabel> ();
 
-                       foreach (SwitchLabel sl in cloned_labels)
+                       foreach (SwitchLabel sl in Labels)
                                cloned_labels.Add (sl.Clone (clonectx));
                        
                        return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
@@ -4088,20 +4113,37 @@ namespace Mono.CSharp {
                                ec.Report.Error (185, loc,
                                        "`{0}' is not a reference type as required by the lock statement",
                                        expr.Type.GetSignatureForError ());
-                               return false;
+                       }
+
+                       if (expr.Type.IsGenericParameter) {
+                               expr = Convert.ImplicitTypeParameterConversion (expr, TypeManager.object_type);
+                       }
+
+                       VariableReference lv = expr as VariableReference;
+                       bool locked;
+                       if (lv != null) {
+                               locked = lv.IsLockedByStatement;
+                               lv.IsLockedByStatement = true;
+                       } else {
+                               lv = null;
+                               locked = false;
                        }
 
                        ec.StartFlowBranching (this);
-                       bool ok = Statement.Resolve (ec);
+                       Statement.Resolve (ec);
                        ec.EndFlowBranching ();
 
-                       ok &= base.Resolve (ec);
+                       if (lv != null) {
+                               lv.IsLockedByStatement = locked;
+                       }
+
+                       base.Resolve (ec);
 
                        //
                        // Have to keep original lock value around to unlock same location
                        // in the case the original has changed or is null
                        //
-                       expr_copy = TemporaryVariableReference.Create (expr.Type, ec.CurrentBlock.Parent, loc);
+                       expr_copy = TemporaryVariableReference.Create (TypeManager.object_type, ec.CurrentBlock.Parent, loc);
                        expr_copy.Resolve (ec);
 
                        //
@@ -4112,13 +4154,25 @@ namespace Mono.CSharp {
                                lock_taken.Resolve (ec);
                        }
 
-                       return ok;
+                       return true;
                }
                
                protected override void EmitPreTryBody (EmitContext ec)
                {
                        expr_copy.EmitAssign (ec, expr);
-                       lock_taken.EmitAssign (ec, new BoolLiteral (false, loc));
+
+                       if (lock_taken != null) {
+                               //
+                               // Initialize ref variable
+                               //
+                               lock_taken.EmitAssign (ec, new BoolLiteral (false, loc));
+                       } else {
+                               //
+                               // Monitor.Enter (expr_copy)
+                               //
+                               expr_copy.Emit (ec);
+                               ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+                       }
                }
 
                protected override void EmitTryBody (EmitContext ec)
@@ -4126,15 +4180,13 @@ namespace Mono.CSharp {
                        //
                        // Monitor.Enter (expr_copy, ref lock_taken)
                        //
-                       expr_copy.Emit (ec);
-
                        if (lock_taken != null) {
+                               expr_copy.Emit (ec);
                                lock_taken.LocalInfo.CreateBuilder (ec);
                                lock_taken.AddressOf (ec, AddressOp.Load);
+                               ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
                        }
 
-                       ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
-
                        Statement.Emit (ec);
                }
 
@@ -4158,7 +4210,7 @@ namespace Mono.CSharp {
                int ResolvePredefinedMethods (ResolveContext rc)
                {
                        if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
-                               TypeSpec monitor_type = TypeManager.CoreLookupType (rc.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
+                               TypeSpec monitor_type = rc.Module.PredefinedTypes.Monitor.Resolve (loc);
 
                                if (monitor_type == null)
                                        return 0;
@@ -4351,8 +4403,11 @@ namespace Mono.CSharp {
                                pinned_string.Type = TypeManager.string_type;
 
                                if (TypeManager.int_get_offset_to_string_data == null) {
-                                       TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
-                                               TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+                                       var helper = rc.Module.PredefinedTypes.RuntimeHelpers.Resolve (loc);
+                                       if (helper != null) {
+                                               TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (helper,
+                                                       "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+                                       }
                                }
 
                                eclass = ExprClass.Variable;
@@ -4808,13 +4863,18 @@ namespace Mono.CSharp {
                        }
 
                        if (General != null) {
-                               if (CodeGen.Assembly.WrapNonExceptionThrows) {
-                                       foreach (Catch c in Specific){
-                                               if (c.CatchType == TypeManager.exception_type && ec.Compiler.PredefinedAttributes.RuntimeCompatibility.IsDefined) {
-                                                       ec.Report.Warning (1058, 1, c.loc,
-                                                               "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
-                                               }
-                                       }
+                               foreach (Catch c in Specific) {
+                                       if (c.CatchType != TypeManager.exception_type)
+                                               continue;
+
+                                       if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
+                                               continue;
+
+                                       if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
+                                               continue;
+
+                                       ec.Report.Warning (1058, 1, c.loc,
+                                               "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
                                }
 
                                ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
@@ -4913,14 +4973,15 @@ namespace Mono.CSharp {
                                return base.Resolve (bc);
                        }
 
-                       public void ResolveExpression (BlockContext bc)
+                       public Expression ResolveExpression (BlockContext bc)
                        {
                                var e = Initializer.Resolve (bc);
                                if (e == null)
-                                       return;
+                                       return null;
 
                                li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
                                Initializer = ResolveInitializer (bc, Variable, e);
+                               return e;
                        }
 
                        protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
@@ -5062,9 +5123,16 @@ namespace Mono.CSharp {
 
                public override bool Resolve (BlockContext ec)
                {
+                       VariableReference vr;
+                       bool vr_locked = false;
+
                        using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
                                if (decl.Variable == null) {
-                                       decl.ResolveExpression (ec);
+                                       vr = decl.ResolveExpression (ec) as VariableReference;
+                                       if (vr != null) {
+                                               vr_locked = vr.IsLockedByStatement;
+                                               vr.IsLockedByStatement = true;
+                                       }
                                } else {
                                        if (!decl.Resolve (ec))
                                                return false;
@@ -5072,18 +5140,23 @@ namespace Mono.CSharp {
                                        if (decl.Declarators != null) {
                                                stmt = decl.RewriteForDeclarators (ec, stmt);
                                        }
+
+                                       vr = null;
                                }
                        }
 
                        ec.StartFlowBranching (this);
 
-                       bool ok = stmt.Resolve (ec);
+                       stmt.Resolve (ec);
 
                        ec.EndFlowBranching ();
 
-                       ok &= base.Resolve (ec);
+                       if (vr != null)
+                               vr.IsLockedByStatement = vr_locked;
 
-                       return ok;
+                       base.Resolve (ec);
+
+                       return true;
                }
 
                protected override void CloneTo (CloneContext clonectx, Statement t)
@@ -5406,7 +5479,8 @@ namespace Mono.CSharp {
                                // Option 2: Try to match using IEnumerable interfaces with preference of generic version
                                //
                                TypeSpec iface_candidate = null;
-                               for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) {
+                               var t = expr.Type;
+                               do {
                                        var ifaces = t.Interfaces;
                                        if (ifaces != null) {
                                                foreach (var iface in ifaces) {
@@ -5429,7 +5503,13 @@ namespace Mono.CSharp {
                                                        }
                                                }
                                        }
-                               }
+
+                                       if (t.IsGenericParameter)
+                                               t = t.BaseType;
+                                       else
+                                               t = null;
+
+                               } while (t != null);
 
                                if (iface_candidate == null) {
                                        rc.Report.Error (1579, loc,