X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=9a3121ecae27fc9f2cd6ecef0fde5f0eaae55588;hb=75e27c6abf4cb612f7945c861d227382498737f1;hp=fb8391d611e68f3feca8efa5c954c2259af85e7f;hpb=7d90b80db26f7abf98142db3c35c3bcbba4501fc;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index fb8391d611e..9a3121ecae2 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -93,19 +93,22 @@ namespace Mono.CSharp { // protected virtual void CloneTo (CloneContext clonectx, Statement target) { - throw new Exception (String.Format ("Statement.CloneTo not implemented for {0}", this.GetType ())); + throw new InternalErrorException ("{0} does not implement Statement.CloneTo", this.GetType ()); } - + public Statement Clone (CloneContext clonectx) { Statement s = (Statement) this.MemberwiseClone (); - if (s is Block) - clonectx.AddBlockMap ((Block) this, (Block) s); - CloneTo (clonectx, s); return s; } + public virtual Expression CreateExpressionTree (EmitContext ec) + { + Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); + return null; + } + public Statement PerformClone () { CloneContext clonectx = new CloneContext (); @@ -146,6 +149,18 @@ namespace Mono.CSharp { return result; } + /// + /// Remaps block to cloned copy if one exists. + /// + public Block RemapBlockCopy (Block from) + { + Block mapped_to = (Block)block_map[from]; + if (mapped_to == null) + return from; + + return mapped_to; + } + public void AddVariableMap (LocalInfo from, LocalInfo to) { if (variable_map == null) @@ -186,6 +201,11 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + // nothing needed. + } } public class If : Statement { @@ -195,21 +215,21 @@ namespace Mono.CSharp { bool is_true_ret; - public If (Expression expr, Statement trueStatement, Location l) + public If (Expression expr, Statement true_statement, Location l) { this.expr = expr; - TrueStatement = trueStatement; + TrueStatement = true_statement; loc = l; } public If (Expression expr, - Statement trueStatement, - Statement falseStatement, + Statement true_statement, + Statement false_statement, Location l) { this.expr = expr; - TrueStatement = trueStatement; - FalseStatement = falseStatement; + TrueStatement = true_statement; + FalseStatement = false_statement; loc = l; } @@ -233,8 +253,8 @@ namespace Mono.CSharp { // // Dead code elimination // - if (expr is BoolConstant){ - bool take = ((BoolConstant) expr).Value; + if (expr is Constant){ + bool take = !((Constant) expr).IsDefaultValue; if (take){ if (!TrueStatement.Resolve (ec)) @@ -282,15 +302,34 @@ namespace Mono.CSharp { Label end; // - // If we're a boolean expression, Resolve() already + // If we're a boolean constant, Resolve() already // eliminated dead code for us. // - if (expr is BoolConstant){ - bool take = ((BoolConstant) expr).Value; + if (expr is Constant){ + + // + // Simple bool constant + // + if (expr is BoolConstant) { + bool take = ((BoolConstant) expr).Value; + + if (take) + TrueStatement.Emit (ec); + else if (FalseStatement != null) + FalseStatement.Emit (ec); + + return; + } + + // + // Bool constant with side-effects + // + expr.Emit (ec); + ig.Emit (OpCodes.Pop); - if (take) + if (TrueStatement != null) TrueStatement.Emit (ec); - else if (FalseStatement != null) + if (FalseStatement != null) FalseStatement.Emit (ec); return; @@ -335,9 +374,9 @@ namespace Mono.CSharp { public Statement EmbeddedStatement; bool infinite; - public Do (Statement statement, Expression boolExpr, Location l) + public Do (Statement statement, Expression bool_expr, Location l) { - expr = boolExpr; + expr = bool_expr; EmbeddedStatement = statement; loc = l; } @@ -420,9 +459,9 @@ namespace Mono.CSharp { public Statement Statement; bool infinite, empty; - public While (Expression boolExpr, Statement statement, Location l) + public While (Expression bool_expr, Statement statement, Location l) { - this.expr = boolExpr; + this.expr = bool_expr; Statement = statement; loc = l; } @@ -501,6 +540,7 @@ namespace Mono.CSharp { Statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); + ec.Mark (loc, true); expr.EmitBranchable (ec, while_loop, true); @@ -511,6 +551,11 @@ namespace Mono.CSharp { ec.LoopEnd = old_end; } + public override void Emit (EmitContext ec) + { + DoEmit (ec); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { While target = (While) t; @@ -527,13 +572,13 @@ namespace Mono.CSharp { public Statement Statement; bool infinite, empty; - public For (Statement initStatement, + public For (Statement init_statement, Expression test, Statement increment, Statement statement, Location l) { - InitStatement = initStatement; + InitStatement = init_statement; Test = test; Increment = increment; Statement = statement; @@ -700,65 +745,80 @@ namespace Mono.CSharp { /// Implements the return statement /// public class Return : Statement { - public Expression Expr; + protected Expression Expr; + bool unwind_protect; public Return (Expression expr, Location l) { Expr = expr; loc = l; } - - bool unwind_protect; - - public override bool Resolve (EmitContext ec) + + bool DoResolve (EmitContext ec) { + if (Expr == null) { + if (ec.ReturnType == TypeManager.void_type) + return true; + + Error (126, "An object of a type convertible to `{0}' is required " + + "for the return statement", + TypeManager.CSharpName (ec.ReturnType)); + return false; + } + AnonymousContainer am = ec.CurrentAnonymousMethod; if ((am != null) && am.IsIterator && ec.InIterator) { Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + - "statement to return a value, or yield break to end the iteration"); - return false; + "statement to return a value, or yield break to end the iteration"); } - if (ec.ReturnType == null){ - if (Expr != null){ - if (am != null){ - Report.Error (1662, loc, - "Cannot convert anonymous method block to delegate type `{0}' because some of the return types in the block are not implicitly convertible to the delegate return type", - am.GetSignatureForError ()); - } - Error (127, "A return keyword must not be followed by any expression when method returns void"); - return false; - } - } else { - if (Expr == null){ - Error (126, "An object of a type convertible to `{0}' is required " + - "for the return statement", - TypeManager.CSharpName (ec.ReturnType)); - return false; - } + if (am == null && ec.ReturnType == TypeManager.void_type) { + MemberCore mc = ec.ResolveContext as MemberCore; + Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void", + mc.GetSignatureForError ()); + } - Expr = Expr.Resolve (ec); - if (Expr == null) - return false; + Expr = Expr.Resolve (ec); + if (Expr == null) + return false; - if (Expr.Type != ec.ReturnType) { - if (ec.InferReturnType) { - ec.ReturnType = Expr.Type; - } else { - Expr = Convert.ImplicitConversionRequired ( - ec, Expr, ec.ReturnType, loc); - if (Expr == null) - return false; + if (Expr.Type != ec.ReturnType) { + if (ec.InferReturnType) { + // + // void cannot be used in contextual return + // + if (Expr.Type == TypeManager.void_type) + return false; + + ec.ReturnType = Expr.Type; + } else { + Expr = Convert.ImplicitConversionRequired ( + ec, Expr, ec.ReturnType, loc); + + if (Expr == null) { + if (am != null) { + Report.Error (1662, loc, + "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type", + am.ContainerType, am.GetSignatureForError ()); + } + return false; } } } - int errors = Report.Errors; + return true; + } + + public override bool Resolve (EmitContext ec) + { + if (!DoResolve (ec)) + return false; + unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc); if (unwind_protect) ec.NeedReturnLabel (); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } protected override void DoEmit (EmitContext ec) @@ -779,8 +839,9 @@ namespace Mono.CSharp { protected override void CloneTo (CloneContext clonectx, Statement t) { Return target = (Return) t; - - target.Expr = Expr.Clone (clonectx); + // It's null for simple return; + if (Expr != null) + target.Expr = Expr.Clone (clonectx); } } @@ -917,7 +978,7 @@ namespace Mono.CSharp { } if (!ec.Switch.GotDefault){ - Report.Error (159, loc, "No such label `default:' within the scope of the goto statement"); + FlowBranchingBlock.Error_UnknownLabel (loc, "default"); return; } ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); @@ -976,7 +1037,8 @@ namespace Mono.CSharp { sl = (SwitchLabel) ec.Switch.Elements [val]; if (sl == null){ - Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val.ToString ()); + FlowBranchingBlock.Error_UnknownLabel (loc, "case " + + (c.GetValue () == null ? "null" : val.ToString ())); return false; } @@ -1064,7 +1126,8 @@ namespace Mono.CSharp { { Throw target = (Throw) t; - target.expr = expr.Clone (clonectx); + if (expr != null) + target.expr = expr.Clone (clonectx); } } @@ -1089,6 +1152,11 @@ namespace Mono.CSharp { { ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd); } + + protected override void CloneTo (CloneContext clonectx, Statement t) + { + // nothing needed + } } public class Continue : Statement { @@ -1112,6 +1180,11 @@ namespace Mono.CSharp { { ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); } + + protected override void CloneTo (CloneContext clonectx, Statement t) + { + // nothing needed. + } } public abstract class Variable @@ -1137,10 +1210,15 @@ namespace Mono.CSharp { public abstract void EmitAddressOf (EmitContext ec); } + public interface IKnownVariable { + Block Block { get; } + Location Location { get; } + } + // // The information about a user-perceived local variable // - public class LocalInfo { + public class LocalInfo : IKnownVariable { public Expression Type; public Type VariableType; @@ -1215,7 +1293,7 @@ namespace Mono.CSharp { public void EmitSymbolInfo (EmitContext ec, string name) { if (builder != null) - ec.DefineLocalVariable (name, builder); + ec.DefineLocalVariable (Name, builder); } public bool IsThisAssigned (EmitContext ec) @@ -1240,7 +1318,7 @@ namespace Mono.CSharp { public bool Resolve (EmitContext ec) { if (VariableType == null) { - TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false); + TypeExpr texpr = Type.ResolveAsContextualType (ec, false); if (texpr == null) return false; @@ -1267,42 +1345,23 @@ namespace Mono.CSharp { } public bool IsCaptured { - get { - return (flags & Flags.Captured) != 0; - } - - set { - flags |= Flags.Captured; - } + get { return (flags & Flags.Captured) != 0; } + set { flags |= Flags.Captured; } } public bool IsConstant { - get { - return (flags & Flags.IsConstant) != 0; - } - set { - flags |= Flags.IsConstant; - } + get { return (flags & Flags.IsConstant) != 0; } + set { flags |= Flags.IsConstant; } } public bool AddressTaken { - get { - return (flags & Flags.AddressTaken) != 0; - } - - set { - flags |= Flags.AddressTaken; - } + get { return (flags & Flags.AddressTaken) != 0; } + set { flags |= Flags.AddressTaken; } } public bool CompilerGenerated { - get { - return (flags & Flags.CompilerGenerated) != 0; - } - - set { - flags |= Flags.CompilerGenerated; - } + get { return (flags & Flags.CompilerGenerated) != 0; } + set { flags |= Flags.CompilerGenerated; } } public override string ToString () @@ -1312,18 +1371,12 @@ namespace Mono.CSharp { } public bool Used { - get { - return (flags & Flags.Used) != 0; - } - set { - flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); - } + get { return (flags & Flags.Used) != 0; } + set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); } } public bool ReadOnly { - get { - return (flags & Flags.ReadOnly) != 0; - } + get { return (flags & Flags.ReadOnly) != 0; } } public void SetReadOnlyContext (ReadOnlyContext context) @@ -1353,21 +1406,21 @@ namespace Mono.CSharp { // allocated in a pinned slot with DeclareLocal. // public bool Pinned { - get { - return (flags & Flags.Pinned) != 0; - } - set { - flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); - } + get { return (flags & Flags.Pinned) != 0; } + set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); } } public bool IsThis { - get { - return (flags & Flags.IsThis) != 0; - } - set { - flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); - } + get { return (flags & Flags.IsThis) != 0; } + set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); } + } + + Block IKnownVariable.Block { + get { return Block; } + } + + Location IKnownVariable.Location { + get { return Location; } } protected class LocalVariable : Variable @@ -1416,8 +1469,18 @@ namespace Mono.CSharp { public LocalInfo Clone (CloneContext clonectx) { - // Only this kind is created by the parser. - return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + // + // Variables in anonymous block are not resolved yet + // + if (VariableType == null) + return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + + // + // Variables in method block are resolved + // + LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location); + li.VariableType = VariableType; + return li; } } @@ -1440,28 +1503,22 @@ namespace Mono.CSharp { public readonly Location StartLocation; public Location EndLocation = Location.Null; - public readonly ToplevelBlock Toplevel; + public ExplicitBlock Explicit; + public ToplevelBlock Toplevel; [Flags] - public enum Flags : ushort { - Implicit = 1, - Unchecked = 2, - BlockUsed = 4, - VariablesInitialized = 8, - HasRet = 16, - IsDestructor = 32, - IsToplevel = 64, - Unsafe = 128, - HasVarargs = 256, // Used in ToplevelBlock - IsIterator = 512 - + public enum Flags : byte { + Unchecked = 1, + BlockUsed = 2, + VariablesInitialized = 4, + HasRet = 8, + IsDestructor = 16, + Unsafe = 32, + HasVarargs = 64, // Used in ToplevelBlock + IsIterator = 128 } protected Flags flags; - public bool Implicit { - get { return (flags & Flags.Implicit) != 0; } - } - public bool Unchecked { get { return (flags & Flags.Unchecked) != 0; } set { flags |= Flags.Unchecked; } @@ -1476,7 +1533,6 @@ namespace Mono.CSharp { // The statements in this block // protected ArrayList statements; - protected int current_statement; int num_statements; // @@ -1491,7 +1547,7 @@ namespace Mono.CSharp { // // Labels. (label, block) pairs. // - Hashtable labels; + HybridDictionary labels; // // Keeps track of (name, type) pairs @@ -1500,7 +1556,7 @@ namespace Mono.CSharp { // // Keeps track of constants - Hashtable constants; + HybridDictionary constants; // // Temporary variables. @@ -1512,13 +1568,20 @@ namespace Mono.CSharp { // Block switch_block; + // TODO: merge with scope_initializers ExpressionStatement scope_init; + ArrayList scope_initializers; ArrayList anonymous_children; protected static int id; int this_id; + + int assignable_slots; + protected ScopeInfo scope_info; + bool unreachable_shown; + bool unreachable; public Block (Block parent) : this (parent, (Flags) 0, Location.Null, Location.Null) @@ -1534,8 +1597,13 @@ namespace Mono.CSharp { public Block (Block parent, Flags flags, Location start, Location end) { - if (parent != null) + if (parent != null) { parent.AddChild (this); + + // the appropriate constructors will fixup these fields + Toplevel = parent.Toplevel; + Explicit = parent.Explicit; + } this.Parent = parent; this.flags = flags; @@ -1543,24 +1611,13 @@ namespace Mono.CSharp { this.EndLocation = end; this.loc = start; this_id = id++; - statements = new ArrayList (); - - if ((flags & Flags.IsToplevel) != 0) - Toplevel = (ToplevelBlock) this; - else - Toplevel = parent.Toplevel; - - if (parent != null && Implicit) { - if (parent.known_variables == null) - parent.known_variables = new Hashtable (); - // share with parent - known_variables = parent.known_variables; - } + statements = new ArrayList (4); } public Block CreateSwitchBlock (Location start) { - Block new_block = new Block (this, start, start); + // FIXME: should this be implicit? + Block new_block = new ExplicitBlock (this, start, start); new_block.switch_block = this; return new_block; } @@ -1580,7 +1637,7 @@ namespace Mono.CSharp { void AddChild (Block b) { if (children == null) - children = new ArrayList (); + children = new ArrayList (1); children.Add (b); } @@ -1593,7 +1650,7 @@ namespace Mono.CSharp { 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); + "by the same name in a contained scope", name); } /// @@ -1614,13 +1671,14 @@ namespace Mono.CSharp { Block cur = this; while (cur != null) { - if (cur.DoLookupLabel (name) != null) { - Report.Error (140, target.loc, - "The label `{0}' is a duplicate", name); + LabeledStatement s = cur.DoLookupLabel (name); + if (s != null) { + Report.SymbolRelatedToPreviousError (s.loc, s.Name); + Report.Error (140, target.loc, "The label `{0}' is a duplicate", name); return false; } - if (!Implicit) + if (this == Explicit) break; cur = cur.Parent; @@ -1638,6 +1696,7 @@ namespace Mono.CSharp { if (s == null) continue; + Report.SymbolRelatedToPreviousError (s.loc, s.Name); Error_158 (name, target.loc); return false; } @@ -1649,7 +1708,7 @@ namespace Mono.CSharp { Toplevel.CheckError158 (name, target.loc); if (labels == null) - labels = new Hashtable (); + labels = new HybridDictionary(); labels.Add (name, target); return true; @@ -1665,7 +1724,7 @@ namespace Mono.CSharp { return null; foreach (Block child in children) { - if (!child.Implicit) + if (Explicit != child.Explicit) continue; s = child.LookupLabel (name); @@ -1688,59 +1747,22 @@ namespace Mono.CSharp { return null; } - Hashtable known_variables; - - // - // Marks a variable with name @name as being used in this or a child block. - // If a variable name has been used in a child block, it's illegal to - // declare a variable with the same name in the current block. - // - void AddKnownVariable (string name, LocalInfo info) - { - if (known_variables == null) - known_variables = new Hashtable (); - - known_variables [name] = info; - } - - LocalInfo GetKnownVariableInfo (string name, bool recurse) - { - if (known_variables != null) { - LocalInfo vi = (LocalInfo) known_variables [name]; - if (vi != null) - return vi; - } - - if (!recurse || (children == null)) - return null; - - 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, true); + IKnownVariable kvi = b.Explicit.GetKnownVariable (name); while (kvi == null) { - while (b.Implicit) - b = b.Parent; - b = b.Parent; + b = b.Explicit.Parent; if (b == null) return true; - kvi = b.GetKnownVariableInfo (name, false); + kvi = b.Explicit.GetKnownVariable (name); } if (kvi.Block == b) return true; // Is kvi.Block nested inside 'b' - if (b.known_variables != kvi.Block.known_variables) { + if (b.Explicit != kvi.Block.Explicit) { // // If a variable by the same name it defined in a nested block of this // block, we violate the invariant meaning in a block. @@ -1767,7 +1789,7 @@ namespace Mono.CSharp { // an indirect check that depends on AddVariable doing its // part in maintaining the invariant-meaning-in-block property. // - if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null)) + if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; // @@ -1779,144 +1801,89 @@ 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); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); - if (known_variables == vi.Block.known_variables) - Report.Error (128, l, - "A local variable named `{0}' is already defined in this scope", name); + if (Explicit == vi.Block.Explicit) + Error_AlreadyDeclared (l, name, null); else Error_AlreadyDeclared (l, name, "parent"); return null; } - if (!CheckError136 (name, null, true, true, l)) + ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name); + if (pi != null) { + Report.SymbolRelatedToPreviousError (pi.Location, name); + Error_AlreadyDeclared (loc, name, + pi.Block == Toplevel ? "method argument" : "parent or current"); return null; + } + + if (Toplevel.GenericMethod != null) { + foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) { + if (tp.Name == name) { + Report.SymbolRelatedToPreviousError (tp); + Error_AlreadyDeclaredTypeParameter (loc, name); + return null; + } + } + } + + IKnownVariable kvi = Explicit.GetKnownVariable (name); + if (kvi != null) { + Report.SymbolRelatedToPreviousError (kvi.Location, name); + Error_AlreadyDeclared (l, name, "child"); + return null; + } vi = new LocalInfo (type, name, this, l); - Variables.Add (name, vi); - AddKnownVariable (name, vi); + AddVariable (vi); if ((flags & Flags.VariablesInitialized) != 0) throw new InternalErrorException ("block has already been resolved"); return vi; } + + protected virtual void AddVariable (LocalInfo li) + { + Variables.Add (li.Name, li); + Explicit.AddKnownVariable (li.Name, li); + } - void Error_AlreadyDeclared (Location loc, string var, string reason) + protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason) { + if (reason == null) { + Error_AlreadyDeclared (loc, var); + return; + } + 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); } + protected virtual void Error_AlreadyDeclared (Location loc, string name) + { + Report.Error (128, loc, + "A local variable named `{0}' is already defined in this scope", name); + } + + protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name) + { + GenericMethod.Error_ParameterNameCollision (loc, name, "local variable"); + } + public bool AddConstant (Expression type, string name, Expression value, Location l) { if (AddVariable (type, name, l) == null) return false; if (constants == null) - constants = new Hashtable (); + constants = new HybridDictionary(); constants.Add (name, value); @@ -1972,16 +1939,22 @@ namespace Mono.CSharp { } return null; } - - public void AddStatement (Statement s) + + // + // It should be used by expressions which require to + // register a statement during resolve process. + // + public void AddScopeStatement (StatementExpression s) { - statements.Add (s); - flags |= Flags.BlockUsed; + if (scope_initializers == null) + scope_initializers = new ArrayList (); + + scope_initializers.Add (s); } - public void InsertStatementAfterCurrent (Statement statement) + public void AddStatement (Statement s) { - statements.Insert (current_statement + 1, statement); + statements.Add (s); flags |= Flags.BlockUsed; } @@ -2007,30 +1980,14 @@ namespace Mono.CSharp { flags |= Flags.IsDestructor; } - VariableMap param_map; - - public VariableMap ParameterMap { - get { - if ((flags & Flags.VariablesInitialized) == 0){ - throw new Exception ("Variables have not been initialized yet"); - } - - return param_map; - } - } - - int assignable_slots; public int AssignableSlots { get { - if ((flags & Flags.VariablesInitialized) == 0){ + if ((flags & Flags.VariablesInitialized) == 0) throw new Exception ("Variables have not been initialized yet"); - } return assignable_slots; } } - protected ScopeInfo scope_info; - public ScopeInfo ScopeInfo { get { return scope_info; } } @@ -2068,8 +2025,12 @@ namespace Mono.CSharp { LocalInfo vi = (LocalInfo) de.Value; Type variable_type = vi.VariableType; - if (variable_type == null) + if (variable_type == null) { + if (vi.Type is VarExpr) + Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); + continue; + } Expression cv = (Expression) constants [name]; if (cv == null) @@ -2113,33 +2074,31 @@ namespace Mono.CSharp { } } - protected void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip) + protected void ResolveMeta (EmitContext ec, int offset) { - Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel); + Report.Debug (64, "BLOCK RESOLVE META", this, Parent); // If some parent block was unsafe, we remain unsafe even if this block // isn't explicitly marked as such. using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) { - param_map = new VariableMap (ip); flags |= Flags.VariablesInitialized; - int offset = Parent == null ? 0 : Parent.AssignableSlots; if (variables != null) { foreach (LocalInfo li in variables.Values) { - if (li.Resolve (ec)) { - li.VariableInfo = new VariableInfo (li, offset); - offset += li.VariableInfo.Length; - } + if (!li.Resolve (ec)) + continue; + li.VariableInfo = new VariableInfo (li, offset); + offset += li.VariableInfo.Length; } } assignable_slots = offset; DoResolveConstants (ec); - if (children != null) { - foreach (Block b in children) - b.ResolveMeta (toplevel, ec, ip); - } + if (children == null) + return; + foreach (Block b in children) + b.ResolveMeta (ec, offset); } } @@ -2161,13 +2120,13 @@ namespace Mono.CSharp { } if (temporary_variables != null) { - foreach (LocalInfo vi in temporary_variables) - vi.ResolveVariable (ec); + for (int i = 0; i < temporary_variables.Count; i++) + ((LocalInfo)temporary_variables[i]).ResolveVariable(ec); } if (children != null){ - foreach (Block b in children) - b.EmitMeta (ec); + for (int i = 0; i < children.Count; i++) + ((Block)children[i]).EmitMeta(ec); } } @@ -2175,7 +2134,7 @@ namespace Mono.CSharp { { string name; - if ((variables != null) && (RootContext.WarningLevel >= 3)) { + if ((variables != null) && (Report.WarningLevel >= 3)) { foreach (DictionaryEntry de in variables){ LocalInfo vi = (LocalInfo) de.Value; @@ -2194,9 +2153,6 @@ namespace Mono.CSharp { } } - bool unreachable_shown; - bool unreachable; - private void CheckPossibleMistakenEmptyStatement (Statement s) { Statement body; @@ -2245,12 +2201,13 @@ namespace Mono.CSharp { // from the beginning of the function. The outer Resolve() that detected the unreachability is // responsible for handling the situation. // - for (current_statement = 0; current_statement < statements.Count; current_statement++) { - Statement s = (Statement) statements [current_statement]; + int statement_count = statements.Count; + for (int ix = 0; ix < statement_count; ix++){ + Statement s = (Statement) statements [ix]; // Check possible empty statement (CS0642) - if (RootContext.WarningLevel >= 3 && - current_statement + 1 < statements.Count && - statements [current_statement + 1] is Block) + if (Report.WarningLevel >= 3 && + ix + 1 < statement_count && + statements [ix + 1] is Block) CheckPossibleMistakenEmptyStatement (s); // @@ -2279,14 +2236,17 @@ namespace Mono.CSharp { if (!s.Resolve (ec)) { ok = false; - statements [current_statement] = EmptyStatement.Value; + if (ec.IsInProbingMode) + break; + + statements [ix] = EmptyStatement.Value; continue; } if (unreachable && !(s is LabeledStatement) && !(s is Block)) - statements [current_statement] = EmptyStatement.Value; + statements [ix] = EmptyStatement.Value; - num_statements = current_statement + 1; + num_statements = ix + 1; unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable; if (unreachable && s is LabeledStatement) @@ -2294,10 +2254,7 @@ namespace Mono.CSharp { } Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, - ec.CurrentBranching, statements.Count, num_statements); - - if (!ok) - return false; + ec.CurrentBranching, statement_count, num_statements); while (ec.CurrentBranching is FlowBranchingLabeled) ec.EndFlowBranching (); @@ -2308,12 +2265,10 @@ namespace Mono.CSharp { // If we're a non-static `struct' constructor which doesn't have an // initializer, then we must initialize all of the struct's fields. - if ((flags & Flags.IsToplevel) != 0 && - !Toplevel.IsThisAssigned (ec) && - !vector.IsUnreachable) + if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable) ok = false; - if ((labels != null) && (RootContext.WarningLevel >= 2)) { + if ((labels != null) && (Report.WarningLevel >= 2)) { foreach (LabeledStatement label in labels.Values) if (!label.HasBeenReferenced) Report.Warning (164, 2, label.loc, @@ -2326,8 +2281,7 @@ namespace Mono.CSharp { flags |= Flags.HasRet; if (ok && (errors == Report.Errors)) { - if (RootContext.WarningLevel >= 3) - UsageWarning (vector); + UsageWarning (vector); } return ok; @@ -2352,15 +2306,6 @@ namespace Mono.CSharp { { for (int ix = 0; ix < num_statements; ix++){ Statement s = (Statement) statements [ix]; - - // Check whether we are the last statement in a - // top-level block. - - if (((Parent == null) || Implicit) && (ix+1 == num_statements) && !(s is Block)) - ec.IsLastStatement = true; - else - ec.IsLastStatement = false; - s.Emit (ec); } } @@ -2371,90 +2316,169 @@ namespace Mono.CSharp { ec.CurrentBlock = this; - bool emit_debug_info = (CodeGen.SymbolWriter != null); - bool is_lexical_block = !Implicit && (Parent != null); + bool emit_debug_info = SymbolWriter.HasSymbolWriter; + bool is_lexical_block = (this == Explicit) && (Parent != null) && + ((flags & Flags.IsIterator) == 0); + + bool omit_debug_info = ec.OmitDebuggingInfo; if (emit_debug_info) { if (is_lexical_block) ec.BeginScope (); } - ec.Mark (StartLocation, true); - if (scope_init != null) + + if ((scope_init != null) || (scope_initializers != null)) + SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); + + if (scope_init != null) { + ec.OmitDebuggingInfo = true; scope_init.EmitStatement (ec); + ec.OmitDebuggingInfo = omit_debug_info; + } + if (scope_initializers != null) { + ec.OmitDebuggingInfo = true; + foreach (StatementExpression s in scope_initializers) + s.Emit (ec); + ec.OmitDebuggingInfo = omit_debug_info; + } + + if ((scope_init != null) || (scope_initializers != null)) + SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); + + ec.Mark (StartLocation, true); DoEmit (ec); - ec.Mark (EndLocation, true); if (emit_debug_info) { + EmitSymbolInfo (ec); + if (is_lexical_block) ec.EndScope (); + } - if (variables != null) { - foreach (DictionaryEntry de in variables) { - string name = (string) de.Key; - LocalInfo vi = (LocalInfo) de.Value; + ec.CurrentBlock = prev_block; + } - vi.EmitSymbolInfo (ec, name); - } + protected virtual void EmitSymbolInfo (EmitContext ec) + { + if (variables != null) { + foreach (DictionaryEntry de in variables) { + string name = (string) de.Key; + LocalInfo vi = (LocalInfo) de.Value; + + vi.EmitSymbolInfo (ec, name); } } + } - ec.CurrentBlock = prev_block; + public override string ToString () + { + return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation); } - // - // Returns true if we ar ea child of `b'. - // - public bool IsChildOf (Block b) + protected override void CloneTo (CloneContext clonectx, Statement t) { - Block current = this; - - do { - if (current.Parent == b) - return true; - current = current.Parent; - } while (current != null); - return false; + Block target = (Block) t; + + clonectx.AddBlockMap (this, target); + + //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel); + target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit); + if (Parent != null) + target.Parent = clonectx.RemapBlockCopy (Parent); + + if (variables != null){ + target.variables = new Hashtable (); + + foreach (DictionaryEntry de in variables){ + LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx); + target.variables [de.Key] = newlocal; + clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal); + } + } + + target.statements = new ArrayList (statements.Count); + foreach (Statement s in statements) + target.statements.Add (s.Clone (clonectx)); + + if (target.children != null){ + target.children = new ArrayList (children.Count); + foreach (Block b in children){ + target.children.Add (clonectx.LookupBlock (b)); + } + } + + // + // TODO: labels, switch_block, constants (?), anonymous_children + // + } + } + + public class ExplicitBlock : Block { + public ExplicitBlock (Block parent, Location start, Location end) + : this (parent, (Flags) 0, start, end) + { + } + + public ExplicitBlock (Block parent, Flags flags, Location start, Location end) + : base (parent, flags, start, end) + { + this.Explicit = this; + } + + public bool IsIterator { + get { return (flags & Flags.IsIterator) != 0; } + } + + HybridDictionary known_variables; + + // + // Marks a variable with name @name as being used in this or a child block. + // If a variable name has been used in a child block, it's illegal to + // declare a variable with the same name in the current block. + // + internal void AddKnownVariable (string name, IKnownVariable info) + { + if (known_variables == null) + known_variables = new HybridDictionary(); + + known_variables [name] = info; + + if (Parent != null) + Parent.Explicit.AddKnownVariable (name, info); } - public override string ToString () + internal IKnownVariable GetKnownVariable (string name) { - return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation); + return known_variables == null ? null : (IKnownVariable) known_variables [name]; } protected override void CloneTo (CloneContext clonectx, Statement t) { - Block target = (Block) t; - - if (Parent != null) - target.Parent = clonectx.LookupBlock (Parent); - - target.statements = new ArrayList (); - if (target.children != null){ - target.children = new ArrayList (); - foreach (Block b in children){ - Block newblock = (Block) b.Clone (clonectx); - - target.children.Add (newblock); - } - - } - - foreach (Statement s in statements) - target.statements.Add (s.Clone (clonectx)); + ExplicitBlock target = (ExplicitBlock) t; + target.known_variables = null; + base.CloneTo (clonectx, t); + } + } - if (variables != null){ - target.variables = new Hashtable (); + public class ToplevelParameterInfo : IKnownVariable { + public readonly ToplevelBlock Block; + public readonly int Index; + public VariableInfo VariableInfo; - foreach (DictionaryEntry de in variables){ - LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx); - target.variables [de.Key] = newlocal; - clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal); - } - } + Block IKnownVariable.Block { + get { return Block; } + } + public Parameter Parameter { + get { return Block.Parameters [Index]; } + } + public Location Location { + get { return Parameter.Location; } + } - // - // TODO: labels, switch_block, constants (?), anonymous_children - // + public ToplevelParameterInfo (ToplevelBlock block, int idx) + { + this.Block = block; + this.Index = idx; } } @@ -2466,46 +2490,35 @@ namespace Mono.CSharp { // In particular, this was introduced when the support for Anonymous // Methods was implemented. // - public class ToplevelBlock : Block { - // - // Pointer to the host of this anonymous method, or null - // if we are the topmost block - // - Block container; - ToplevelBlock child; + public class ToplevelBlock : ExplicitBlock { GenericMethod generic; FlowBranchingToplevel top_level_branching; AnonymousContainer anonymous_container; RootScopeInfo root_scope; + Parameters parameters; + ToplevelParameterInfo[] parameter_info; 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. // - Parameters parameters; public Parameters Parameters { get { return parameters; } } public bool CompleteContexts (EmitContext ec) { - Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, - container, root_scope); + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope); if (root_scope != null) root_scope.LinkScopes (); - if ((container == null) && (root_scope != null)) { - Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, - root_scope); + if (Parent == null && root_scope != null) { + Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope); if (root_scope.DefineType () == null) return false; @@ -2525,11 +2538,7 @@ namespace Mono.CSharp { } public ToplevelBlock Container { - get { return container != null ? container.Toplevel : null; } - } - - public Block ContainerBlock { - get { return container; } + get { return Parent == null ? null : Parent.Toplevel; } } public AnonymousContainer AnonymousContainer { @@ -2537,18 +2546,13 @@ namespace Mono.CSharp { set { anonymous_container = value; } } - // - // Parent is only used by anonymous blocks to link back to their - // parents - // - public ToplevelBlock (Block container, Parameters parameters, Location start) : - this (container, (Flags) 0, parameters, start) + public ToplevelBlock (Block parent, Parameters parameters, Location start) : + this (parent, (Flags) 0, parameters, start) { } - public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic, - Location start) : - this (container, parameters, start) + public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) : + this (parent, parameters, start) { this.generic = generic; } @@ -2563,17 +2567,37 @@ namespace Mono.CSharp { { } - public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) : - base (null, flags | Flags.IsToplevel, start, Location.Null) + // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child. + // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'. + public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) : + base (null, flags, start, Location.Null) { + this.Toplevel = this; + this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; - this.container = container; + this.Parent = parent; + if (parent != null) + parent.AddAnonymousChild (this); + + if (this.parameters.Count != 0) + ProcessParameters (); } public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) { } + protected override void CloneTo (CloneContext clonectx, Statement t) + { + ToplevelBlock target = (ToplevelBlock) t; + base.CloneTo (clonectx, t); + + if (parameters.Count != 0) + target.parameter_info = new ToplevelParameterInfo [parameters.Count]; + for (int i = 0; i < parameters.Count; ++i) + target.parameter_info [i] = new ToplevelParameterInfo (target, i); + } + public bool CheckError158 (string name, Location loc) { if (AnonymousChildren != null) { @@ -2591,10 +2615,50 @@ namespace Mono.CSharp { return true; } + public virtual Expression GetTransparentIdentifier (string name) + { + return null; + } + + void ProcessParameters () + { + int n = parameters.Count; + parameter_info = new ToplevelParameterInfo [n]; + for (int i = 0; i < n; ++i) { + parameter_info [i] = new ToplevelParameterInfo (this, i); + + Parameter p = parameters [i]; + if (p == null) + continue; + + string name = p.Name; + LocalInfo vi = GetLocalInfo (name); + if (vi != null) { + Report.SymbolRelatedToPreviousError (vi.Location, name); + Error_AlreadyDeclared (loc, name, "parent or current"); + continue; + } + + ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name); + if (pi != null) { + Report.SymbolRelatedToPreviousError (pi.Location, name); + Error_AlreadyDeclared (loc, name, "parent or current"); + continue; + } + + AddKnownVariable (name, parameter_info [i]); + } + + // mark this block as "used" so that we create local declarations in a sub-block + // FIXME: This appears to uncover a lot of bugs + //this.Use (); + } + bool DoCheckError158 (string name, Location loc) { LabeledStatement s = LookupLabel (name); if (s != null) { + Report.SymbolRelatedToPreviousError (s.loc, s.Name); Error_158 (name, loc); return false; } @@ -2618,12 +2682,16 @@ namespace Mono.CSharp { return root_scope; } + public override Expression CreateExpressionTree (EmitContext ec) + { + return ((Statement) statements [0]).CreateExpressionTree (ec); + } + public void CreateIteratorHost (RootScopeInfo root) { - Report.Debug (64, "CREATE ITERATOR HOST", this, root, - container, root_scope); + Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope); - if ((container != null) || (root_scope != null)) + if (Parent != null || root_scope != null) throw new InternalErrorException (); scope_info = root_scope = root; @@ -2655,9 +2723,10 @@ namespace Mono.CSharp { // public void ReParent (ToplevelBlock new_parent) { - container = new_parent; + if ((flags & Flags.VariablesInitialized) != 0) + throw new InternalErrorException ("block has already been resolved"); + Parent = new_parent; - new_parent.child = this; } // @@ -2666,37 +2735,19 @@ namespace Mono.CSharp { // 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 (par, this, idx, loc); - } - return null; + ToplevelParameterInfo p = GetParameterInfo (name); + return p == null ? null : new ParameterReference (this, p, loc); } - // - // 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) + public ToplevelParameterInfo GetParameterInfo (string name) { + int idx; for (ToplevelBlock t = this; t != null; t = t.Container) { - if (t.IsLocalParameter (name)) - return true; + Parameter par = t.Parameters.GetParameterByName (name, out idx); + if (par != null) + return t.parameter_info [idx]; } - return false; + return null; } LocalInfo this_variable = null; @@ -2738,6 +2789,7 @@ namespace Mono.CSharp { public bool ResolveMeta (EmitContext ec, Parameters ip) { int errors = Report.Errors; + int orig_count = parameters.Count; if (top_level_branching != null) return true; @@ -2745,37 +2797,80 @@ namespace Mono.CSharp { 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; - } - } + // Assert: orig_count != parameter.Count => orig_count == 0 + if (orig_count != 0 && orig_count != parameters.Count) + throw new InternalErrorException ("parameter information mismatch"); + + int offset = Parent == null ? 0 : Parent.AssignableSlots; + + for (int i = 0; i < orig_count; ++i) { + Parameter.Modifier mod = parameters.ParameterModifier (i); - ResolveMeta (this, ec, ip); + if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT) + continue; + + VariableInfo vi = new VariableInfo (ip, i, offset); + parameter_info [i].VariableInfo = vi; + offset += vi.Length; + } - if (child != null) - child.ResolveMeta (this, ec, ip); + ResolveMeta (ec, offset); top_level_branching = ec.StartFlowBranching (this); return Report.Errors == errors; } + // + // Check whether all `out' parameters have been assigned. + // + public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc) + { + if (vector.IsUnreachable) + return; + + int n = parameter_info == null ? 0 : parameter_info.Length; + + for (int i = 0; i < n; i++) { + VariableInfo var = parameter_info [i].VariableInfo; + + if (var == null) + continue; + + if (vector.IsAssigned (var, false)) + continue; + + Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method", + var.Name); + } + } + public override void EmitMeta (EmitContext ec) { + // Avoid declaring an IL variable for this_variable since it is not accessed + // from the generated IL + if (this_variable != null) + Variables.Remove ("this"); base.EmitMeta (ec); parameters.ResolveVariable (this); } + protected override void EmitSymbolInfo (EmitContext ec) + { + if ((AnonymousContainer != null) && (AnonymousContainer.Scope != null)) + SymbolWriter.DefineScopeVariable (AnonymousContainer.Scope.ID); + + base.EmitSymbolInfo (ec); + } + public void MakeIterator (Iterator iterator) { flags |= Flags.IsIterator; - Block block = new Block (this); + Block block = new ExplicitBlock (this, flags, StartLocation, EndLocation); foreach (Statement stmt in statements) block.AddStatement (stmt); - statements = new ArrayList (); + statements.Clear (); statements.Add (new MoveNextStatement (iterator, block)); } @@ -2886,7 +2981,7 @@ namespace Mono.CSharp { converted = NullStringCase; return true; } - + c = c.ImplicitConversionRequired (required_type, loc); if (c == null) return false; @@ -2895,19 +2990,19 @@ namespace Mono.CSharp { return true; } - public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith) + public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with) { string label; if (converted == null) label = "default"; else if (converted == NullStringCase) label = "null"; - else if (TypeManager.IsEnumType (switchType)) - label = TypeManager.CSharpEnumValue (switchType, converted); + else if (TypeManager.IsEnumType (switch_type)) + label = TypeManager.CSharpEnumValue (switch_type, converted); else label = converted.ToString (); - Report.SymbolRelatedToPreviousError (collisionWith.loc, null); + Report.SymbolRelatedToPreviousError (collision_with.loc, null); Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); } @@ -3011,7 +3106,7 @@ namespace Mono.CSharp { // Expression SwitchGoverningType (EmitContext ec, Expression expr) { - Type t = TypeManager.DropGenericTypeArguments (expr.Type); + Type t = expr.Type; if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || @@ -3024,7 +3119,7 @@ namespace Mono.CSharp { t == TypeManager.char_type || t == TypeManager.string_type || t == TypeManager.bool_type || - t.IsSubclassOf (TypeManager.enum_type)) + TypeManager.IsEnumType (t)) return expr; if (allowed_types == null){ @@ -3095,7 +3190,7 @@ namespace Mono.CSharp { foreach (SwitchLabel sl in ss.Labels){ if (sl.Label == null){ if (default_section != null){ - sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); + sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); error = true; } default_section = ss; @@ -3111,7 +3206,7 @@ namespace Mono.CSharp { try { Elements.Add (key, sl); } catch (ArgumentException) { - sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); + sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); error = true; } } @@ -3170,22 +3265,22 @@ namespace Mono.CSharp { // structure used to hold blocks of keys while calculating table switch class KeyBlock : IComparable { - public KeyBlock (long _nFirst) + public KeyBlock (long _first) { - nFirst = nLast = _nFirst; + first = last = _first; } - public long nFirst; - public long nLast; - public ArrayList rgKeys = null; + public long first; + public long last; + public ArrayList element_keys = null; // how many items are in the bucket public int Size = 1; public int Length { - get { return (int) (nLast - nFirst + 1); } + get { return (int) (last - first + 1); } } - public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast) + public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last) { - return kbLast.nLast - kbFirst.nFirst + 1; + return kb_last.last - kb_first.first + 1; } public int CompareTo (object obj) { @@ -3193,7 +3288,7 @@ namespace Mono.CSharp { int nLength = Length; int nLengthOther = kb.Length; if (nLengthOther == nLength) - return (int) (kb.nFirst - nFirst); + return (int) (kb.first - first); return nLength - nLengthOther; } } @@ -3210,89 +3305,89 @@ namespace Mono.CSharp { /// void TableSwitchEmit (EmitContext ec, LocalBuilder val) { - int cElements = Elements.Count; - object [] rgKeys = new object [cElements]; - Elements.Keys.CopyTo (rgKeys, 0); - Array.Sort (rgKeys); + int element_count = Elements.Count; + object [] element_keys = new object [element_count]; + Elements.Keys.CopyTo (element_keys, 0); + Array.Sort (element_keys); // initialize the block list with one element per key - ArrayList rgKeyBlocks = new ArrayList (); - foreach (object key in rgKeys) - rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); + ArrayList key_blocks = new ArrayList (); + foreach (object key in element_keys) + key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); - KeyBlock kbCurr; + KeyBlock current_kb; // iteratively merge the blocks while they are at least half full // there's probably a really cool way to do this with a tree... - while (rgKeyBlocks.Count > 1) + while (key_blocks.Count > 1) { - ArrayList rgKeyBlocksNew = new ArrayList (); - kbCurr = (KeyBlock) rgKeyBlocks [0]; - for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++) + ArrayList key_blocks_new = new ArrayList (); + current_kb = (KeyBlock) key_blocks [0]; + for (int ikb = 1; ikb < key_blocks.Count; ikb++) { - KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb]; - if ((kbCurr.Size + kb.Size) * 2 >= KeyBlock.TotalLength (kbCurr, kb)) + KeyBlock kb = (KeyBlock) key_blocks [ikb]; + if ((current_kb.Size + kb.Size) * 2 >= KeyBlock.TotalLength (current_kb, kb)) { // merge blocks - kbCurr.nLast = kb.nLast; - kbCurr.Size += kb.Size; + current_kb.last = kb.last; + current_kb.Size += kb.Size; } else { // start a new block - rgKeyBlocksNew.Add (kbCurr); - kbCurr = kb; + key_blocks_new.Add (current_kb); + current_kb = kb; } } - rgKeyBlocksNew.Add (kbCurr); - if (rgKeyBlocks.Count == rgKeyBlocksNew.Count) + key_blocks_new.Add (current_kb); + if (key_blocks.Count == key_blocks_new.Count) break; - rgKeyBlocks = rgKeyBlocksNew; + key_blocks = key_blocks_new; } // initialize the key lists - foreach (KeyBlock kb in rgKeyBlocks) - kb.rgKeys = new ArrayList (); + foreach (KeyBlock kb in key_blocks) + kb.element_keys = new ArrayList (); // fill the key lists int iBlockCurr = 0; - if (rgKeyBlocks.Count > 0) { - kbCurr = (KeyBlock) rgKeyBlocks [0]; - foreach (object key in rgKeys) + if (key_blocks.Count > 0) { + current_kb = (KeyBlock) key_blocks [0]; + foreach (object key in element_keys) { - bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast : - System.Convert.ToInt64 (key) > kbCurr.nLast; - if (fNextBlock) - kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr]; - kbCurr.rgKeys.Add (key); + bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last : + System.Convert.ToInt64 (key) > current_kb.last; + if (next_block) + current_kb = (KeyBlock) key_blocks [++iBlockCurr]; + current_kb.element_keys.Add (key); } } // sort the blocks so we can tackle the largest ones first - rgKeyBlocks.Sort (); + key_blocks.Sort (); // okay now we can start... ILGenerator ig = ec.ig; - Label lblEnd = ig.DefineLabel (); // at the end ;-) - Label lblDefault = ig.DefineLabel (); + Label lbl_end = ig.DefineLabel (); // at the end ;-) + Label lbl_default = ig.DefineLabel (); - Type typeKeys = null; - if (rgKeys.Length > 0) - typeKeys = rgKeys [0].GetType (); // used for conversions + Type type_keys = null; + if (element_keys.Length > 0) + type_keys = element_keys [0].GetType (); // used for conversions Type compare_type; if (TypeManager.IsEnumType (SwitchType)) - compare_type = TypeManager.EnumToUnderlying (SwitchType); + compare_type = TypeManager.GetEnumUnderlyingType (SwitchType); else compare_type = SwitchType; - for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock) + for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock) { - KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]); - lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel (); + KeyBlock kb = ((KeyBlock) key_blocks [iBlock]); + lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel (); if (kb.Length <= 2) { - foreach (object key in kb.rgKeys) + foreach (object key in kb.element_keys) { ig.Emit (OpCodes.Ldloc, val); EmitObjectInteger (ig, key); @@ -3311,17 +3406,17 @@ namespace Mono.CSharp { // check block range (could be > 2^31) ig.Emit (OpCodes.Ldloc, val); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys)); - ig.Emit (OpCodes.Blt, lblDefault); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); + ig.Emit (OpCodes.Blt, lbl_default); ig.Emit (OpCodes.Ldloc, val); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nLast, typeKeys)); - ig.Emit (OpCodes.Bgt, lblDefault); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys)); + ig.Emit (OpCodes.Bgt, lbl_default); // normalize range ig.Emit (OpCodes.Ldloc, val); - if (kb.nFirst != 0) + if (kb.first != 0) { - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys)); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); ig.Emit (OpCodes.Sub); } ig.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels! @@ -3330,15 +3425,15 @@ namespace Mono.CSharp { { // normalize range ig.Emit (OpCodes.Ldloc, val); - int nFirst = (int) kb.nFirst; - if (nFirst > 0) + int first = (int) kb.first; + if (first > 0) { - IntConstant.EmitInt (ig, nFirst); + IntConstant.EmitInt (ig, first); ig.Emit (OpCodes.Sub); } - else if (nFirst < 0) + else if (first < 0) { - IntConstant.EmitInt (ig, -nFirst); + IntConstant.EmitInt (ig, -first); ig.Emit (OpCodes.Add); } } @@ -3346,26 +3441,26 @@ namespace Mono.CSharp { // first, build the list of labels for the switch int iKey = 0; int cJumps = kb.Length; - Label [] rgLabels = new Label [cJumps]; + Label [] switch_labels = new Label [cJumps]; for (int iJump = 0; iJump < cJumps; iJump++) { - object key = kb.rgKeys [iKey]; - if (System.Convert.ToInt64 (key) == kb.nFirst + iJump) + object key = kb.element_keys [iKey]; + if (System.Convert.ToInt64 (key) == kb.first + iJump) { SwitchLabel sl = (SwitchLabel) Elements [key]; - rgLabels [iJump] = sl.GetILLabel (ec); + switch_labels [iJump] = sl.GetILLabel (ec); iKey++; } else - rgLabels [iJump] = lblDefault; + switch_labels [iJump] = lbl_default; } // emit the switch opcode - ig.Emit (OpCodes.Switch, rgLabels); + ig.Emit (OpCodes.Switch, switch_labels); } // mark the default for this block if (iBlock != 0) - ig.MarkLabel (lblDefault); + ig.MarkLabel (lbl_default); } // TODO: find the default case and emit it here, @@ -3373,16 +3468,16 @@ namespace Mono.CSharp { // make sure to mark other labels in the default section // the last default just goes to the end - ig.Emit (OpCodes.Br, lblDefault); + ig.Emit (OpCodes.Br, lbl_default); // now emit the code for the sections - bool fFoundDefault = false; - bool fFoundNull = false; + bool found_default = false; + bool found_null = false; foreach (SwitchSection ss in Sections) { foreach (SwitchLabel sl in ss.Labels) if (sl.Converted == SwitchLabel.NullStringCase) - fFoundNull = true; + found_null = true; } foreach (SwitchSection ss in Sections) @@ -3394,19 +3489,23 @@ namespace Mono.CSharp { if (sl.Converted == SwitchLabel.NullStringCase) ig.MarkLabel (null_target); else if (sl.Label == null) { - ig.MarkLabel (lblDefault); - fFoundDefault = true; - if (!fFoundNull) + ig.MarkLabel (lbl_default); + found_default = true; + if (!found_null) ig.MarkLabel (null_target); } } ss.Block.Emit (ec); } - if (!fFoundDefault) { - ig.MarkLabel (lblDefault); + if (!found_default) { + ig.MarkLabel (lbl_default); + if (HaveUnwrap && !found_null) { + ig.MarkLabel (null_target); + } } - ig.MarkLabel (lblEnd); + + ig.MarkLabel (lbl_end); } // // This simple emit switch works, but does not take advantage of the @@ -3548,7 +3647,7 @@ namespace Mono.CSharp { SwitchType = new_expr.Type; if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) { - Report.FeatureIsNotISO1 (loc, "switch expression of boolean type"); + Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); return false; } @@ -3576,6 +3675,7 @@ namespace Mono.CSharp { } bool first = true; + bool ok = true; foreach (SwitchSection ss in Sections){ if (!first) ec.CurrentBranching.CreateSibling ( @@ -3588,11 +3688,12 @@ namespace Mono.CSharp { // one single section - mark all the others as // unreachable. ec.CurrentBranching.CurrentUsageVector.Goto (); - if (!ss.Block.ResolveUnreachable (ec, true)) - return false; + if (!ss.Block.ResolveUnreachable (ec, true)) { + ok = false; + } } else { if (!ss.Block.Resolve (ec)) - return false; + ok = false; } } @@ -3605,7 +3706,12 @@ namespace Mono.CSharp { Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching); - return true; + if (TypeManager.string_isinterned_string == null) { + TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type, + "IsInterned", loc, TypeManager.string_type); + } + + return ok; } protected override void DoEmit (EmitContext ec) @@ -3740,6 +3846,14 @@ namespace Mono.CSharp { temp = new TemporaryVariable (t, loc); temp.Resolve (ec); + + if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) { + Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true); + TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod ( + monitor_type, "Enter", loc, TypeManager.object_type); + TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod ( + monitor_type, "Exit", loc, TypeManager.object_type); + } return ok; } @@ -3967,24 +4081,13 @@ namespace Mono.CSharp { return false; } - TypeExpr texpr = null; - if (type is VarExpr) { - Unary u = ((Pair) declarators[0]).Second as Unary; - if (u == null) - return false; - - Expression e = u.Expr.Resolve (ec); - if (e == null || e.Type == null) - return false; - - Type t = TypeManager.GetPointerType (e.Type); - texpr = new TypeExpression (t, loc); - } - else - texpr = type.ResolveAsTypeTerminal (ec, false); + TypeExpr texpr = type.ResolveAsContextualType (ec, false); + if (texpr == null) { + if (type is VarExpr) + Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable"); - if (texpr == null) return false; + } expr_type = texpr.Type; @@ -4000,9 +4103,6 @@ namespace Mono.CSharp { LocalInfo vi = (LocalInfo) p.First; Expression e = (Expression) p.Second; - if (type is VarExpr) - vi.VariableType = expr_type; - vi.VariableInfo.SetAssigned (ec); vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed); @@ -4087,6 +4187,17 @@ namespace Mono.CSharp { ec, array_ptr, vi.VariableType, loc); if (converted == null) return false; + + // + // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0]) + // + converted = new Conditional (new Binary (Binary.Operator.LogicalOr, + new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)), + new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))), + NullPointer.Null, + converted); + + converted = converted.Resolve (ec); data [i] = new ExpressionEmitter (converted, vi); i++; @@ -4104,22 +4215,10 @@ namespace Mono.CSharp { } // Case 4: fixed buffer - FieldExpr fe = e as FieldExpr; - if (fe != null) { - IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo); - if (ff != null) { - Expression fixed_buffer_ptr = new FixedBufferPtr (fe, ff.ElementType, loc); - - Expression converted = Convert.ImplicitConversionRequired ( - ec, fixed_buffer_ptr, vi.VariableType, loc); - if (converted == null) - return false; - - data [i] = new ExpressionEmitter (converted, vi); - i++; - - continue; - } + FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr; + if (fixed_buffer_ptr != null) { + data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi); + continue; } // @@ -4168,9 +4267,15 @@ namespace Mono.CSharp { Fixed target = (Fixed) t; target.type = type.Clone (clonectx); - target.declarators = new ArrayList (); - foreach (LocalInfo var in declarators) - target.declarators.Add (clonectx.LookupVariable (var)); + target.declarators = new ArrayList (declarators.Count); + foreach (Pair p in declarators) { + LocalInfo vi = (LocalInfo) p.First; + Expression e = (Expression) p.Second; + + target.declarators.Add ( + new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx))); + } + target.statement = statement.Clone (clonectx); } } @@ -4246,7 +4351,7 @@ namespace Mono.CSharp { type = te.Type; - if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){ + if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){ Error (155, "The type caught or thrown must be derived from System.Exception"); return false; } @@ -4269,9 +4374,11 @@ namespace Mono.CSharp { { Catch target = (Catch) t; - target.type_expr = type_expr.Clone (clonectx); + if (type_expr != null) + target.type_expr = type_expr.Clone (clonectx); + if (VarBlock != null) + target.VarBlock = clonectx.LookupBlock (VarBlock); target.Block = clonectx.LookupBlock (Block); - target.VarBlock = clonectx.LookupBlock (VarBlock); } } @@ -4313,7 +4420,7 @@ namespace Mono.CSharp { Report.Debug (1, "START OF CATCH BLOCKS", vector); - Type[] prevCatches = new Type [Specific.Count]; + Type[] prev_catches = new Type [Specific.Count]; int last_index = 0; foreach (Catch c in Specific){ ec.CurrentBranching.CreateSibling ( @@ -4332,15 +4439,15 @@ namespace Mono.CSharp { if (!c.Resolve (ec)) return false; - Type resolvedType = c.CatchType; + Type resolved_type = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { - if (resolvedType == prevCatches [ii] || resolvedType.IsSubclassOf (prevCatches [ii])) { - Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prevCatches [ii].FullName); + if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) { + Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName); return false; } } - prevCatches [last_index++] = resolvedType; + prev_catches [last_index++] = resolved_type; need_exc_block = true; } @@ -4458,7 +4565,7 @@ namespace Mono.CSharp { Type expr_type; Expression [] resolved_vars; Expression [] converted_vars; - ExpressionStatement [] assign; + Expression [] assign; TemporaryVariable local_copy; public Using (object expression_or_block, Statement stmt, Location l) @@ -4473,97 +4580,52 @@ namespace Mono.CSharp { // bool ResolveLocalVariableDecls (EmitContext ec) { - int i = 0; - - TypeExpr texpr = null; - - if (expr is VarExpr) { - Expression e = ((Expression)((DictionaryEntry)var_list[0]).Value).Resolve (ec); - if (e == null || e.Type == null) - return false; - texpr = new TypeExpression (e.Type, loc); - } - else - texpr = expr.ResolveAsTypeTerminal (ec, false); - - if (texpr == null) - return false; + resolved_vars = new Expression[var_list.Count]; + assign = new Expression [var_list.Count]; + converted_vars = new Expression[var_list.Count]; - expr_type = texpr.Type; - - // - // The type must be an IDisposable or an implicit conversion - // must exist. - // - converted_vars = new Expression [var_list.Count]; - resolved_vars = new Expression [var_list.Count]; - assign = new ExpressionStatement [var_list.Count]; - - bool need_conv = !TypeManager.ImplementsInterface ( - expr_type, TypeManager.idisposable_type); - - foreach (DictionaryEntry e in var_list){ + for (int i = 0; i < assign.Length; ++i) { + DictionaryEntry e = (DictionaryEntry) var_list [i]; Expression var = (Expression) e.Key; - - if (expr is VarExpr) { - LocalVariableReference l = var as LocalVariableReference; - ((LocalInfo)l.Block.Variables[l.Name]).VariableType = expr_type; - ((VarExpr)expr).Handled = true; - } + Expression new_expr = (Expression) e.Value; - var = var.ResolveLValue (ec, new EmptyExpression (), loc); - if (var == null) + Expression a = new Assign (var, new_expr, loc); + a = a.Resolve (ec); + if (a == null) return false; resolved_vars [i] = var; + assign [i] = a; - if (!need_conv) { - i++; + if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) { + converted_vars [i] = var; continue; } - converted_vars [i] = Convert.ImplicitConversion ( - ec, var, TypeManager.idisposable_type, loc); - - if (converted_vars [i] == null) { - Error_IsNotConvertibleToIDisposable (); + a = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location); + if (a == null) { + Error_IsNotConvertibleToIDisposable (var); return false; } - i++; - } - - i = 0; - foreach (DictionaryEntry e in var_list){ - Expression var = resolved_vars [i]; - Expression new_expr = (Expression) e.Value; - Expression a; - - a = new Assign (var, new_expr, loc); - a = a.Resolve (ec); - if (a == null) - return false; - - if (!need_conv) - converted_vars [i] = var; - assign [i] = (ExpressionStatement) a; - i++; + converted_vars [i] = a; } return true; } - void Error_IsNotConvertibleToIDisposable () + static void Error_IsNotConvertibleToIDisposable (Expression expr) { - Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", - TypeManager.CSharpName (expr_type)); + Report.SymbolRelatedToPreviousError (expr.Type); + Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", + expr.GetSignatureForError ()); } bool ResolveExpression (EmitContext ec) { if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){ if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { - Error_IsNotConvertibleToIDisposable (); + Error_IsNotConvertibleToIDisposable (expr); return false; } } @@ -4583,7 +4645,14 @@ namespace Mono.CSharp { int i = 0; for (i = 0; i < assign.Length; i++) { - assign [i].EmitStatement (ec); + ExpressionStatement es = assign [i] as ExpressionStatement; + + if (es != null) + es.EmitStatement (ec); + else { + assign [i].Emit (ec); + ig.Emit (OpCodes.Pop); + } if (emit_finally) ig.BeginExceptionBlock (); @@ -4744,6 +4813,11 @@ namespace Mono.CSharp { // So, ensure there's some IL code after the finally block. ec.NeedReturnLabel (); + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); + } + return ok; } @@ -4767,10 +4841,22 @@ namespace Mono.CSharp { { Using target = (Using) t; - if (expression_or_block is Expression) + if (expression_or_block is Expression) { target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx); - else - target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx); + } else { + DictionaryEntry de = (DictionaryEntry) expression_or_block; + ArrayList var_list = (ArrayList) de.Value; + ArrayList target_var_list = new ArrayList (var_list.Count); + + foreach (DictionaryEntry de_variable in var_list) + target_var_list.Add (new DictionaryEntry ( + ((Expression) de_variable.Key).Clone (clonectx), + ((Expression) de_variable.Value).Clone (clonectx))); + + target.expression_or_block = new DictionaryEntry ( + ((Expression) de.Key).Clone (clonectx), + target_var_list); + } target.Statement = Statement.Clone (clonectx); } @@ -4807,58 +4893,11 @@ namespace Mono.CSharp { if (expr == null) return false; - if (type is VarExpr) { - Type element_type = null; - if (TypeManager.HasElementType (expr.Type)) - element_type = TypeManager.GetElementType (expr.Type); - else { - MethodGroupExpr mg = Expression.MemberLookup ( - ec.ContainerType, expr.Type, "GetEnumerator", MemberTypes.Method, - Expression.AllBindingFlags, loc) as MethodGroupExpr; - - if (mg == null) - return false; - - MethodInfo get_enumerator = null; - foreach (MethodInfo mi in mg.Methods) { - if (TypeManager.GetParameterData (mi).Count != 0) - continue; - if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public) - continue; - if (CollectionForeach.IsOverride (mi)) - continue; - get_enumerator = mi; - } - - if (get_enumerator == null) - return false; - - PropertyInfo pi = TypeManager.GetProperty (get_enumerator.ReturnType, "Current"); - - if (pi == null) - return false; - - element_type = pi.PropertyType; - } - - type = new TypeLookupExpression (element_type.AssemblyQualifiedName); - - LocalVariableReference lv = variable as LocalVariableReference; - ((LocalInfo)lv.Block.Variables[lv.Name]).VariableType = element_type; - } - - Constant c = expr as Constant; - if (c != null && c.GetValue () == null) { + if (expr.IsNull) { Report.Error (186, loc, "Use of null is not valid in this context"); return false; } - TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false); - if (texpr == null) - return false; - - Type var_type = texpr.Type; - if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", expr.ExprClassName); @@ -4879,13 +4918,12 @@ namespace Mono.CSharp { } if (expr.Type.IsArray) { - array = new ArrayForeach (var_type, variable, expr, statement, loc); + array = new ArrayForeach (type, variable, expr, statement, loc); return array.Resolve (ec); - } else { - collection = new CollectionForeach ( - var_type, variable, expr, statement, loc); - return collection.Resolve (ec); } + + collection = new CollectionForeach (type, variable, expr, statement, loc); + return collection.Resolve (ec); } protected override void DoEmit (EmitContext ec) @@ -4933,7 +4971,7 @@ namespace Mono.CSharp { Expression variable, expr, conv; Statement statement; Type array_type; - Type var_type; + Expression var_type; TemporaryVariable[] lengths; ArrayCounter[] counter; int rank; @@ -4941,7 +4979,7 @@ namespace Mono.CSharp { TemporaryVariable copy; Expression access; - public ArrayForeach (Type var_type, Expression var, + public ArrayForeach (Expression var_type, Expression var, Expression expr, Statement stmt, Location l) { this.var_type = var_type; @@ -4977,7 +5015,17 @@ namespace Mono.CSharp { if (access == null) return false; - conv = Convert.ExplicitConversion (ec, access, var_type, loc); + VarExpr ve = var_type as VarExpr; + if (ve != null) { + // Infer implicitly typed local variable from foreach array type + var_type = new TypeExpression (access.Type, ve.Location); + } + + var_type = var_type.ResolveAsTypeTerminal (ec, false); + if (var_type == null) + return false; + + conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc); if (conv == null) return false; @@ -5059,11 +5107,12 @@ namespace Mono.CSharp { MethodGroupExpr get_enumerator; PropertyExpr get_current; MethodInfo move_next; - Type var_type, enumerator_type; + Expression var_type; + Type enumerator_type; bool is_disposable; bool enumerator_found; - public CollectionForeach (Type var_type, Expression var, + public CollectionForeach (Expression var_type, Expression var, Expression expr, Statement stmt, Location l) { this.var_type = var_type; @@ -5108,6 +5157,16 @@ namespace Mono.CSharp { // way I could do this without a goto // + if (TypeManager.bool_movenext_void == null) { + TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod ( + TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes); + } + + if (TypeManager.ienumerator_getcurrent == null) { + TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty ( + TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type); + } + #if GMCS_SOURCE // // Prefer a generic enumerator over a non-generic one. @@ -5231,7 +5290,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (expr.Type)); } - public static bool IsOverride (MethodInfo m) + bool IsOverride (MethodInfo m) { m = (MethodInfo) TypeManager.DropGenericMethodArguments (m); @@ -5311,7 +5370,7 @@ namespace Mono.CSharp { get_current = tmp_get_cur; enumerator_type = tmp_enumerator_type; MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result }; - get_enumerator = new MethodGroupExpr (mi, loc); + get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc); if (t != expr.Type) { expr = Convert.ExplicitConversion ( @@ -5363,10 +5422,20 @@ namespace Mono.CSharp { return false; } + VarExpr ve = var_type as VarExpr; + if (ve != null) { + // Infer implicitly typed local variable from foreach enumerable type + var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location); + } + + var_type = var_type.ResolveAsTypeTerminal (ec, false); + if (var_type == null) + return false; + enumerator = new TemporaryVariable (enumerator_type, loc); enumerator.Resolve (ec); - init = new Invocation (get_enumerator, new ArrayList ()); + init = new Invocation (get_enumerator, null); init = init.Resolve (ec); if (init == null) return false; @@ -5374,16 +5443,16 @@ namespace Mono.CSharp { Expression move_next_expr; { MemberInfo[] mi = new MemberInfo[] { move_next }; - MethodGroupExpr mg = new MethodGroupExpr (mi, loc); + MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc); mg.InstanceExpression = enumerator; - move_next_expr = new Invocation (mg, new ArrayList ()); + move_next_expr = new Invocation (mg, null); } get_current.InstanceExpression = enumerator; Statement block = new CollectionForeachStatement ( - var_type, variable, get_current, statement, loc); + var_type.Type, variable, get_current, statement, loc); loop = new While (move_next_expr, block, loc); @@ -5399,6 +5468,11 @@ namespace Mono.CSharp { if (is_disposable) { ResolveFinally (branching); ec.EndFlowBranching (); + + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); + } } else emit_finally = true;