X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fstatement.cs;h=e2d0752152fda1a988d891c25d17076a686d6865;hb=43b6678d45b2cf3705971998e1f04f67ef4d7667;hp=7d70945eca849c1b7146c0755aaf7a127d440dbb;hpb=b585d00928892398dfbfc315ed78b8032fa14708;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 7d70945eca8..e2d0752152f 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -4,6 +4,7 @@ // Author: // Miguel de Icaza (miguel@ximian.com) // Martin Baulig (martin@ximian.com) +// Marek Safar (marek.safar@seznam.cz) // // (C) 2001, 2002, 2003 Ximian, Inc. // (C) 2003, 2004 Novell, Inc. @@ -97,7 +98,12 @@ namespace Mono.CSharp { { return true; } - + + public override bool ResolveUnreachable (EmitContext ec, bool warn) + { + return true; + } + protected override void DoEmit (EmitContext ec) { } @@ -253,8 +259,15 @@ namespace Mono.CSharp { ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); + bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable; + + ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); if (!EmbeddedStatement.Resolve (ec)) ok = false; + ec.EndFlowBranching (); + + if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable && !was_unreachable) + Report.Warning (162, 2, expr.Location, "Unreachable code detected"); expr = Expression.ResolveBoolean (ec, expr, loc); if (expr == null) @@ -265,8 +278,9 @@ namespace Mono.CSharp { if (res) infinite = true; } + if (infinite) + ec.CurrentBranching.CurrentUsageVector.Goto (); - ec.CurrentBranching.Infinite = infinite; ec.EndFlowBranching (); return ok; @@ -343,10 +357,14 @@ namespace Mono.CSharp { if (!infinite) ec.CurrentBranching.CreateSibling (); + ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); if (!Statement.Resolve (ec)) ok = false; + ec.EndFlowBranching (); + + // There's no direct control flow from the end of the embedded statement to the end of the loop + ec.CurrentBranching.CurrentUsageVector.Goto (); - ec.CurrentBranching.Infinite = infinite; ec.EndFlowBranching (); return ok; @@ -451,15 +469,26 @@ namespace Mono.CSharp { if (!infinite) ec.CurrentBranching.CreateSibling (); + bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable; + + ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); if (!Statement.Resolve (ec)) ok = false; + ec.EndFlowBranching (); if (Increment != null){ - if (!Increment.Resolve (ec)) - ok = false; + if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable) { + if (!Increment.ResolveUnreachable (ec, !was_unreachable)) + ok = false; + } else { + if (!Increment.Resolve (ec)) + ok = false; + } } - ec.CurrentBranching.Infinite = infinite; + // There's no direct control flow from the end of the embedded statement to the end of the loop + ec.CurrentBranching.CurrentUsageVector.Goto (); + ec.EndFlowBranching (); return ok; @@ -554,7 +583,7 @@ namespace Mono.CSharp { loc = l; } - bool in_exc; + bool unwind_protect; public override bool Resolve (EmitContext ec) { @@ -595,22 +624,12 @@ namespace Mono.CSharp { } } - FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector; - - if (ec.CurrentBranching.InTryOrCatch (true)) { - ec.CurrentBranching.AddFinallyVector (vector); - in_exc = true; - } else if (ec.InFinally) { - Error (157, "Control cannot leave the body of a finally clause"); - return false; - } else - vector.CheckOutParameters (ec.CurrentBranching); - - if (in_exc) + int errors = Report.Errors; + unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc); + if (unwind_protect) ec.NeedReturnLabel (); - ec.CurrentBranching.CurrentUsageVector.Return (); - return true; + return errors == Report.Errors; } protected override void DoEmit (EmitContext ec) @@ -618,11 +637,11 @@ namespace Mono.CSharp { if (Expr != null) { Expr.Emit (ec); - if (in_exc) + if (unwind_protect) ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); } - if (in_exc) + if (unwind_protect) ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel); else ec.ig.Emit (OpCodes.Ret); @@ -632,21 +651,14 @@ namespace Mono.CSharp { public class Goto : Statement { string target; LabeledStatement label; + bool unwind_protect; public override bool Resolve (EmitContext ec) { - label = ec.CurrentBranching.LookupLabel (target, loc); - if (label == null) - return false; - - // If this is a forward goto. - if (!label.IsDefined) - label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector); - + int errors = Report.Errors; + unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this); ec.CurrentBranching.CurrentUsageVector.Goto (); - label.AddReference (); - - return true; + return errors == Report.Errors; } public Goto (string label, Location l) @@ -656,19 +668,26 @@ namespace Mono.CSharp { } public string Target { - get { - return target; - } + get { return target; } + } + + public void SetResolvedTarget (LabeledStatement label) + { + this.label = label; + label.AddReference (); } protected override void DoEmit (EmitContext ec) { + if (label == null) + throw new InternalErrorException ("goto emitted before target resolved"); Label l = label.LabelTarget (ec); - ec.ig.Emit (OpCodes.Br, l); + ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l); } } public class LabeledStatement : Statement { + string name; bool defined; bool referenced; Label label; @@ -676,8 +695,9 @@ namespace Mono.CSharp { FlowBranching.UsageVector vectors; - public LabeledStatement (string label_name, Location l) + public LabeledStatement (string name, Location l) { + this.name = name; this.loc = l; } @@ -692,16 +712,20 @@ namespace Mono.CSharp { return label; } + public string Name { + get { return name; } + } + public bool IsDefined { - get { - return defined; - } + get { return defined; } } public bool HasBeenReferenced { - get { - return referenced; - } + get { return referenced; } + } + + public FlowBranching.UsageVector JumpOrigins { + get { return vectors; } } public void AddUsageVector (FlowBranching.UsageVector vector) @@ -713,18 +737,15 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - ec.CurrentBranching.Label (vectors); - + // this flow-branching will be terminated when the surrounding block ends + ec.StartFlowBranching (this); return true; } protected override void DoEmit (EmitContext ec) { - if (ig != null && ig != ec.ig) { - // TODO: location is wrong - Report.Error (1632, loc, "Control cannot leave the body of an anonymous method"); - return; - } + if (ig != null && ig != ec.ig) + throw new InternalErrorException ("cannot happen"); LabelTarget (ec); ec.ig.MarkLabel (label); } @@ -797,11 +818,22 @@ namespace Mono.CSharp { return false; } - c = c.ToType (ec.Switch.SwitchType, loc); - if (c == null) - return false; + Type type = ec.Switch.SwitchType; + if (!Convert.ImplicitStandardConversionExists (c, type)) + Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " + + "convertible to type `{0}'", TypeManager.CSharpName (type)); + bool fail = false; object val = c.GetValue (); + if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type)) + val = TypeManager.ChangeType (val, type, out fail); + + if (fail) { + Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'", + c.GetSignatureForError (), TypeManager.CSharpName (type)); + return false; + } + if (val == null) val = SwitchLabel.NullStringCase; @@ -844,15 +876,15 @@ namespace Mono.CSharp { if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { - expr.Error_UnexpectedKind (ec, "value, variable, property or indexer access ", loc); + expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc); return false; } Type t = expr.Type; if ((t != TypeManager.exception_type) && - !t.IsSubclassOf (TypeManager.exception_type) && - !(expr is NullLiteral)) { + !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && + !(expr is NullLiteral)) { Error (155, "The type caught or thrown must be derived " + "from System.Exception"); @@ -892,41 +924,19 @@ namespace Mono.CSharp { loc = l; } - bool crossing_exc; + bool unwind_protect; public override bool Resolve (EmitContext ec) { - if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ - Error (139, "No enclosing loop out of which to break or continue"); - return false; - } else if (ec.InFinally && ec.CurrentBranching.BreakCrossesTryCatchBoundary()) { - Error (157, "Control cannot leave the body of a finally clause"); - return false; - } else if (ec.CurrentBranching.InTryOrCatch (false)) - ec.CurrentBranching.AddFinallyVector ( - ec.CurrentBranching.CurrentUsageVector); - else if (ec.CurrentBranching.InLoop () || ec.CurrentBranching.InSwitch ()) - ec.CurrentBranching.AddBreakVector ( - ec.CurrentBranching.CurrentUsageVector); - - crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary (); - - if (!crossing_exc) - ec.NeedReturnLabel (); - - ec.CurrentBranching.CurrentUsageVector.Break (); - return true; + int errors = Report.Errors; + unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc); + ec.CurrentBranching.CurrentUsageVector.Goto (); + return errors == Report.Errors; } protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (crossing_exc) - ig.Emit (OpCodes.Leave, ec.LoopEnd); - else { - ig.Emit (OpCodes.Br, ec.LoopEnd); - } + ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd); } } @@ -937,53 +947,51 @@ namespace Mono.CSharp { loc = l; } - bool crossing_exc; + bool unwind_protect; public override bool Resolve (EmitContext ec) { - if (!ec.CurrentBranching.InLoop ()){ - Error (139, "No enclosing loop out of which to break or continue"); - return false; - } else if (ec.InFinally) { - Error (157, "Control cannot leave the body of a finally clause"); - return false; - } else if (ec.CurrentBranching.InTryOrCatch (false)) - ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector); - - crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary (); - + int errors = Report.Errors; + unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); - return true; + return errors == Report.Errors; } protected override void DoEmit (EmitContext ec) { - Label begin = ec.LoopBegin; - - if (crossing_exc) - ec.ig.Emit (OpCodes.Leave, begin); - else - ec.ig.Emit (OpCodes.Br, begin); + ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); } } + public abstract class Variable + { + public abstract Type Type { + get; + } + + public abstract bool HasInstance { + get; + } + + public abstract bool NeedsTemporary { + get; + } + + public abstract void EmitInstance (EmitContext ec); + + public abstract void Emit (EmitContext ec); + + public abstract void EmitAssign (EmitContext ec); + + public abstract void EmitAddressOf (EmitContext ec); + } + // // The information about a user-perceived local variable // public class LocalInfo { public Expression Type; - // - // Most of the time a variable will be stored in a LocalBuilder - // - // But sometimes, it will be stored in a field (variables that have been - // hoisted by iterators or by anonymous methods). The context of the field will - // be stored in the EmitContext - // - // - public LocalBuilder LocalBuilder; - public FieldBuilder FieldBuilder; - public Type VariableType; public readonly string Name; public readonly Location Location; @@ -991,6 +999,12 @@ namespace Mono.CSharp { public VariableInfo VariableInfo; + Variable var; + public Variable Variable { + get { return var; } + } + + [Flags] enum Flags : byte { Used = 1, ReadOnly = 2, @@ -998,7 +1012,8 @@ namespace Mono.CSharp { IsThis = 8, Captured = 16, AddressTaken = 32, - CompilerGenerated = 64 + CompilerGenerated = 64, + IsConstant = 128 } public enum ReadOnlyContext: byte { @@ -1009,6 +1024,7 @@ namespace Mono.CSharp { Flags flags; ReadOnlyContext ro_context; + LocalBuilder builder; public LocalInfo (Expression type, string name, Block block, Location l) { @@ -1018,13 +1034,39 @@ namespace Mono.CSharp { Location = l; } - public LocalInfo (TypeContainer tc, Block block, Location l) + public LocalInfo (DeclSpace ds, Block block, Location l) { - VariableType = tc.TypeBuilder; + VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder; Block = block; Location = l; } + public void ResolveVariable (EmitContext ec) + { + Block theblock = Block; + if (theblock.ScopeInfo != null) + var = theblock.ScopeInfo.GetCapturedVariable (this); + + if (var == null) { + if (Pinned) + // + // This is needed to compile on both .NET 1.x and .NET 2.x + // the later introduced `DeclareLocal (Type t, bool pinned)' + // + builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType); + else + builder = ec.ig.DeclareLocal (VariableType); + + var = new LocalVariable (this, builder); + } + } + + public void EmitSymbolInfo (EmitContext ec, string name) + { + if (builder != null) + ec.DefineLocalVariable (name, builder); + } + public bool IsThisAssigned (EmitContext ec, Location loc) { if (VariableInfo == null) @@ -1051,17 +1093,16 @@ namespace Mono.CSharp { if (texpr == null) return false; - VariableType = texpr.ResolveType (ec); + VariableType = texpr.Type; } if (VariableType == TypeManager.void_type) { - Report.Error (1547, Location, - "Keyword 'void' cannot be used in this context"); + Expression.Error_VoidInvalidInTheContext (Location); return false; } if (VariableType.IsAbstract && VariableType.IsSealed) { - Report.Error (723, Location, "Cannot declare variable of static type `{0}'", TypeManager.CSharpName (VariableType)); + FieldMember.Error_VariableOfStaticClass (Location, Name, VariableType); return false; } @@ -1081,6 +1122,15 @@ namespace Mono.CSharp { } } + public bool IsConstant { + get { + return (flags & Flags.IsConstant) != 0; + } + set { + flags |= Flags.IsConstant; + } + } + public bool AddressTaken { get { return (flags & Flags.AddressTaken) != 0; @@ -1165,6 +1215,50 @@ namespace Mono.CSharp { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); } } + + protected class LocalVariable : Variable + { + public readonly LocalInfo LocalInfo; + LocalBuilder builder; + + public LocalVariable (LocalInfo local, LocalBuilder builder) + { + this.LocalInfo = local; + this.builder = builder; + } + + public override Type Type { + get { return LocalInfo.VariableType; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { + // Do nothing. + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloc, builder); + } + + public override void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stloc, builder); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloca, builder); + } + } } /// @@ -1198,7 +1292,9 @@ namespace Mono.CSharp { IsDestructor = 32, IsToplevel = 64, Unsafe = 128, - HasVarargs = 256 // Used in ToplevelBlock + HasVarargs = 256, // Used in ToplevelBlock + IsIterator = 512 + } protected Flags flags; @@ -1219,7 +1315,7 @@ namespace Mono.CSharp { // // The statements in this block // - ArrayList statements; + protected ArrayList statements; int num_statements; // @@ -1255,6 +1351,10 @@ namespace Mono.CSharp { // Block switch_block; + ExpressionStatement scope_init; + + ArrayList anonymous_children; + protected static int id; int this_id; @@ -1295,7 +1395,6 @@ namespace Mono.CSharp { // share with parent known_variables = parent.known_variables; } - } public Block CreateSwitchBlock (Location start) @@ -1309,7 +1408,7 @@ namespace Mono.CSharp { get { return this_id; } } - protected IDictionary Variables { + public IDictionary Variables { get { if (variables == null) variables = new ListDictionary (); @@ -1330,6 +1429,12 @@ namespace Mono.CSharp { EndLocation = loc; } + protected static void Error_158 (string name, Location loc) + { + Report.Error (158, loc, "The label `{0}' shadows another label " + + "by the same name in a contained scope.", name); + } + /// /// Adds a label to the current block. /// @@ -1339,17 +1444,18 @@ namespace Mono.CSharp { /// otherwise. /// /// - public bool AddLabel (string name, LabeledStatement target, Location loc) + public bool AddLabel (LabeledStatement target) { if (switch_block != null) - return switch_block.AddLabel (name, target, loc); + return switch_block.AddLabel (target); + + string name = target.Name; Block cur = this; while (cur != null) { if (cur.DoLookupLabel (name) != null) { - Report.Error ( - 140, loc, "The label `{0}' is a duplicate", - name); + Report.Error (140, target.loc, + "The label `{0}' is a duplicate", name); return false; } @@ -1361,11 +1467,7 @@ namespace Mono.CSharp { while (cur != null) { if (cur.DoLookupLabel (name) != null) { - Report.Error ( - 158, loc, - "The label `{0}' shadows another label " + - "by the same name in a contained scope.", - name); + Error_158 (name, target.loc); return false; } @@ -1375,20 +1477,16 @@ namespace Mono.CSharp { if (s == null) continue; - Report.Error ( - 158, s.loc, - "The label `{0}' shadows another " + - "label by the same name in a " + - "contained scope.", - name); + Error_158 (name, target.loc); return false; } } - cur = cur.Parent; } + Toplevel.CheckError158 (name, target.loc); + if (labels == null) labels = new Hashtable (); @@ -1444,24 +1542,37 @@ namespace Mono.CSharp { known_variables [name] = info; } - LocalInfo GetKnownVariableInfo (string name) + LocalInfo GetKnownVariableInfo (string name, bool recurse) { - if (known_variables == null) + if (known_variables != null) { + LocalInfo vi = (LocalInfo) known_variables [name]; + if (vi != null) + return vi; + } + + if (!recurse || (children == null)) return null; - return (LocalInfo) known_variables [name]; + + foreach (Block block in children) { + LocalInfo vi = block.GetKnownVariableInfo (name, true); + if (vi != null) + return vi; + } + + return null; } public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { Block b = this; - LocalInfo kvi = b.GetKnownVariableInfo (name); + LocalInfo kvi = b.GetKnownVariableInfo (name, true); while (kvi == null) { while (b.Implicit) b = b.Parent; b = b.Parent; if (b == null) return true; - kvi = b.GetKnownVariableInfo (name); + kvi = b.GetKnownVariableInfo (name, false); } if (kvi.Block == b) @@ -1507,6 +1618,103 @@ namespace Mono.CSharp { return false; } + public bool CheckError136_InParents (string name, Location loc) + { + for (Block b = Parent; b != null; b = b.Parent) { + if (!b.DoCheckError136 (name, "parent or current", loc)) + return false; + } + + for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) { + if (!b.CheckError136_InParents (name, loc)) + return false; + } + + return true; + } + + public bool CheckError136_InChildren (string name, Location loc) + { + if (!DoCheckError136_InChildren (name, loc)) + return false; + + Block b = this; + while (b.Implicit) { + if (!b.Parent.DoCheckError136_InChildren (name, loc)) + return false; + b = b.Parent; + } + + return true; + } + + protected bool DoCheckError136_InChildren (string name, Location loc) + { + if (!DoCheckError136 (name, "child", loc)) + return false; + + if (AnonymousChildren != null) { + foreach (ToplevelBlock child in AnonymousChildren) { + if (!child.DoCheckError136_InChildren (name, loc)) + return false; + } + } + + if (children != null) { + foreach (Block child in children) { + if (!child.DoCheckError136_InChildren (name, loc)) + return false; + } + } + + return true; + } + + public bool CheckError136 (string name, string scope, bool check_parents, + bool check_children, Location loc) + { + if (!DoCheckError136 (name, scope, loc)) + return false; + + if (check_parents) { + if (!CheckError136_InParents (name, loc)) + return false; + } + + if (check_children) { + if (!CheckError136_InChildren (name, loc)) + return false; + } + + for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) { + if (!c.DoCheckError136 (name, "parent or current", loc)) + return false; + } + + return true; + } + + protected bool DoCheckError136 (string name, string scope, Location loc) + { + LocalInfo vi = GetKnownVariableInfo (name, false); + if (vi != null) { + Report.SymbolRelatedToPreviousError (vi.Location, name); + Error_AlreadyDeclared (loc, name, scope != null ? scope : "child"); + return false; + } + + int idx; + Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx); + if (p != null) { + Report.SymbolRelatedToPreviousError (p.Location, name); + Error_AlreadyDeclared ( + loc, name, scope != null ? scope : "method argument"); + return false; + } + + return true; + } + public LocalInfo AddVariable (Expression type, string name, Location l) { LocalInfo vi = GetLocalInfo (name); @@ -1520,27 +1728,12 @@ namespace Mono.CSharp { return null; } - vi = GetKnownVariableInfo (name); - if (vi != null) { - Report.SymbolRelatedToPreviousError (vi.Location, name); - Error_AlreadyDeclared (l, name, "child"); + if (!CheckError136 (name, null, true, true, l)) return null; - } - - int idx; - Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx); - if (p != null) { - Report.SymbolRelatedToPreviousError (p.Location, name); - Error_AlreadyDeclared (l, name, "method argument"); - return null; - } vi = new LocalInfo (type, name, this, l); - Variables.Add (name, vi); - - for (Block b = this; b != null; b = b.Parent) - b.AddKnownVariable (name, vi); + AddKnownVariable (name, vi); if ((flags & Flags.VariablesInitialized) != 0) throw new Exception (); @@ -1550,8 +1743,10 @@ namespace Mono.CSharp { void Error_AlreadyDeclared (Location loc, string var, string reason) { - Report.Error (136, loc, "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning to `{0}', " + - "which is already used in a `{1}' scope", var, reason); + Report.Error (136, loc, "A local variable named `{0}' cannot be declared " + + "in this scope because it would give a different meaning " + + "to `{0}', which is already used in a `{1}' scope " + + "to denote something else", var, reason); } public bool AddConstant (Expression type, string name, Expression value, Location l) @@ -1573,6 +1768,8 @@ namespace Mono.CSharp { public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc) { + Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc); + if (temporary_variables == null) temporary_variables = new ArrayList (); @@ -1663,6 +1860,28 @@ namespace Mono.CSharp { } } + public ScopeInfo ScopeInfo; + + public ScopeInfo CreateScopeInfo () + { + if (ScopeInfo == null) + ScopeInfo = ScopeInfo.CreateScope (this); + + return ScopeInfo; + } + + public ArrayList AnonymousChildren { + get { return anonymous_children; } + } + + public void AddAnonymousChild (ToplevelBlock b) + { + if (anonymous_children == null) + anonymous_children = new ArrayList (); + + anonymous_children.Add (b); + } + /// /// Emits the variable declarations and labels. /// @@ -1672,149 +1891,133 @@ namespace Mono.CSharp { /// public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip) { - bool old_unsafe = ec.InUnsafe; + Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel); // If some parent block was unsafe, we remain unsafe even if this block // isn't explicitly marked as such. - ec.InUnsafe |= Unsafe; + using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) { + // + // Compute the VariableMap's. + // + // Unfortunately, we don't know the type when adding variables with + // AddVariable(), so we need to compute this info here. + // - // - // Compute the VariableMap's. - // - // Unfortunately, we don't know the type when adding variables with - // AddVariable(), so we need to compute this info here. - // + LocalInfo[] locals; + if (variables != null) { + foreach (LocalInfo li in variables.Values) + li.Resolve (ec); - LocalInfo[] locals; - if (variables != null) { - foreach (LocalInfo li in variables.Values) - li.Resolve (ec); + locals = new LocalInfo [variables.Count]; + variables.Values.CopyTo (locals, 0); + } else + locals = new LocalInfo [0]; - locals = new LocalInfo [variables.Count]; - variables.Values.CopyTo (locals, 0); - } else - locals = new LocalInfo [0]; + if (Parent != null) + local_map = new VariableMap (Parent.LocalMap, locals); + else + local_map = new VariableMap (locals); - if (Parent != null) - local_map = new VariableMap (Parent.LocalMap, locals); - else - local_map = new VariableMap (locals); + param_map = new VariableMap (ip); + flags |= Flags.VariablesInitialized; - param_map = new VariableMap (ip); - flags |= Flags.VariablesInitialized; + // + // Process this block variables + // + if (variables != null) { + foreach (DictionaryEntry de in variables) { + string name = (string) de.Key; + LocalInfo vi = (LocalInfo) de.Value; + Type variable_type = vi.VariableType; - bool old_check_state = ec.ConstantCheckState; - ec.ConstantCheckState = (flags & Flags.Unchecked) == 0; - - // - // Process this block variables - // - if (variables != null){ - foreach (DictionaryEntry de in variables){ - string name = (string) de.Key; - LocalInfo vi = (LocalInfo) de.Value; - - if (vi.VariableType == null) - continue; + if (variable_type == null) + continue; - Type variable_type = vi.VariableType; + if (variable_type.IsPointer) { + // + // Am not really convinced that this test is required (Microsoft does it) + // but the fact is that you would not be able to use the pointer variable + // *anyways* + // + if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type), + vi.Location)) + continue; + } - if (variable_type.IsPointer){ - // - // Am not really convinced that this test is required (Microsoft does it) - // but the fact is that you would not be able to use the pointer variable - // *anyways* - // - if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type), - vi.Location)) + if (constants == null) continue; - } - if (constants == null) - continue; + Expression cv = (Expression) constants [name]; + if (cv == null) + continue; - Expression cv = (Expression) constants [name]; - if (cv == null) - continue; + // Don't let 'const int Foo = Foo;' succeed. + // Removing the name from 'constants' ensures that we get a LocalVariableReference below, + // which in turn causes the 'must be constant' error to be triggered. + constants.Remove (name); - // Don't let 'const int Foo = Foo;' succeed. - // Removing the name from 'constants' ensures that we get a LocalVariableReference below, - // which in turn causes the 'must be constant' error to be triggered. - constants.Remove (name); + if (!Const.IsConstantTypeValid (variable_type)) { + Const.Error_InvalidConstantType (variable_type, loc); + continue; + } - ec.CurrentBlock = this; - Expression e = cv.Resolve (ec); - if (e == null) - continue; + using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) { + ec.CurrentBlock = this; + Expression e = cv.Resolve (ec); + if (e == null) + continue; - Constant ce = e as Constant; - if (ce == null){ - Const.Error_ExpressionMustBeConstant (vi.Location, name); - continue; - } + Constant ce = e as Constant; + if (ce == null) { + Const.Error_ExpressionMustBeConstant (vi.Location, name); + continue; + } - e = ce.ToType (variable_type, vi.Location); - if (e == null) - continue; + e = ce.ImplicitConversionRequired (variable_type, vi.Location); + if (e == null) + continue; + + if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue) { + Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name); + continue; + } - constants.Add (name, e); + constants.Add (name, e); + vi.IsConstant = true; + } + } } - } - ec.ConstantCheckState = old_check_state; - // - // Now, handle the children - // - if (children != null){ - foreach (Block b in children) - b.ResolveMeta (toplevel, ec, ip); + // + // Now, handle the children + // + if (children != null) { + foreach (Block b in children) + b.ResolveMeta (toplevel, ec, ip); + } } - ec.InUnsafe = old_unsafe; } // // Emits the local variable declarations for a block // - public void EmitMeta (EmitContext ec) + public virtual void EmitMeta (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (variables != null){ - bool have_captured_vars = ec.HaveCapturedVariables (); - - foreach (DictionaryEntry de in variables){ - LocalInfo vi = (LocalInfo) de.Value; - - if (have_captured_vars && ec.IsCaptured (vi)) - continue; + Report.Debug (64, "BLOCK EMIT META", this, Parent, Toplevel, ScopeInfo, ec); + if (ScopeInfo != null) { + scope_init = ScopeInfo.GetScopeInitializer (ec); + Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo, + ec, scope_init); + } - if (vi.Pinned) - // - // This is needed to compile on both .NET 1.x and .NET 2.x - // the later introduced `DeclareLocal (Type t, bool pinned)' - // - vi.LocalBuilder = TypeManager.DeclareLocalPinned (ig, vi.VariableType); - else if (!vi.IsThis) - vi.LocalBuilder = ig.DeclareLocal (vi.VariableType); - } + if (variables != null){ + foreach (LocalInfo vi in variables.Values) + vi.ResolveVariable (ec); } if (temporary_variables != null) { - AnonymousContainer am = ec.CurrentAnonymousMethod; - TypeBuilder scope = null; - if ((am != null) && am.IsIterator) { - scope = am.Scope.ScopeTypeBuilder; - if (scope == null) - throw new InternalErrorException (); - } - foreach (LocalInfo vi in temporary_variables) { - if (scope != null) { - if (vi.FieldBuilder == null) - vi.FieldBuilder = scope.DefineField ( - vi.Name, vi.VariableType, FieldAttributes.Assembly); - } else - vi.LocalBuilder = ig.DeclareLocal (vi.VariableType); - } + foreach (LocalInfo vi in temporary_variables) + vi.ResolveVariable (ec); } if (children != null){ @@ -1830,13 +2033,14 @@ namespace Mono.CSharp { if ((variables != null) && (RootContext.WarningLevel >= 3)) { foreach (DictionaryEntry de in variables){ LocalInfo vi = (LocalInfo) de.Value; - + if (vi.Used) continue; - + name = (string) de.Key; - if (vector.IsAssigned (vi.VariableInfo)){ + // vi.VariableInfo can be null for 'catch' variables + if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){ Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name); } else { Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name); @@ -1890,6 +2094,12 @@ 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]; @@ -1909,7 +2119,7 @@ namespace Mono.CSharp { if (s is Block) ((Block) s).unreachable = true; - if (!unreachable_shown) { + if (!unreachable_shown && !(s is LabeledStatement)) { Report.Warning (162, 2, s.loc, "Unreachable code detected"); unreachable_shown = true; } @@ -1933,15 +2143,18 @@ namespace Mono.CSharp { statements [ix] = EmptyStatement.Value; num_statements = ix + 1; - if (s is LabeledStatement) - unreachable = false; - else - unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable; + + unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable; + if (unreachable && s is LabeledStatement) + throw new InternalErrorException ("should not happen"); } Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching, statement_count, num_statements); + while (ec.CurrentBranching is FlowBranchingLabeled) + ec.EndFlowBranching (); + FlowBranching.UsageVector vector = ec.DoEndFlowBranching (); ec.CurrentBlock = prev_block; @@ -1950,7 +2163,7 @@ namespace Mono.CSharp { // initializer, then we must initialize all of the struct's fields. if ((flags & Flags.IsToplevel) != 0 && !Toplevel.IsThisAssigned (ec) && - vector.Reachability.Throws != FlowBranching.FlowReturns.Always) + !vector.Reachability.AlwaysThrows) ok = false; if ((labels != null) && (RootContext.WarningLevel >= 2)) { @@ -1962,9 +2175,7 @@ namespace Mono.CSharp { Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector); - if ((vector.Reachability.Returns == FlowBranching.FlowReturns.Always) || - (vector.Reachability.Throws == FlowBranching.FlowReturns.Always) || - (vector.Reachability.Reachable == FlowBranching.FlowReturns.Never)) + if (vector.Reachability.IsUnreachable) flags |= Flags.HasRet; if (ok && (errors == Report.Errors)) { @@ -2019,27 +2230,27 @@ namespace Mono.CSharp { if (emit_debug_info) { if (is_lexical_block) ec.BeginScope (); + } + ec.Mark (StartLocation, true); + if (scope_init != null) + scope_init.EmitStatement (ec); + DoEmit (ec); + ec.Mark (EndLocation, true); + + if (emit_debug_info) { + if (is_lexical_block) + ec.EndScope (); if (variables != null) { foreach (DictionaryEntry de in variables) { string name = (string) de.Key; LocalInfo vi = (LocalInfo) de.Value; - if (vi.LocalBuilder == null) - continue; - - ec.DefineLocalVariable (name, vi.LocalBuilder); + vi.EmitSymbolInfo (ec, name); } } } - ec.Mark (StartLocation, true); - DoEmit (ec); - ec.Mark (EndLocation, true); - - if (emit_debug_info && is_lexical_block) - ec.EndScope (); - ec.CurrentBlock = prev_block; } @@ -2077,64 +2288,87 @@ namespace Mono.CSharp { // Pointer to the host of this anonymous method, or null // if we are the topmost block // - ToplevelBlock container; - CaptureContext capture_context; - FlowBranching top_level_branching; - - Hashtable capture_contexts; - ArrayList children; + Block container; + ToplevelBlock child; + GenericMethod generic; + FlowBranchingToplevel top_level_branching; + AnonymousContainer anonymous_container; + RootScopeInfo root_scope; public bool HasVarargs { get { return (flags & Flags.HasVarargs) != 0; } set { flags |= Flags.HasVarargs; } } + public bool IsIterator { + get { return (flags & Flags.IsIterator) != 0; } + } + // // The parameters for the block. // - public readonly Parameters Parameters; - - public void RegisterCaptureContext (CaptureContext cc) - { - if (capture_contexts == null) - capture_contexts = new Hashtable (); - capture_contexts [cc] = cc; + Parameters parameters; + public Parameters Parameters { + get { return parameters; } } - public void CompleteContexts () + public bool CompleteContexts (EmitContext ec) { - if (capture_contexts == null) - return; + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, + container, root_scope); + + if (root_scope != null) + root_scope.LinkScopes (); - foreach (CaptureContext cc in capture_contexts.Keys){ - cc.AdjustScopes (); + if ((container == null) && (root_scope != null)) { + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, + root_scope); + + if (root_scope.DefineType () == null) + return false; + if (!root_scope.ResolveType ()) + return false; + if (!root_scope.ResolveMembers ()) + return false; + if (!root_scope.DefineMembers ()) + return false; } + + return true; } - public CaptureContext ToplevelBlockCaptureContext { - get { return capture_context; } + public GenericMethod GenericMethod { + get { return generic; } } public ToplevelBlock Container { - get { return container; } + get { return container != null ? container.Toplevel : null; } } - protected void AddChild (ToplevelBlock block) - { - if (children == null) - children = new ArrayList (); + public Block ContainerBlock { + get { return container; } + } - children.Add (block); + public AnonymousContainer AnonymousContainer { + get { return anonymous_container; } + set { anonymous_container = value; } } // // Parent is only used by anonymous blocks to link back to their // parents // - public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) : + public ToplevelBlock (Block container, Parameters parameters, Location start) : this (container, (Flags) 0, parameters, start) { } + + public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic, + Location start) : + this (container, parameters, start) + { + this.generic = generic; + } public ToplevelBlock (Parameters parameters, Location start) : this (null, (Flags) 0, parameters, start) @@ -2146,31 +2380,81 @@ namespace Mono.CSharp { { } - public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) : + public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) : base (null, flags | Flags.IsToplevel, start, Location.Null) { - Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; this.container = container; - - if (container != null) - container.AddChild (this); } public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) { } - public void SetHaveAnonymousMethods (Location loc, AnonymousContainer host) + public bool CheckError158 (string name, Location loc) + { + if (AnonymousChildren != null) { + foreach (ToplevelBlock child in AnonymousChildren) { + if (!child.CheckError158 (name, loc)) + return false; + } + } + + for (ToplevelBlock c = Container; c != null; c = c.Container) { + if (!c.DoCheckError158 (name, loc)) + return false; + } + + return true; + } + + bool DoCheckError158 (string name, Location loc) + { + LabeledStatement s = LookupLabel (name); + if (s != null) { + Error_158 (name, loc); + return false; + } + + return true; + } + + public RootScopeInfo CreateRootScope (TypeContainer host) + { + if (root_scope != null) + return root_scope; + + if (Container == null) + root_scope = new RootScopeInfo ( + this, host, generic, StartLocation); + + ScopeInfo = root_scope; + return root_scope; + } + + public void CreateIteratorHost (RootScopeInfo root) { - if (capture_context == null) - capture_context = new CaptureContext (this, loc, host); + Report.Debug (64, "CREATE ITERATOR HOST", this, root, + container, root_scope); + + if ((container != null) || (root_scope != null)) + throw new InternalErrorException (); + + ScopeInfo = root_scope = root; } - public CaptureContext CaptureContext { - get { return capture_context; } + public RootScopeInfo RootScope { + get { + if (root_scope != null) + return root_scope; + else if (Container != null) + return Container.RootScope; + else + return null; + } } - public FlowBranching TopLevelBranching { + public FlowBranchingToplevel TopLevelBranching { get { return top_level_branching; } } @@ -2183,15 +2467,11 @@ namespace Mono.CSharp { // null. Later on, when resolving the iterator, we need to move the // anonymous method into that iterator. // - public void ReParent (ToplevelBlock new_parent, AnonymousContainer new_host) + public void ReParent (ToplevelBlock new_parent) { - foreach (ToplevelBlock block in children) { - if (block.CaptureContext == null) - continue; - - block.container = new_parent; - block.CaptureContext.ReParent (new_parent, new_host); - } + container = new_parent; + Parent = new_parent; + new_parent.child = this; } // @@ -2251,10 +2531,10 @@ namespace Mono.CSharp { // analysis code to ensure that it's been fully initialized before control // leaves the constructor. // - public LocalInfo AddThisVariable (TypeContainer tc, Location l) + public LocalInfo AddThisVariable (DeclSpace ds, Location l) { if (this_variable == null) { - this_variable = new LocalInfo (tc, this, l); + this_variable = new LocalInfo (ds, this, l); this_variable.Used = true; this_variable.IsThis = true; @@ -2276,12 +2556,71 @@ namespace Mono.CSharp { if (top_level_branching != null) return true; + if (ip != null) + parameters = ip; + + if (!IsIterator && (container != null) && (parameters != null)) { + foreach (Parameter p in parameters.FixedParameters) { + if (!CheckError136_InParents (p.Name, loc)) + return false; + } + } + ResolveMeta (this, ec, ip); + if (child != null) + child.ResolveMeta (this, ec, ip); + top_level_branching = ec.StartFlowBranching (this); return Report.Errors == errors; } + + public override void EmitMeta (EmitContext ec) + { + base.EmitMeta (ec); + parameters.ResolveVariable (this); + } + + public void MakeIterator (Iterator iterator) + { + flags |= Flags.IsIterator; + + Block block = new Block (this); + foreach (Statement stmt in statements) + block.AddStatement (stmt); + statements = new ArrayList (); + statements.Add (new MoveNextStatement (iterator, block)); + } + + protected class MoveNextStatement : Statement { + Iterator iterator; + Block block; + + public MoveNextStatement (Iterator iterator, Block block) + { + this.iterator = iterator; + this.block = block; + this.loc = iterator.Location; + } + + public override bool Resolve (EmitContext ec) + { + return block.Resolve (ec); + } + + protected override void DoEmit (EmitContext ec) + { + iterator.EmitMoveNext (ec, block); + } + } + + public override string ToString () + { + return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation, + root_scope, anonymous_container != null ? + anonymous_container.Scope : null); + } } public class SwitchLabel { @@ -2339,7 +2678,7 @@ namespace Mono.CSharp { // Resolves the expression, reduces it to a literal if possible // and then converts it to the requested type. // - public bool ResolveAndReduce (EmitContext ec, Type required_type) + public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable) { Expression e = label.Resolve (ec); @@ -2357,7 +2696,12 @@ namespace Mono.CSharp { return true; } - c = c.ToType (required_type, loc); + if (allow_nullable && c.GetValue () == null) { + converted = NullStringCase; + return true; + } + + c = c.ImplicitConversionRequired (required_type, loc); if (c == null) return false; @@ -2409,11 +2753,27 @@ namespace Mono.CSharp { // Computed // Label default_target; + Label null_target; Expression new_expr; bool is_constant; SwitchSection constant_section; SwitchSection default_section; +#if GMCS_SOURCE + // + // Nullable Types support for GMCS. + // + Nullable.Unwrap unwrap; + + protected bool HaveUnwrap { + get { return unwrap != null; } + } +#else + protected bool HaveUnwrap { + get { return false; } + } +#endif + // // The types allowed to be implicitly cast from // on the governing type @@ -2445,8 +2805,10 @@ namespace Mono.CSharp { // expression that includes any potential conversions to the // integral types or to string. // - Expression SwitchGoverningType (EmitContext ec, Type t) + Expression SwitchGoverningType (EmitContext ec, Expression expr) { + Type t = expr.Type; + if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.ushort_type || @@ -2459,7 +2821,7 @@ namespace Mono.CSharp { t == TypeManager.string_type || t == TypeManager.bool_type || t.IsSubclassOf (TypeManager.enum_type)) - return Expr; + return expr; if (allowed_types == null){ allowed_types = new Type [] { @@ -2487,7 +2849,7 @@ namespace Mono.CSharp { foreach (Type tt in allowed_types){ Expression e; - e = Convert.ImplicitUserConversion (ec, Expr, tt, loc); + e = Convert.ImplicitUserConversion (ec, expr, tt, loc); if (e == null) continue; @@ -2502,7 +2864,7 @@ namespace Mono.CSharp { Report.ExtraInformation ( loc, String.Format ("reason: more than one conversion to an integral type exist for type {0}", - TypeManager.CSharpName (Expr.Type))); + TypeManager.CSharpName (expr.Type))); return null; } @@ -2536,7 +2898,7 @@ namespace Mono.CSharp { continue; } - if (!sl.ResolveAndReduce (ec, SwitchType)){ + if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) { error = true; continue; } @@ -2544,11 +2906,10 @@ namespace Mono.CSharp { object key = sl.Converted; try { Elements.Add (key, sl); + } catch (ArgumentException) { + sl.Erorr_AlreadyOccurs (); + error = true; } - catch (ArgumentException) { - sl.Erorr_AlreadyOccurs (); - error = true; - } } } return !error; @@ -2575,14 +2936,15 @@ namespace Mono.CSharp { } else if (k is ulong) { - if ((ulong) k < (1L<<32)) + ulong ul = (ulong) k; + if (ul < (1L<<32)) { - IntConstant.EmitInt (ig, (int) (long) k); + IntConstant.EmitInt (ig, unchecked ((int) ul)); ig.Emit (OpCodes.Conv_U8); } else { - LongConstant.EmitLong (ig, unchecked ((long) (ulong) k)); + LongConstant.EmitLong (ig, unchecked ((long) ul)); } } else if (k is char) @@ -2811,20 +3173,30 @@ namespace Mono.CSharp { // now emit the code for the sections bool fFoundDefault = false; + bool fFoundNull = false; + foreach (SwitchSection ss in Sections) + { + foreach (SwitchLabel sl in ss.Labels) + if (sl.Converted == SwitchLabel.NullStringCase) + fFoundNull = true; + } + foreach (SwitchSection ss in Sections) { foreach (SwitchLabel sl in ss.Labels) { ig.MarkLabel (sl.GetILLabel (ec)); ig.MarkLabel (sl.GetILLabelCode (ec)); - if (sl.Label == null) - { + if (sl.Converted == SwitchLabel.NullStringCase) + ig.MarkLabel (null_target); + else if (sl.Label == null) { ig.MarkLabel (lblDefault); fFoundDefault = true; + if (!fFoundNull) + ig.MarkLabel (null_target); } } ss.Block.Emit (ec); - //ig.Emit (OpCodes.Br, lblEnd); } if (!fFoundDefault) { @@ -2843,7 +3215,6 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; Label end_of_switch = ig.DefineLabel (); Label next_test = ig.DefineLabel (); - Label null_target = ig.DefineLabel (); bool first_test = true; bool pending_goto_end = false; bool null_marked = false; @@ -2892,7 +3263,7 @@ namespace Mono.CSharp { if (lit == SwitchLabel.NullStringCase){ null_found = true; - if (label_count == 1) + if (label + 1 == label_count) ig.Emit (OpCodes.Br, next_test); continue; } @@ -2948,7 +3319,18 @@ namespace Mono.CSharp { if (Expr == null) return false; - new_expr = SwitchGoverningType (ec, Expr.Type); + new_expr = SwitchGoverningType (ec, Expr); + +#if GMCS_SOURCE + if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) { + unwrap = Nullable.Unwrap.Create (Expr, ec); + if (unwrap == null) + return false; + + new_expr = SwitchGoverningType (ec, unwrap); + } +#endif + if (new_expr == null){ Report.Error (151, loc, "A value of an integral type or string expected for switch"); return false; @@ -2960,6 +3342,9 @@ namespace Mono.CSharp { if (!CheckSwitch (ec)) return false; + if (HaveUnwrap) + Elements.Remove (SwitchLabel.NullStringCase); + Switch old_switch = ec.Switch; ec.Switch = this; ec.Switch.SwitchType = SwitchType; @@ -3015,17 +3400,26 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; + default_target = ig.DefineLabel (); + null_target = ig.DefineLabel (); + // Store variable for comparission purposes LocalBuilder value; - if (!is_constant) { + if (HaveUnwrap) { + value = ig.DeclareLocal (SwitchType); +#if GMCS_SOURCE + unwrap.EmitCheck (ec); + ig.Emit (OpCodes.Brfalse, null_target); + new_expr.Emit (ec); + ig.Emit (OpCodes.Stloc, value); +#endif + } else if (!is_constant) { value = ig.DeclareLocal (SwitchType); new_expr.Emit (ec); ig.Emit (OpCodes.Stloc, value); } else value = null; - default_target = ig.DefineLabel (); - // // Setup the codegen context // @@ -3114,7 +3508,7 @@ namespace Mono.CSharp { ResolveFinally (branching); FlowBranching.Reachability reachability = ec.EndFlowBranching (); - if (reachability.Returns != FlowBranching.FlowReturns.Always) { + if (!reachability.AlwaysReturns) { // Unfortunately, System.Reflection.Emit automatically emits // a leave to the end of the finally block. // This is a problem if `returns' is true since we may jump @@ -3123,7 +3517,13 @@ namespace Mono.CSharp { ec.NeedReturnLabel (); } - temp = new TemporaryVariable (expr.Type, loc); + // Avoid creating libraries that reference the internal + // mcs NullType: + Type t = expr.Type; + if (t == TypeManager.null_type) + t = TypeManager.object_type; + + temp = new TemporaryVariable (t, loc); temp.Resolve (ec); return true; @@ -3166,28 +3566,14 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - bool previous_state = ec.CheckState; - bool previous_state_const = ec.ConstantCheckState; - - ec.CheckState = false; - ec.ConstantCheckState = false; - bool ret = Block.Resolve (ec); - ec.CheckState = previous_state; - ec.ConstantCheckState = previous_state_const; - - return ret; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - bool previous_state = ec.CheckState; - bool previous_state_const = ec.ConstantCheckState; - - ec.CheckState = false; - ec.ConstantCheckState = false; - Block.Emit (ec); - ec.CheckState = previous_state; - ec.ConstantCheckState = previous_state_const; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + Block.Emit (ec); } } @@ -3202,28 +3588,14 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - bool previous_state = ec.CheckState; - bool previous_state_const = ec.ConstantCheckState; - - ec.CheckState = true; - ec.ConstantCheckState = true; - bool ret = Block.Resolve (ec); - ec.CheckState = previous_state; - ec.ConstantCheckState = previous_state_const; - - return ret; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - bool previous_state = ec.CheckState; - bool previous_state_const = ec.ConstantCheckState; - - ec.CheckState = true; - ec.ConstantCheckState = true; - Block.Emit (ec); - ec.CheckState = previous_state; - ec.ConstantCheckState = previous_state_const; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + Block.Emit (ec); } } @@ -3238,23 +3610,14 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - bool previous_state = ec.InUnsafe; - bool val; - - ec.InUnsafe = true; - val = Block.Resolve (ec); - ec.InUnsafe = previous_state; - - return val; + using (ec.With (EmitContext.Flags.InUnsafe, true)) + return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - bool previous_state = ec.InUnsafe; - - ec.InUnsafe = true; - Block.Emit (ec); - ec.InUnsafe = previous_state; + using (ec.With (EmitContext.Flags.InUnsafe, true)) + Block.Emit (ec); } } @@ -3281,7 +3644,7 @@ namespace Mono.CSharp { } public abstract void Emit (EmitContext ec); - public abstract void EmitExit (ILGenerator ig); + public abstract void EmitExit (EmitContext ec); } class ExpressionEmitter : Emitter { @@ -3295,14 +3658,14 @@ namespace Mono.CSharp { // Store pointer in pinned location // converted.Emit (ec); - ec.ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + vi.Variable.EmitAssign (ec); } - public override void EmitExit (ILGenerator ig) + public override void EmitExit (EmitContext ec) { - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Conv_U); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + ec.ig.Emit (OpCodes.Ldc_I4_0); + ec.ig.Emit (OpCodes.Conv_U); + vi.Variable.EmitAssign (ec); } } @@ -3332,13 +3695,13 @@ namespace Mono.CSharp { return; converted.Emit (ec); - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + vi.Variable.EmitAssign (ec); } - public override void EmitExit(ILGenerator ig) + public override void EmitExit (EmitContext ec) { - ig.Emit (OpCodes.Ldnull); - ig.Emit (OpCodes.Stloc, pinned_string); + ec.ig.Emit (OpCodes.Ldnull); + ec.ig.Emit (OpCodes.Stloc, pinned_string); } } @@ -3365,7 +3728,7 @@ namespace Mono.CSharp { if (texpr == null) return false; - expr_type = texpr.ResolveType (ec); + expr_type = texpr.Type; data = new Emitter [declarators.Count]; @@ -3425,7 +3788,7 @@ namespace Mono.CSharp { return false; if (!Convert.ImplicitConversionExists (ec, e, expr_type)) { - e.Error_ValueCannotBeConverted (e.Location, expr_type, false); + e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false); return false; } @@ -3536,13 +3899,11 @@ namespace Mono.CSharp { if (has_ret) return; - ILGenerator ig = ec.ig; - // // Clear the pinned variable // for (int i = 0; i < data.Length; i++) { - data [i].EmitExit (ig); + data [i].EmitExit (ec); } } } @@ -3550,15 +3911,17 @@ namespace Mono.CSharp { public class Catch : Statement { public readonly string Name; public readonly Block Block; + public readonly Block VarBlock; Expression type_expr; Type type; - public Catch (Expression type, string name, Block block, Location l) + public Catch (Expression type, string name, Block block, Block var_block, Location l) { type_expr = type; Name = name; Block = block; + VarBlock = var_block; loc = l; } @@ -3576,19 +3939,45 @@ namespace Mono.CSharp { protected override void DoEmit(EmitContext ec) { + ILGenerator ig = ec.ig; + + if (CatchType != null) + ig.BeginCatchBlock (CatchType); + else + ig.BeginCatchBlock (TypeManager.object_type); + + if (VarBlock != null) + VarBlock.Emit (ec); + + if (Name != null) { + LocalInfo vi = Block.GetLocalInfo (Name); + if (vi == null) + throw new Exception ("Variable does not exist in this block"); + + if (vi.Variable.NeedsTemporary) { + LocalBuilder e = ig.DeclareLocal (vi.VariableType); + ig.Emit (OpCodes.Stloc, e); + + vi.Variable.EmitInstance (ec); + ig.Emit (OpCodes.Ldloc, e); + vi.Variable.EmitAssign (ec); + } else + vi.Variable.EmitAssign (ec); + } else + ig.Emit (OpCodes.Pop); + + Block.Emit (ec); } public override bool Resolve (EmitContext ec) { - bool was_catch = ec.InCatch; - ec.InCatch = true; - try { + using (ec.With (EmitContext.Flags.InCatch, true)) { if (type_expr != null) { TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); if (te == null) return false; - type = te.ResolveType (ec); + type = te.Type; if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){ Error (155, "The type caught or thrown must be derived from System.Exception"); @@ -3597,10 +3986,15 @@ namespace Mono.CSharp { } else type = null; - return Block.Resolve (ec); - } - finally { - ec.InCatch = was_catch; + if (!Block.Resolve (ec)) + return false; + + // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly + // emit the "unused variable" warnings. + if (VarBlock != null) + return VarBlock.Resolve (ec); + + return true; } } } @@ -3700,15 +4094,13 @@ namespace Mono.CSharp { if (Fini != null) { if (ok) - ec.CurrentBranching.CreateSibling ( - Fini, FlowBranching.SiblingType.Finally); + ec.CurrentBranching.CreateSibling (Fini, FlowBranching.SiblingType.Finally); Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector); - bool was_finally = ec.InFinally; - ec.InFinally = true; - if (!Fini.Resolve (ec)) - ok = false; - ec.InFinally = was_finally; + using (ec.With (EmitContext.Flags.InFinally, true)) { + if (!Fini.Resolve (ec)) + ok = false; + } if (!ec.InIterator) need_exc_block = true; @@ -3726,7 +4118,7 @@ namespace Mono.CSharp { Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector); - if (reachability.Returns != FlowBranching.FlowReturns.Always) { + if (!reachability.AlwaysReturns) { // Unfortunately, System.Reflection.Emit automatically emits // a leave to the end of the finally block. This is a problem // if `returns' is true since we may jump to a point after the @@ -3746,36 +4138,11 @@ namespace Mono.CSharp { ig.BeginExceptionBlock (); Block.Emit (ec); - foreach (Catch c in Specific){ - LocalInfo vi; - - ig.BeginCatchBlock (c.CatchType); - - if (c.Name != null){ - vi = c.Block.GetLocalInfo (c.Name); - if (vi == null) - throw new Exception ("Variable does not exist in this block"); - - if (vi.IsCaptured){ - LocalBuilder e = ig.DeclareLocal (vi.VariableType); - ig.Emit (OpCodes.Stloc, e); - - ec.EmitCapturedVariableInstance (vi); - ig.Emit (OpCodes.Ldloc, e); - ig.Emit (OpCodes.Stfld, vi.FieldBuilder); - } else - ig.Emit (OpCodes.Stloc, vi.LocalBuilder); - } else - ig.Emit (OpCodes.Pop); - - c.Block.Emit (ec); - } + foreach (Catch c in Specific) + c.Emit (ec); - if (General != null){ - ig.BeginCatchBlock (TypeManager.object_type); - ig.Emit (OpCodes.Pop); - General.Block.Emit (ec); - } + if (General != null) + General.Emit (ec); DoEmitFinally (ec); if (need_exc_block) @@ -3805,7 +4172,7 @@ namespace Mono.CSharp { Expression [] resolved_vars; Expression [] converted_vars; ExpressionStatement [] assign; - LocalBuilder local_copy; + TemporaryVariable local_copy; public Using (object expression_or_block, Statement stmt, Location l) { @@ -3825,7 +4192,7 @@ namespace Mono.CSharp { if (texpr == null) return false; - expr_type = texpr.ResolveType (ec); + expr_type = texpr.Type; // // The type must be an IDisposable or an implicit conversion @@ -3898,6 +4265,9 @@ namespace Mono.CSharp { } } + local_copy = new TemporaryVariable (expr_type, loc); + local_copy.Resolve (ec); + return true; } @@ -3916,6 +4286,7 @@ namespace Mono.CSharp { ig.BeginExceptionBlock (); } Statement.Emit (ec); + var_list.Reverse (); DoEmitFinally (ec); @@ -3930,13 +4301,16 @@ namespace Mono.CSharp { Expression var = resolved_vars [--i]; Label skip = ig.DefineLabel (); + if (emit_finally) + ig.BeginFinallyBlock (); + if (!var.Type.IsValueType) { var.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); converted_vars [i].Emit (ec); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); } else { - Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null); + Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null); if (!(ml is MethodGroupExpr)) { var.Emit (ec); @@ -3980,10 +4354,8 @@ namespace Mono.CSharp { // Make a copy of the expression and operate on that. // ILGenerator ig = ec.ig; - local_copy = ig.DeclareLocal (expr_type); - expr.Emit (ec); - ig.Emit (OpCodes.Stloc, local_copy); + local_copy.Store (ec, expr); if (emit_finally) ig.BeginExceptionBlock (); @@ -3998,19 +4370,21 @@ namespace Mono.CSharp { void EmitExpressionFinally (EmitContext ec) { ILGenerator ig = ec.ig; - if (!local_copy.LocalType.IsValueType) { + if (!expr_type.IsValueType) { Label skip = ig.DefineLabel (); - ig.Emit (OpCodes.Ldloc, local_copy); + local_copy.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); - ig.Emit (OpCodes.Ldloc, local_copy); + local_copy.Emit (ec); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); ig.MarkLabel (skip); } else { - Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, local_copy.LocalType, "Dispose", Mono.CSharp.Location.Null); + Expression ml = Expression.MemberLookup ( + ec.ContainerType, TypeManager.idisposable_type, expr_type, + "Dispose", Location.Null); if (!(ml is MethodGroupExpr)) { - ig.Emit (OpCodes.Ldloc, local_copy); - ig.Emit (OpCodes.Box, local_copy.LocalType); + local_copy.Emit (ec); + ig.Emit (OpCodes.Box, expr_type); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); } else { MethodInfo mi = null; @@ -4027,7 +4401,7 @@ namespace Mono.CSharp { return; } - ig.Emit (OpCodes.Ldloca, local_copy); + local_copy.AddressOf (ec, AddressOp.Load); ig.Emit (OpCodes.Call, mi); } } @@ -4064,10 +4438,10 @@ namespace Mono.CSharp { return false; } - ResolveFinally (branching); + ResolveFinally (branching); FlowBranching.Reachability reachability = ec.EndFlowBranching (); - if (reachability.Returns != FlowBranching.FlowReturns.Always) { + if (!reachability.AlwaysReturns) { // Unfortunately, System.Reflection.Emit automatically emits a leave // to the end of the finally block. This is a problem if `returns' // is true since we may jump to a point after the end of the method. @@ -4138,7 +4512,7 @@ namespace Mono.CSharp { Type var_type = texpr.Type; - if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethod) { + if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", expr.ExprClassName); return false; @@ -4194,7 +4568,7 @@ namespace Mono.CSharp { { EmitThis (ec); ec.ig.Emit (OpCodes.Ldc_I4_0); - EmitStore (ec.ig); + EmitStore (ec); } public void Increment (EmitContext ec) @@ -4203,7 +4577,7 @@ namespace Mono.CSharp { Emit (ec); ec.ig.Emit (OpCodes.Ldc_I4_1); ec.ig.Emit (OpCodes.Add); - EmitStore (ec.ig); + EmitStore (ec); } } @@ -4269,8 +4643,13 @@ namespace Mono.CSharp { if (variable == null) ok = false; + ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); if (!statement.Resolve (ec)) ok = false; + ec.EndFlowBranching (); + + // There's no direct control flow from the end of the embedded statement to the end of the loop + ec.CurrentBranching.CurrentUsageVector.Goto (); ec.EndFlowBranching (); @@ -4292,7 +4671,7 @@ namespace Mono.CSharp { lengths [i].EmitThis (ec); ((ArrayAccess) access).EmitGetLength (ec, i); - lengths [i].EmitStore (ig); + lengths [i].EmitStore (ec); } for (int i = 0; i < rank; i++) { @@ -4382,12 +4761,28 @@ namespace Mono.CSharp { // way I could do this without a goto // +#if GMCS_SOURCE + // + // Prefer a generic enumerator over a non-generic one. + // + if (return_type.IsInterface && return_type.IsGenericType) { + enumerator_type = return_type; + if (!FetchGetCurrent (ec, return_type)) + get_current = new PropertyExpr ( + ec.ContainerType, TypeManager.ienumerator_getcurrent, loc); + if (!FetchMoveNext (return_type)) + move_next = TypeManager.bool_movenext_void; + return true; + } +#endif + if (return_type.IsInterface || - !FetchMoveNext (ec, return_type) || + !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) { + enumerator_type = return_type; move_next = TypeManager.bool_movenext_void; get_current = new PropertyExpr ( - ec, TypeManager.ienumerator_getcurrent, loc); + ec.ContainerType, TypeManager.ienumerator_getcurrent, loc); return true; } } else { @@ -4396,7 +4791,7 @@ namespace Mono.CSharp { // find if they support the GetEnumerator pattern. // - if (TypeManager.HasElementType (return_type) || !FetchMoveNext (ec, return_type) || !FetchGetCurrent (ec, return_type)) { + if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) { Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property", TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi)); return false; @@ -4414,7 +4809,7 @@ namespace Mono.CSharp { // // Retrieves a `public bool MoveNext ()' method from the Type `t' // - bool FetchMoveNext (EmitContext ec, Type t) + bool FetchMoveNext (Type t) { MemberList move_next_list; @@ -4444,7 +4839,7 @@ namespace Mono.CSharp { bool FetchGetCurrent (EmitContext ec, Type t) { PropertyExpr pe = Expression.MemberLookup ( - ec, t, "Current", MemberTypes.Property, + ec.ContainerType, t, "Current", MemberTypes.Property, Expression.AllBindingFlags, loc) as PropertyExpr; if (pe == null) return false; @@ -4492,28 +4887,65 @@ namespace Mono.CSharp { bool TryType (EmitContext ec, Type t) { MethodGroupExpr mg = Expression.MemberLookup ( - ec, t, "GetEnumerator", MemberTypes.Method, + ec.ContainerType, t, "GetEnumerator", MemberTypes.Method, Expression.AllBindingFlags, loc) as MethodGroupExpr; if (mg == null) return false; - foreach (MethodBase mb in mg.Methods) { - if (TypeManager.GetParameterData (mb).Count != 0) + MethodInfo result = null; + MethodInfo tmp_move_next = null; + PropertyExpr tmp_get_cur = null; + Type tmp_enumerator_type = enumerator_type; + foreach (MethodInfo mi in mg.Methods) { + if (TypeManager.GetParameterData (mi).Count != 0) continue; // Check whether GetEnumerator is public - if ((mb.Attributes & MethodAttributes.Public) != MethodAttributes.Public) + if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public) continue; - if (TypeManager.IsOverride (mb)) + if (TypeManager.IsOverride (mi)) continue; enumerator_found = true; - if (!GetEnumeratorFilter (ec, (MethodInfo) mb)) + if (!GetEnumeratorFilter (ec, mi)) continue; - MethodInfo[] mi = new MethodInfo[] { (MethodInfo) mb }; + if (result != null) { + if (TypeManager.IsGenericType (result.ReturnType)) { + if (!TypeManager.IsGenericType (mi.ReturnType)) + continue; + + Report.SymbolRelatedToPreviousError(t); + Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " + + "because it contains multiple implementation of `{1}'. Try casting to a specific implementation", + TypeManager.CSharpName (t), TypeManager.CSharpSignature (mi)); + return false; + } + + // Always prefer generics enumerators + if (TypeManager.IsGenericType(mi.ReturnType)) + continue; + + Report.SymbolRelatedToPreviousError (result); + Report.SymbolRelatedToPreviousError (mi); + Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'", + TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi)); + } + result = mi; + tmp_move_next = move_next; + tmp_get_cur = get_current; + tmp_enumerator_type = enumerator_type; + if (mi.DeclaringType == t) + break; + } + + if (result != null) { + move_next = tmp_move_next; + get_current = tmp_get_cur; + enumerator_type = tmp_enumerator_type; + MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result }; get_enumerator = new MethodGroupExpr (mi, loc); if (t != expr.Type) { @@ -4534,12 +4966,16 @@ namespace Mono.CSharp { bool ProbeCollectionType (EmitContext ec, Type t) { + int errors = Report.Errors; for (Type tt = t; tt != null && tt != TypeManager.object_type;){ if (TryType (ec, tt)) return true; tt = tt.BaseType; } + if (Report.Errors > errors) + return false; + // // Now try to find the method in the interfaces // @@ -4602,9 +5038,6 @@ namespace Mono.CSharp { bool ok = true; - ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); - ec.CurrentBranching.CreateSibling (); - FlowBranchingException branching = null; if (is_disposable) branching = ec.StartFlowBranching (this); @@ -4618,8 +5051,6 @@ namespace Mono.CSharp { } else emit_finally = true; - ec.EndFlowBranching (); - return ok; } @@ -4654,8 +5085,6 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; if (enumerator_type.IsValueType) { - enumerator.Emit (ec); - MethodInfo mi = FetchMethodDispose (enumerator_type); if (mi != null) { enumerator.EmitLoadAddress (ec);