X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=51a975d549f59797a6eeff5bfbe67ab96fdd1cc1;hb=21dd2b0200d091c43fce9e1941e8ab5e111f3651;hp=45454aa06ff0041c1c69dbd098ac4b0cf04325dd;hpb=50d3a6417b66b26d0923f868f83be54ed60c08fa;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 45454aa06ff..51a975d549f 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -15,8 +15,7 @@ using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Diagnostics; -using System.Collections; -using System.Collections.Specialized; +using System.Collections.Generic; namespace Mono.CSharp { @@ -27,7 +26,7 @@ namespace Mono.CSharp { /// Resolves the statement, true means that all sub-statements /// did resolve ok. // - public virtual bool Resolve (EmitContext ec) + public virtual bool Resolve (BlockContext ec) { return true; } @@ -36,7 +35,7 @@ namespace Mono.CSharp { /// We already know that the statement is unreachable, but we still /// need to resolve it to catch errors. /// - public virtual bool ResolveUnreachable (EmitContext ec, bool warn) + public virtual bool ResolveUnreachable (BlockContext ec, bool warn) { // // This conflicts with csc's way of doing this, but IMHO it's @@ -48,7 +47,7 @@ namespace Mono.CSharp { // if (warn) - Report.Warning (162, 2, loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); bool ok = Resolve (ec); @@ -62,25 +61,6 @@ namespace Mono.CSharp { /// protected abstract void DoEmit (EmitContext ec); - /// - /// Utility wrapper routine for Error, just to beautify the code - /// - public void Error (int error, string format, params object[] args) - { - Error (error, String.Format (format, args)); - } - - public void Error (int error, string s) - { - if (!loc.IsNull) - Report.Error (error, loc, s); - else - Report.Error (error, s); - } - - /// - /// Return value indicates whether all code paths emitted return. - /// public virtual void Emit (EmitContext ec) { ec.Mark (loc); @@ -100,9 +80,9 @@ namespace Mono.CSharp { return s; } - public virtual Expression CreateExpressionTree (EmitContext ec) + public virtual Expression CreateExpressionTree (ResolveContext ec) { - Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); + ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); return null; } @@ -112,96 +92,32 @@ namespace Mono.CSharp { return Clone (clonectx); } - - public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey); } - // - // This class is used during the Statement.Clone operation - // to remap objects that have been cloned. - // - // Since blocks are cloned by Block.Clone, we need a way for - // expressions that must reference the block to be cloned - // pointing to the new cloned block. - // - public class CloneContext { - Hashtable block_map = new Hashtable (); - Hashtable variable_map; - - public void AddBlockMap (Block from, Block to) - { - if (block_map.Contains (from)) - return; - block_map [from] = to; - } - - public Block LookupBlock (Block from) - { - Block result = (Block) block_map [from]; - - if (result == null){ - result = (Block) from.Clone (this); - block_map [from] = result; - } - - 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) - variable_map = new Hashtable (); - - if (variable_map.Contains (from)) - return; - variable_map [from] = to; - } - - public LocalInfo LookupVariable (LocalInfo from) + public sealed class EmptyStatement : Statement + { + public EmptyStatement (Location loc) { - LocalInfo result = (LocalInfo) variable_map [from]; - - if (result == null) - throw new Exception ("LookupVariable: looking up a variable that has not been registered yet"); - - return result; + this.loc = loc; } - } - - public sealed class EmptyStatement : Statement { - - private EmptyStatement () {} - public static readonly EmptyStatement Value = new EmptyStatement (); - - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { return true; } - public override bool ResolveUnreachable (EmitContext ec, bool warn) + public override bool ResolveUnreachable (BlockContext ec, bool warn) { return true; } - protected override void DoEmit (EmitContext ec) + public override void Emit (EmitContext ec) { } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + protected override void DoEmit (EmitContext ec) { + throw new NotSupportedException (); } protected override void CloneTo (CloneContext clonectx, Statement target) @@ -216,77 +132,61 @@ namespace Mono.CSharp { public Statement FalseStatement; bool is_true_ret; - - public If (Expression expr, Statement true_statement, Location l) + + public If (Expression bool_expr, Statement true_statement, Location l) + : this (bool_expr, true_statement, null, l) { - this.expr = expr; - TrueStatement = true_statement; - loc = l; } - public If (Expression expr, + public If (Expression bool_expr, Statement true_statement, Statement false_statement, Location l) { - this.expr = expr; + this.expr = bool_expr; TrueStatement = true_statement; FalseStatement = false_statement; loc = l; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); - TrueStatement.MutateHoistedGenericType (storey); - if (FalseStatement != null) - FalseStatement.MutateHoistedGenericType (storey); - } - - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; Report.Debug (1, "START IF BLOCK", loc); - expr = Expression.ResolveBoolean (ec, expr, loc); - if (expr == null){ + expr = expr.Resolve (ec); + if (expr == null) { ok = false; - goto skip; - } - - Assign ass = expr as Assign; - if (ass != null && ass.Source is Constant) { - Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?"); - } + } else { + // + // Dead code elimination + // + if (expr is Constant) { + bool take = !((Constant) expr).IsDefaultValue; - // - // Dead code elimination - // - if (expr is Constant){ - bool take = !((Constant) expr).IsDefaultValue; + if (take) { + if (!TrueStatement.Resolve (ec)) + return false; - if (take){ - if (!TrueStatement.Resolve (ec)) - return false; + if ((FalseStatement != null) && + !FalseStatement.ResolveUnreachable (ec, true)) + return false; + FalseStatement = null; + } else { + if (!TrueStatement.ResolveUnreachable (ec, true)) + return false; + TrueStatement = null; - if ((FalseStatement != null) && - !FalseStatement.ResolveUnreachable (ec, true)) - return false; - FalseStatement = null; - } else { - if (!TrueStatement.ResolveUnreachable (ec, true)) - return false; - TrueStatement = null; + if ((FalseStatement != null) && + !FalseStatement.Resolve (ec)) + return false; + } - if ((FalseStatement != null) && - !FalseStatement.Resolve (ec)) - return false; + return true; } - - return true; } - skip: + ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc); ok &= TrueStatement.Resolve (ec); @@ -307,8 +207,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - Label false_target = ig.DefineLabel (); + Label false_target = ec.DefineLabel (); Label end; // @@ -334,19 +233,19 @@ namespace Mono.CSharp { if (FalseStatement != null){ bool branch_emitted = false; - end = ig.DefineLabel (); + end = ec.DefineLabel (); if (!is_true_ret){ - ig.Emit (OpCodes.Br, end); + ec.Emit (OpCodes.Br, end); branch_emitted = true; } - ig.MarkLabel (false_target); + ec.MarkLabel (false_target); FalseStatement.Emit (ec); if (branch_emitted) - ig.MarkLabel (end); + ec.MarkLabel (end); } else { - ig.MarkLabel (false_target); + ec.MarkLabel (false_target); } } @@ -364,15 +263,15 @@ namespace Mono.CSharp { public class Do : Statement { public Expression expr; public Statement EmbeddedStatement; - - public Do (Statement statement, Expression bool_expr, Location l) + + public Do (Statement statement, BooleanExpression bool_expr, Location l) { expr = bool_expr; EmbeddedStatement = statement; loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -386,9 +285,9 @@ namespace Mono.CSharp { ec.EndFlowBranching (); if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable) - Report.Warning (162, 2, expr.Location, "Unreachable code detected"); + ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected"); - expr = Expression.ResolveBoolean (ec, expr, loc); + expr = expr.Resolve (ec); if (expr == null) ok = false; else if (expr is Constant){ @@ -404,17 +303,16 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - Label loop = ig.DefineLabel (); + Label loop = ec.DefineLabel (); Label old_begin = ec.LoopBegin; Label old_end = ec.LoopEnd; - ec.LoopBegin = ig.DefineLabel (); - ec.LoopEnd = ig.DefineLabel (); + ec.LoopBegin = ec.DefineLabel (); + ec.LoopEnd = ec.DefineLabel (); - ig.MarkLabel (loop); + ec.MarkLabel (loop); EmbeddedStatement.Emit (ec); - ig.MarkLabel (ec.LoopBegin); + ec.MarkLabel (ec.LoopBegin); // // Dead code elimination @@ -424,22 +322,16 @@ namespace Mono.CSharp { expr.EmitSideEffect (ec); if (res) - ec.ig.Emit (OpCodes.Br, loop); + ec.Emit (OpCodes.Br, loop); } else expr.EmitBranchable (ec, loop, true); - ig.MarkLabel (ec.LoopEnd); + ec.MarkLabel (ec.LoopEnd); ec.LoopBegin = old_begin; ec.LoopEnd = old_end; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); - EmbeddedStatement.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Do target = (Do) t; @@ -453,21 +345,21 @@ namespace Mono.CSharp { public Expression expr; public Statement Statement; bool infinite, empty; - - public While (Expression bool_expr, Statement statement, Location l) + + public While (BooleanExpression bool_expr, Statement statement, Location l) { this.expr = bool_expr; Statement = statement; loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; - expr = Expression.ResolveBoolean (ec, expr, loc); + expr = expr.Resolve (ec); if (expr == null) - return false; + ok = false; // // Inform whether we are infinite or not @@ -508,42 +400,41 @@ namespace Mono.CSharp { return; } - ILGenerator ig = ec.ig; Label old_begin = ec.LoopBegin; Label old_end = ec.LoopEnd; - ec.LoopBegin = ig.DefineLabel (); - ec.LoopEnd = ig.DefineLabel (); + ec.LoopBegin = ec.DefineLabel (); + ec.LoopEnd = ec.DefineLabel (); // // Inform whether we are infinite or not // if (expr is Constant){ // expr is 'true', since the 'empty' case above handles the 'false' case - ig.MarkLabel (ec.LoopBegin); + ec.MarkLabel (ec.LoopBegin); expr.EmitSideEffect (ec); Statement.Emit (ec); - ig.Emit (OpCodes.Br, ec.LoopBegin); + ec.Emit (OpCodes.Br, ec.LoopBegin); // // Inform that we are infinite (ie, `we return'), only // if we do not `break' inside the code. // - ig.MarkLabel (ec.LoopEnd); + ec.MarkLabel (ec.LoopEnd); } else { - Label while_loop = ig.DefineLabel (); + Label while_loop = ec.DefineLabel (); - ig.Emit (OpCodes.Br, ec.LoopBegin); - ig.MarkLabel (while_loop); + ec.Emit (OpCodes.Br, ec.LoopBegin); + ec.MarkLabel (while_loop); Statement.Emit (ec); - ig.MarkLabel (ec.LoopBegin); + ec.MarkLabel (ec.LoopBegin); ec.Mark (loc); expr.EmitBranchable (ec, while_loop, true); - ig.MarkLabel (ec.LoopEnd); + ec.MarkLabel (ec.LoopEnd); } ec.LoopBegin = old_begin; @@ -562,12 +453,6 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); target.Statement = Statement.Clone (clonectx); } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); - Statement.MutateHoistedGenericType (storey); - } } public class For : Statement { @@ -578,7 +463,7 @@ namespace Mono.CSharp { bool infinite, empty; public For (Statement init_statement, - Expression test, + BooleanExpression test, Statement increment, Statement statement, Location l) @@ -590,7 +475,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -600,7 +485,7 @@ namespace Mono.CSharp { } if (Test != null){ - Test = Expression.ResolveBoolean (ec, Test, loc); + Test = Test.Resolve (ec); if (Test == null) ok = false; else if (Test is Constant){ @@ -651,7 +536,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - if (InitStatement != null && InitStatement != EmptyStatement.Value) + if (InitStatement != null) InitStatement.Emit (ec); if (empty) { @@ -659,24 +544,22 @@ namespace Mono.CSharp { return; } - ILGenerator ig = ec.ig; Label old_begin = ec.LoopBegin; Label old_end = ec.LoopEnd; - Label loop = ig.DefineLabel (); - Label test = ig.DefineLabel (); + Label loop = ec.DefineLabel (); + Label test = ec.DefineLabel (); - ec.LoopBegin = ig.DefineLabel (); - ec.LoopEnd = ig.DefineLabel (); + ec.LoopBegin = ec.DefineLabel (); + ec.LoopEnd = ec.DefineLabel (); - ig.Emit (OpCodes.Br, test); - ig.MarkLabel (loop); + ec.Emit (OpCodes.Br, test); + ec.MarkLabel (loop); Statement.Emit (ec); - ig.MarkLabel (ec.LoopBegin); - if (Increment != EmptyStatement.Value) - Increment.Emit (ec); + ec.MarkLabel (ec.LoopBegin); + Increment.Emit (ec); - ig.MarkLabel (test); + ec.MarkLabel (test); // // If test is null, there is no test, and we are just // an infinite loop @@ -689,31 +572,19 @@ namespace Mono.CSharp { // if (Test is Constant) { Test.EmitSideEffect (ec); - ig.Emit (OpCodes.Br, loop); + ec.Emit (OpCodes.Br, loop); } else { Test.EmitBranchable (ec, loop, true); } } else - ig.Emit (OpCodes.Br, loop); - ig.MarkLabel (ec.LoopEnd); + ec.Emit (OpCodes.Br, loop); + ec.MarkLabel (ec.LoopEnd); ec.LoopBegin = old_begin; ec.LoopEnd = old_end; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - if (InitStatement != null) - InitStatement.MutateHoistedGenericType (storey); - if (Test != null) - Test.MutateHoistedGenericType (storey); - if (Increment != null) - Increment.MutateHoistedGenericType (storey); - - Statement.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { For target = (For) t; @@ -737,10 +608,9 @@ namespace Mono.CSharp { loc = expr.Location; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - if (expr != null) - expr = expr.ResolveStatement (ec); + expr = expr.ResolveStatement (ec); return expr != null; } @@ -749,11 +619,6 @@ namespace Mono.CSharp { expr.EmitStatement (ec); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); - } - public override string ToString () { return "StatementExpression (" + expr + ")"; @@ -767,18 +632,67 @@ namespace Mono.CSharp { } } + // + // Simple version of statement list not requiring a block + // + public class StatementList : Statement + { + List statements; + + public StatementList (Statement first, Statement second) + { + statements = new List () { first, second }; + } + + #region Properties + public IList Statements { + get { + return statements; + } + } + #endregion + + public void Add (Statement statement) + { + statements.Add (statement); + } + + public override bool Resolve (BlockContext ec) + { + foreach (var s in statements) + s.Resolve (ec); + + return true; + } + + protected override void DoEmit (EmitContext ec) + { + foreach (var s in statements) + s.Emit (ec); + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + StatementList t = (StatementList) target; + + t.statements = new List (statements.Count); + foreach (Statement s in statements) + t.statements.Add (s.Clone (clonectx)); + } + } + // A 'return' or a 'yield break' public abstract class ExitStatement : Statement { protected bool unwind_protect; - protected abstract bool DoResolve (EmitContext ec); + protected abstract bool DoResolve (BlockContext ec); - public virtual void Error_FinallyClause () + public virtual void Error_FinallyClause (Report Report) { Report.Error (157, loc, "Control cannot leave the body of a finally clause"); } - public sealed override bool Resolve (EmitContext ec) + public sealed override bool Resolve (BlockContext ec) { if (!DoResolve (ec)) return false; @@ -794,63 +708,65 @@ namespace Mono.CSharp { /// /// Implements the return statement /// - public class Return : ExitStatement { + public class Return : ExitStatement + { protected Expression Expr; public Return (Expression expr, Location l) { Expr = expr; loc = l; } - - protected override bool DoResolve (EmitContext ec) + + #region Properties + public Expression Expression { + get { + return Expr; + } + } + #endregion + + protected override bool DoResolve (BlockContext 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)); + ec.Report.Error (126, loc, + "An object of a type convertible to `{0}' is required for the return statement", + TypeManager.CSharpName (ec.ReturnType)); return false; } if (ec.CurrentBlock.Toplevel.IsIterator) { - Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + + ec.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"); } AnonymousExpression am = ec.CurrentAnonymousMethod; 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 ()); + ec.Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void", + ec.GetSignatureForError ()); } Expr = Expr.Resolve (ec); if (Expr == null) return false; + if (ec.HasSet (ResolveContext.Options.InferReturnType)) { + ec.ReturnTypeInference.AddCommonTypeBound (Expr.Type); + return true; + } + if (Expr.Type != ec.ReturnType) { - if (ec.InferReturnType) { - // - // void cannot be used in contextual return - // - if (Expr.Type == TypeManager.void_type) - return false; + Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc); - 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; + if (Expr == null) { + if (am != null) { + ec.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; } } @@ -863,19 +779,13 @@ namespace Mono.CSharp { Expr.Emit (ec); if (unwind_protect) - ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); + ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); } if (unwind_protect) - ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel); + ec.Emit (OpCodes.Leave, ec.ReturnLabel); else - ec.ig.Emit (OpCodes.Ret); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - if (Expr != null) - Expr.MutateHoistedGenericType (storey); + ec.Emit (OpCodes.Ret); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -891,13 +801,12 @@ namespace Mono.CSharp { string target; LabeledStatement label; bool unwind_protect; - - public override bool Resolve (EmitContext ec) + + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } public Goto (string label, Location l) @@ -926,11 +835,7 @@ namespace Mono.CSharp { if (label == null) throw new InternalErrorException ("goto emitted before target resolved"); Label l = label.LabelTarget (ec); - ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { + ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l); } } @@ -939,7 +844,6 @@ namespace Mono.CSharp { bool defined; bool referenced; Label label; - ILGenerator ig; FlowBranching.UsageVector vectors; @@ -953,10 +857,9 @@ namespace Mono.CSharp { { if (defined) return label; - ig = ec.ig; - label = ec.ig.DefineLabel (); - defined = true; + label = ec.DefineLabel (); + defined = true; return label; } @@ -988,7 +891,7 @@ namespace Mono.CSharp { // nothing to clone } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { // this flow-branching will be terminated when the surrounding block ends ec.StartFlowBranching (this); @@ -997,14 +900,8 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - if (ig != null && ig != ec.ig) - throw new InternalErrorException ("cannot happen"); LabelTarget (ec); - ec.ig.MarkLabel (label); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { + ec.MarkLabel (label); } public void AddReference () @@ -1029,28 +926,26 @@ namespace Mono.CSharp { // nothing to clone } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { ec.CurrentBranching.CurrentUsageVector.Goto (); - return true; - } - protected override void DoEmit (EmitContext ec) - { - if (ec.Switch == null){ - Report.Error (153, loc, "A goto case is only valid inside a switch statement"); - return; + if (ec.Switch == null) { + ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement"); + return false; } - if (!ec.Switch.GotDefault){ - FlowBranchingBlock.Error_UnknownLabel (loc, "default"); - return; + if (!ec.Switch.GotDefault) { + FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report); + return false; } - ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); + + return true; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + protected override void DoEmit (EmitContext ec) { + ec.Emit (OpCodes.Br, ec.Switch.DefaultTarget); } } @@ -1067,10 +962,10 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (ec.Switch == null){ - Report.Error (153, loc, "A goto case is only valid inside a switch statement"); + ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement"); return false; } @@ -1082,11 +977,11 @@ namespace Mono.CSharp { Constant c = expr as Constant; if (c == null) { - Error (150, "A constant value is expected"); + ec.Report.Error (150, expr.Location, "A constant value is expected"); return false; } - Type type = ec.Switch.SwitchType; + TypeSpec type = ec.Switch.SwitchType; Constant res = c.TryReduce (ec, type, c.Location); if (res == null) { c.Error_ValueCannotBeConverted (ec, loc, type, true); @@ -1094,7 +989,7 @@ namespace Mono.CSharp { } if (!Convert.ImplicitStandardConversionExists (c, type)) - Report.Warning (469, 2, loc, + ec.Report.Warning (469, 2, loc, "The `goto case' value is not implicitly convertible to type `{0}'", TypeManager.CSharpName (type)); @@ -1102,11 +997,9 @@ namespace Mono.CSharp { if (val == null) val = SwitchLabel.NullStringCase; - sl = (SwitchLabel) ec.Switch.Elements [val]; - - if (sl == null){ + if (!ec.Switch.Elements.TryGetValue (val, out sl)) { FlowBranchingBlock.Error_UnknownLabel (loc, "case " + - (c.GetValue () == null ? "null" : val.ToString ())); + (c.GetValue () == null ? "null" : val.ToString ()), ec.Report); return false; } @@ -1115,12 +1008,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec)); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); + ec.Emit (OpCodes.Br, sl.GetILLabelCode (ec)); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -1140,7 +1028,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (expr == null) { ec.CurrentBranching.CurrentUsageVector.Goto (); @@ -1153,34 +1041,25 @@ namespace Mono.CSharp { if (expr == null) return false; - Type t = expr.Type; + if (Convert.ImplicitConversionExists (ec, expr, TypeManager.exception_type)) + expr = Convert.ImplicitConversion (ec, expr, TypeManager.exception_type, loc); + else + ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception"); - if ((t != TypeManager.exception_type) && - !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && - t != TypeManager.null_type) { - Error (155, "The type caught or thrown must be derived from System.Exception"); - return false; - } return true; } protected override void DoEmit (EmitContext ec) { if (expr == null) - ec.ig.Emit (OpCodes.Rethrow); + ec.Emit (OpCodes.Rethrow); else { expr.Emit (ec); - ec.ig.Emit (OpCodes.Throw); + ec.Emit (OpCodes.Throw); } } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - if (expr != null) - expr.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Throw target = (Throw) t; @@ -1199,23 +1078,18 @@ namespace Mono.CSharp { bool unwind_protect; - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } protected override void DoEmit (EmitContext ec) { - ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd); + ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - } - protected override void CloneTo (CloneContext clonectx, Statement t) { // nothing needed @@ -1231,21 +1105,16 @@ namespace Mono.CSharp { bool unwind_protect; - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } protected override void DoEmit (EmitContext ec) { - ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { + ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -1272,13 +1141,13 @@ namespace Mono.CSharp { public class LocalInfo : IKnownVariable, ILocalVariable { public readonly FullNamedExpression Type; - public Type VariableType; + public TypeSpec VariableType; public readonly string Name; public readonly Location Location; public readonly Block Block; public VariableInfo VariableInfo; - public HoistedVariable HoistedVariableReference; + HoistedVariable hoisted_variant; [Flags] enum Flags : byte { @@ -1309,43 +1178,36 @@ namespace Mono.CSharp { Location = l; } - public LocalInfo (DeclSpace ds, Block block, Location l) + public LocalInfo (TypeContainer ds, Block block, Location l) { - VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder; + VariableType = ds.IsGeneric ? ds.CurrentType : ds.Definition; Block = block; Location = l; } public void ResolveVariable (EmitContext ec) { - if (HoistedVariableReference != null) + if (HoistedVariant != null) return; if (builder == 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); + builder = ec.DeclareLocal (VariableType, Pinned); } } public void Emit (EmitContext ec) { - ec.ig.Emit (OpCodes.Ldloc, builder); + ec.Emit (OpCodes.Ldloc, builder); } public void EmitAssign (EmitContext ec) { - ec.ig.Emit (OpCodes.Stloc, builder); + ec.Emit (OpCodes.Stloc, builder); } public void EmitAddressOf (EmitContext ec) { - ec.ig.Emit (OpCodes.Ldloca, builder); + ec.Emit (OpCodes.Ldloca, builder); } public void EmitSymbolInfo (EmitContext ec) @@ -1354,7 +1216,19 @@ namespace Mono.CSharp { ec.DefineLocalVariable (Name, builder); } - public bool IsThisAssigned (EmitContext ec) + // + // Hoisted local variable variant + // + public HoistedVariable HoistedVariant { + get { + return hoisted_variant; + } + set { + hoisted_variant = value; + } + } + + public bool IsThisAssigned (BlockContext ec, Block block) { if (VariableInfo == null) throw new Exception (); @@ -1362,10 +1236,10 @@ namespace Mono.CSharp { if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo)) return true; - return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc); + return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation); } - public bool IsAssigned (EmitContext ec) + public bool IsAssigned (BlockContext ec) { if (VariableInfo == null) throw new Exception (); @@ -1373,7 +1247,7 @@ namespace Mono.CSharp { return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo); } - public bool Resolve (EmitContext ec) + public bool Resolve (ResolveContext ec) { if (VariableType != null) return true; @@ -1384,16 +1258,13 @@ namespace Mono.CSharp { VariableType = texpr.Type; - if (TypeManager.IsGenericParameter (VariableType)) - return true; - - if (VariableType.IsAbstract && VariableType.IsSealed) { - FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType); + if (VariableType.IsStatic) { + FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType, ec.Report); return false; } - if (VariableType.IsPointer && !ec.InUnsafe) - Expression.UnsafeError (Location); + if (VariableType.IsPointer && !ec.IsUnsafe) + Expression.UnsafeError (ec, Location); return true; } @@ -1512,7 +1383,8 @@ namespace Mono.CSharp { public ToplevelBlock Toplevel; // TODO: Use Explicit [Flags] - public enum Flags : byte { + public enum Flags + { Unchecked = 1, BlockUsed = 2, VariablesInitialized = 4, @@ -1520,8 +1392,10 @@ namespace Mono.CSharp { Unsafe = 16, IsIterator = 32, HasCapturedVariable = 64, - HasCapturedThis = 128 + HasCapturedThis = 1 << 7, + IsExpressionTree = 1 << 8 } + protected Flags flags; public bool Unchecked { @@ -1537,7 +1411,7 @@ namespace Mono.CSharp { // // The statements in this block // - protected ArrayList statements; + protected List statements; // // An array of Blocks. We keep track of children just @@ -1546,35 +1420,37 @@ namespace Mono.CSharp { // Statements and child statements are handled through the // statements. // - ArrayList children; + List children; // // Labels. (label, block) pairs. // - protected HybridDictionary labels; + protected Dictionary labels; // // Keeps track of (name, type) pairs // - IDictionary variables; + Dictionary variables; // // Keeps track of constants - HybridDictionary constants; + Dictionary constants; // // Temporary variables. // - ArrayList temporary_variables; + List temporary_variables; // // If this is a switch section, the enclosing switch block. // Block switch_block; - protected ArrayList scope_initializers; + protected List scope_initializers; - ArrayList anonymous_children; + List anonymous_children; + + int? resolving_init_idx; protected static int id; @@ -1626,33 +1502,37 @@ namespace Mono.CSharp { this.EndLocation = end; this.loc = start; this_id = id++; - statements = new ArrayList (4); + statements = new List (4); } - public Block CreateSwitchBlock (Location start) - { - // FIXME: should this be implicit? - Block new_block = new ExplicitBlock (this, start, start); - new_block.switch_block = this; - return new_block; - } + #region Properties public int ID { get { return this_id; } } - public IDictionary Variables { + public IDictionary Variables { get { if (variables == null) - variables = new ListDictionary (); + variables = new Dictionary (); return variables; } } + #endregion + + public Block CreateSwitchBlock (Location start) + { + // FIXME: should this be implicit? + Block new_block = new ExplicitBlock (this, start, start); + new_block.switch_block = this; + return new_block; + } + void AddChild (Block b) { if (children == null) - children = new ArrayList (1); + children = new List (1); children.Add (b); } @@ -1662,9 +1542,9 @@ namespace Mono.CSharp { EndLocation = loc; } - protected static void Error_158 (string name, Location loc) + protected void Error_158 (string name, Location loc) { - Report.Error (158, loc, "The label `{0}' shadows another label " + + Toplevel.Report.Error (158, loc, "The label `{0}' shadows another label " + "by the same name in a contained scope", name); } @@ -1688,8 +1568,8 @@ namespace Mono.CSharp { while (cur != null) { 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); + Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name); + Toplevel.Report.Error (140, target.loc, "The label `{0}' is a duplicate", name); return false; } @@ -1711,7 +1591,7 @@ namespace Mono.CSharp { if (s == null) continue; - Report.SymbolRelatedToPreviousError (s.loc, s.Name); + Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name); Error_158 (name, target.loc); return false; } @@ -1723,7 +1603,7 @@ namespace Mono.CSharp { Toplevel.CheckError158 (name, target.loc); if (labels == null) - labels = new HybridDictionary(); + labels = new Dictionary (); labels.Add (name, target); return true; @@ -1756,8 +1636,8 @@ namespace Mono.CSharp { return switch_block.LookupLabel (name); if (labels != null) - if (labels.Contains (name)) - return ((LabeledStatement) labels [name]); + if (labels.ContainsKey (name)) + return labels [name]; return null; } @@ -1783,8 +1663,8 @@ namespace Mono.CSharp { // block, we violate the invariant meaning in a block. // if (b == this) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); + Toplevel.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); return false; } @@ -1808,8 +1688,8 @@ namespace Mono.CSharp { return true; if (this is ToplevelBlock) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - e.Error_VariableIsUsedBeforeItIsDeclared (name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); + e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name); return false; } @@ -1817,16 +1697,16 @@ namespace Mono.CSharp { // Even though we detected the error when the name is used, we // treat it as if the variable declaration was in error. // - Report.SymbolRelatedToPreviousError (loc, name); + Toplevel.Report.SymbolRelatedToPreviousError (loc, name); Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; } - protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l) + protected bool CheckParentConflictName (ToplevelBlock block, string name, Location l) { LocalInfo vi = GetLocalInfo (name); if (vi != null) { - Report.SymbolRelatedToPreviousError (vi.Location, name); + block.Report.SymbolRelatedToPreviousError (vi.Location, name); if (Explicit == vi.Block.Explicit) { Error_AlreadyDeclared (l, name, null); } else { @@ -1837,13 +1717,13 @@ namespace Mono.CSharp { } if (block != null) { - Expression e = block.GetParameterReference (name, Location.Null); - if (e != null) { - ParameterReference pr = e as ParameterReference; - if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess)) + var tblock = block.CheckParameterNameConflict (name); + if (tblock != null) { + if (block == tblock && block is Linq.QueryBlock) Error_AlreadyDeclared (loc, name); else Error_AlreadyDeclared (loc, name, "parent or current"); + return false; } } @@ -1856,19 +1736,9 @@ namespace Mono.CSharp { if (!CheckParentConflictName (Toplevel, name, l)) return null; - if (Toplevel.GenericMethod != null) { - foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) { - if (tp.Name == name) { - Report.SymbolRelatedToPreviousError (tp); - Error_AlreadyDeclaredTypeParameter (loc, name, "local variable"); - return null; - } - } - } - IKnownVariable kvi = Explicit.GetKnownVariable (name); if (kvi != null) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); Error_AlreadyDeclared (l, name, "child"); return null; } @@ -1895,7 +1765,7 @@ namespace Mono.CSharp { return; } - Report.Error (136, loc, "A local variable named `{0}' cannot be declared " + + Toplevel.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); @@ -1903,13 +1773,13 @@ namespace Mono.CSharp { protected virtual void Error_AlreadyDeclared (Location loc, string name) { - Report.Error (128, loc, + Toplevel.Report.Error (128, loc, "A local variable named `{0}' is already defined in this scope", name); } public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict) { - Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'", + Toplevel.Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'", name, conflict); } @@ -1919,7 +1789,7 @@ namespace Mono.CSharp { return false; if (constants == null) - constants = new HybridDictionary(); + constants = new Dictionary (); constants.Add (name, value); @@ -1935,7 +1805,7 @@ namespace Mono.CSharp { Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc); if (temporary_variables == null) - temporary_variables = new ArrayList (); + temporary_variables = new List (); int id = ++next_temp_id; string name = "$s_" + id.ToString (); @@ -1950,10 +1820,8 @@ namespace Mono.CSharp { { LocalInfo ret; for (Block b = this; b != null; b = b.Parent) { - if (b.variables != null) { - ret = (LocalInfo) b.variables [name]; - if (ret != null) - return ret; + if (b.variables != null && b.variables.TryGetValue (name, out ret)) { + return ret; } } @@ -1968,10 +1836,10 @@ namespace Mono.CSharp { public Expression GetConstantExpression (string name) { + Expression ret; for (Block b = this; b != null; b = b.Parent) { if (b.constants != null) { - Expression ret = b.constants [name] as Expression; - if (ret != null) + if (b.constants.TryGetValue (name, out ret)) return ret; } } @@ -1985,9 +1853,20 @@ namespace Mono.CSharp { public void AddScopeStatement (Statement s) { if (scope_initializers == null) - scope_initializers = new ArrayList (); + scope_initializers = new List (); - scope_initializers.Add (s); + // + // Simple recursive helper, when resolve scope initializer another + // new scope initializer can be added, this ensures it's initialized + // before existing one. For now this can happen with expression trees + // in base ctor initializer only + // + if (resolving_init_idx.HasValue) { + scope_initializers.Insert (resolving_init_idx.Value, s); + ++resolving_init_idx; + } else { + scope_initializers.Add (s); + } } public void AddStatement (Statement s) @@ -2018,19 +1897,19 @@ namespace Mono.CSharp { } } - public ArrayList AnonymousChildren { + public IList AnonymousChildren { get { return anonymous_children; } } public void AddAnonymousChild (ToplevelBlock b) { if (anonymous_children == null) - anonymous_children = new ArrayList (); + anonymous_children = new List (); anonymous_children.Add (b); } - void DoResolveConstants (EmitContext ec) + void DoResolveConstants (BlockContext ec) { if (constants == null) return; @@ -2038,20 +1917,20 @@ namespace Mono.CSharp { if (variables == null) throw new InternalErrorException ("cannot happen"); - foreach (DictionaryEntry de in variables) { - string name = (string) de.Key; - LocalInfo vi = (LocalInfo) de.Value; - Type variable_type = vi.VariableType; + foreach (var de in variables) { + string name = de.Key; + LocalInfo vi = de.Value; + TypeSpec variable_type = vi.VariableType; if (variable_type == null) { if (vi.Type is VarExpr) - Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); + ec.Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); continue; } - Expression cv = (Expression) constants [name]; - if (cv == null) + Expression cv; + if (!constants.TryGetValue (name, out cv)) continue; // Don't let 'const int Foo = Foo;' succeed. @@ -2059,14 +1938,14 @@ namespace Mono.CSharp { // 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); + if (!variable_type.IsConstantCompatible) { + Const.Error_InvalidConstantType (variable_type, loc, ec.Report); continue; } ec.CurrentBlock = this; Expression e; - using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) { + using (ec.With (ResolveContext.Options.ConstantCheckState, (flags & Flags.Unchecked) == 0)) { e = cv.Resolve (ec); } if (e == null) @@ -2074,14 +1953,14 @@ namespace Mono.CSharp { Constant ce = e as Constant; if (ce == null) { - Const.Error_ExpressionMustBeConstant (vi.Location, name); + e.Error_ExpressionMustBeConstant (ec, vi.Location, name); continue; } - e = ce.ConvertImplicitly (variable_type); + e = ce.ConvertImplicitly (ec, variable_type); if (e == null) { if (TypeManager.IsReferenceType (variable_type)) - Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name); + ce.Error_ConstantCanBeInitializedWithNullOnly (ec, variable_type, vi.Location, vi.Name); else ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false); continue; @@ -2092,13 +1971,13 @@ namespace Mono.CSharp { } } - protected void ResolveMeta (EmitContext ec, int offset) + protected void ResolveMeta (BlockContext ec, int offset) { 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)) { + using (ec.With (ResolveContext.Options.UnsafeScope, ec.IsUnsafe | Unsafe)) { flags |= Flags.VariablesInitialized; if (variables != null) { @@ -2141,27 +2020,27 @@ namespace Mono.CSharp { } } - void UsageWarning () + void UsageWarning (BlockContext ec) { - if (variables == null || Report.WarningLevel < 3) + if (variables == null || ec.Report.WarningLevel < 3) return; - foreach (DictionaryEntry de in variables) { - LocalInfo vi = (LocalInfo) de.Value; + foreach (var de in variables) { + LocalInfo vi = de.Value; if (!vi.Used) { - string name = (string) de.Key; + string name = de.Key; // vi.VariableInfo can be null for 'catch' variables if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned) - Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name); + ec.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); + ec.Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name); } } } - static void CheckPossibleMistakenEmptyStatement (Statement s) + static void CheckPossibleMistakenEmptyStatement (BlockContext ec, Statement s) { Statement body; @@ -2190,21 +2069,32 @@ namespace Mono.CSharp { return; if (body == null || body is EmptyStatement) - Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); + ec.Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { Block prev_block = ec.CurrentBlock; bool ok = true; - int errors = Report.Errors; + int errors = ec.Report.Errors; ec.CurrentBlock = this; ec.StartFlowBranching (this); Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching); + // + // Compiler generated scope statements + // + if (scope_initializers != null) { + for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) { + scope_initializers[resolving_init_idx.Value].Resolve (ec); + } + + resolving_init_idx = null; + } + // // 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 @@ -2213,12 +2103,11 @@ namespace Mono.CSharp { // int statement_count = statements.Count; for (int ix = 0; ix < statement_count; ix++){ - Statement s = (Statement) statements [ix]; + Statement s = statements [ix]; // Check possible empty statement (CS0642) - if (Report.WarningLevel >= 3 && - ix + 1 < statement_count && - statements [ix + 1] is ExplicitBlock) - CheckPossibleMistakenEmptyStatement (s); + if (ix + 1 < statement_count && ec.Report.WarningLevel >= 3 && + statements [ix + 1] is ExplicitBlock) + CheckPossibleMistakenEmptyStatement (ec, s); // // Warn if we detect unreachable code. @@ -2228,7 +2117,7 @@ namespace Mono.CSharp { continue; if (!unreachable_shown && !(s is LabeledStatement)) { - Report.Warning (162, 2, s.loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, s.loc, "Unreachable code detected"); unreachable_shown = true; } @@ -2250,12 +2139,12 @@ namespace Mono.CSharp { if (ec.IsInProbingMode) break; - statements [ix] = EmptyStatement.Value; + statements [ix] = new EmptyStatement (s.loc); continue; } if (unreachable && !(s is LabeledStatement) && !(s is Block)) - statements [ix] = EmptyStatement.Value; + statements [ix] = new EmptyStatement (s.loc); unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable; if (unreachable && s is LabeledStatement) @@ -2280,25 +2169,25 @@ namespace Mono.CSharp { if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable) ok = false; - if ((labels != null) && (Report.WarningLevel >= 2)) { + if ((labels != null) && (ec.Report.WarningLevel >= 2)) { foreach (LabeledStatement label in labels.Values) if (!label.HasBeenReferenced) - Report.Warning (164, 2, label.loc, "This label has not been referenced"); + ec.Report.Warning (164, 2, label.loc, "This label has not been referenced"); } - if (ok && errors == Report.Errors) - UsageWarning (); + if (ok && errors == ec.Report.Errors) + UsageWarning (ec); return ok; } - public override bool ResolveUnreachable (EmitContext ec, bool warn) + public override bool ResolveUnreachable (BlockContext ec, bool warn) { unreachable_shown = true; unreachable = true; if (warn) - Report.Warning (162, 2, loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); bool ok = Resolve (ec); @@ -2310,16 +2199,12 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { for (int ix = 0; ix < statements.Count; ix++){ - Statement s = (Statement) statements [ix]; - s.Emit (ec); + statements [ix].Emit (ec); } } public override void Emit (EmitContext ec) { - Block prev_block = ec.CurrentBlock; - ec.CurrentBlock = this; - if (scope_initializers != null) EmitScopeInitializers (ec); @@ -2328,20 +2213,18 @@ namespace Mono.CSharp { if (SymbolWriter.HasSymbolWriter) EmitSymbolInfo (ec); - - ec.CurrentBlock = prev_block; } protected void EmitScopeInitializers (EmitContext ec) { - SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); + SymbolWriter.OpenCompilerGeneratedBlock (ec); - using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) { + using (ec.With (EmitContext.Options.OmitDebugInfo, true)) { foreach (Statement s in scope_initializers) s.Emit (ec); } - SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); + SymbolWriter.CloseCompilerGeneratedBlock (ec); } protected virtual void EmitSymbolInfo (EmitContext ec) @@ -2353,36 +2236,9 @@ namespace Mono.CSharp { } } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - MutateVariables (storey); - - if (scope_initializers != null) { - foreach (Statement s in scope_initializers) - s.MutateHoistedGenericType (storey); - } - - foreach (Statement s in statements) - s.MutateHoistedGenericType (storey); - } - - void MutateVariables (AnonymousMethodStorey storey) - { - if (variables != null) { - foreach (LocalInfo vi in variables.Values) { - vi.VariableType = storey.MutateType (vi.VariableType); - } - } - - if (temporary_variables != null) { - foreach (LocalInfo vi in temporary_variables) - vi.VariableType = storey.MutateType (vi.VariableType); - } - } - public override string ToString () { - return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation); + return String.Format ("{0} ({1}:{2})", GetType (), this_id, StartLocation); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -2391,27 +2247,27 @@ namespace Mono.CSharp { clonectx.AddBlockMap (this, target); - //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel); + 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 (); + target.variables = new Dictionary (); - foreach (DictionaryEntry de in variables){ - LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx); + foreach (var de in variables){ + LocalInfo newlocal = de.Value.Clone (clonectx); target.variables [de.Key] = newlocal; - clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal); + clonectx.AddVariableMap (de.Value, newlocal); } } - target.statements = new ArrayList (statements.Count); + target.statements = new List (statements.Count); foreach (Statement s in statements) target.statements.Add (s.Clone (clonectx)); if (target.children != null){ - target.children = new ArrayList (children.Count); + target.children = new List (children.Count); foreach (Block b in children){ target.children.Add (clonectx.LookupBlock (b)); } @@ -2423,8 +2279,9 @@ namespace Mono.CSharp { } } - public class ExplicitBlock : Block { - HybridDictionary known_variables; + public class ExplicitBlock : Block + { + Dictionary known_variables; protected AnonymousMethodStorey am_storey; public ExplicitBlock (Block parent, Location start, Location end) @@ -2446,7 +2303,7 @@ namespace Mono.CSharp { internal void AddKnownVariable (string name, IKnownVariable info) { if (known_variables == null) - known_variables = new HybridDictionary(); + known_variables = new Dictionary (); known_variables [name] = info; @@ -2461,7 +2318,7 @@ namespace Mono.CSharp { // // Creates anonymous method storey in current block // - public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec) + public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec) { // // When referencing a variable in iterator storey from children anonymous method @@ -2477,13 +2334,13 @@ namespace Mono.CSharp { return ec.CurrentIterator.Storey; if (am_storey == null) { - MemberBase mc = ec.ResolveContext as MemberBase; + MemberBase mc = ec.MemberContext as MemberBase; GenericMethod gm = mc == null ? null : mc.GenericMethod; // // Creates anonymous method storey for this block // - am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey"); + am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, gm, "AnonStorey"); } return am_storey; @@ -2523,23 +2380,30 @@ namespace Mono.CSharp { while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey) parent = parent.Parent.Explicit; - am_storey.AddParentStoreyReference (parent.am_storey); + am_storey.AddParentStoreyReference (ec, parent.am_storey); } - am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey); + am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey); + + // TODO MemberCache: Review + am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator; } + am_storey.CreateType (); + if (am_storey.Mutator == null && ec.CurrentTypeParameters != null) + am_storey.Mutator = new TypeParameterMutator (ec.CurrentTypeParameters, am_storey.CurrentTypeParameters); + am_storey.DefineType (); - am_storey.ResolveType (); + am_storey.ResolveTypeParameters (); am_storey.Define (); am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey); - ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock; + var ref_blocks = am_storey.ReferencesFromChildrenBlock; if (ref_blocks != null) { foreach (ExplicitBlock ref_block in ref_blocks) { for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) { if (b.am_storey != null) { - b.am_storey.AddParentStoreyReference (am_storey); + b.am_storey.AddParentStoreyReference (ec, am_storey); // Stop propagation inside same top block if (b.Toplevel == Toplevel) @@ -2556,9 +2420,14 @@ namespace Mono.CSharp { base.EmitMeta (ec); } - internal IKnownVariable GetKnownVariable (string name) + public IKnownVariable GetKnownVariable (string name) { - return known_variables == null ? null : (IKnownVariable) known_variables [name]; + if (known_variables == null) + return null; + + IKnownVariable kw; + known_variables.TryGetValue (name, out kw); + return kw; } public bool HasCapturedThis @@ -2593,7 +2462,7 @@ namespace Mono.CSharp { get { return Block.Parameters [Index]; } } - public Type ParameterType { + public TypeSpec ParameterType { get { return Block.Parameters.Types [Index]; } } @@ -2632,17 +2501,16 @@ namespace Mono.CSharp { this.block = block; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { throw new NotSupportedException (); } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { if (child == null) return null; - block.ResolveMeta (ec, ParametersCompiled.EmptyReadOnlyParameters); child = child.Resolve (ec); if (child == null) return null; @@ -2658,23 +2526,23 @@ namespace Mono.CSharp { block.EmitScopeInitializers (ec); child.Emit (ec); } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - type = storey.MutateType (type); - child.MutateHoistedGenericType (storey); - block.MutateHoistedGenericType (storey); - } } - GenericMethod generic; - FlowBranchingToplevel top_level_branching; protected ParametersCompiled parameters; - ToplevelParameterInfo[] parameter_info; + protected ToplevelParameterInfo[] parameter_info; LocalInfo this_variable; + bool resolved; + bool unreachable; + CompilerContext compiler; public HoistedVariable HoistedThisVariable; + public bool Resolved { + get { + return resolved; + } + } + // // The parameters for the block. // @@ -2682,40 +2550,35 @@ namespace Mono.CSharp { get { return parameters; } } - public GenericMethod GenericMethod { - get { return generic; } + public Report Report { + get { return compiler.Report; } } public ToplevelBlock Container { get { return Parent == null ? null : Parent.Toplevel; } } - public ToplevelBlock (Block parent, ParametersCompiled parameters, Location start) : - this (parent, (Flags) 0, parameters, start) + public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, Location start) : + this (ctx, parent, (Flags) 0, parameters, start) { } - public ToplevelBlock (Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) : - this (parent, parameters, start) - { - this.generic = generic; - } - - public ToplevelBlock (ParametersCompiled parameters, Location start) : - this (null, (Flags) 0, parameters, start) + public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) : + this (ctx, null, (Flags) 0, parameters, start) { } - ToplevelBlock (Flags flags, ParametersCompiled parameters, Location start) : - this (null, flags, parameters, start) + ToplevelBlock (CompilerContext ctx, Flags flags, ParametersCompiled parameters, Location start) : + this (ctx, null, flags, parameters, start) { } // 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, ParametersCompiled parameters, Location start) : + public ToplevelBlock (CompilerContext ctx, Block parent, Flags flags, ParametersCompiled parameters, Location start) : base (null, flags, start, Location.Null) { + this.compiler = ctx; this.Toplevel = this; this.parameters = parameters; @@ -2727,8 +2590,8 @@ namespace Mono.CSharp { ProcessParameters (); } - public ToplevelBlock (Location loc) - : this (null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc) + public ToplevelBlock (CompilerContext ctx, Location loc) + : this (ctx, null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc) { } @@ -2737,10 +2600,11 @@ namespace Mono.CSharp { 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); + 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) @@ -2794,7 +2658,7 @@ namespace Mono.CSharp { return true; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { if (statements.Count == 1) { Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec); @@ -2817,7 +2681,7 @@ namespace Mono.CSharp { // Creates block with original statements AddStatement (new IteratorStatement (iterator, new Block (this, source))); - source.statements = new ArrayList (1); + source.statements = new List (1); source.AddStatement (new Return (iterator, iterator.Location)); source.IsIterator = false; @@ -2826,10 +2690,6 @@ namespace Mono.CSharp { return iterator_storey; } - public FlowBranchingToplevel TopLevelBranching { - get { return top_level_branching; } - } - // // Returns a parameter reference expression for the given name, // or null if there is no such parameter @@ -2837,6 +2697,9 @@ namespace Mono.CSharp { public Expression GetParameterReference (string name, Location loc) { for (ToplevelBlock t = this; t != null; t = t.Container) { + if (t.parameters.IsEmpty) + continue; + Expression expr = t.GetParameterReferenceExpression (name, loc); if (expr != null) return expr; @@ -2852,6 +2715,21 @@ namespace Mono.CSharp { null : new ParameterReference (parameter_info [idx], loc); } + public ToplevelBlock CheckParameterNameConflict (string name) + { + for (ToplevelBlock t = this; t != null; t = t.Container) { + if (t.HasParameterWithName (name)) + return t; + } + + return null; + } + + protected virtual bool HasParameterWithName (string name) + { + return parameters.GetParameterIndexByName (name) >= 0; + } + // // Returns the "this" instance variable of this block. // See AddThisVariable() for more information. @@ -2867,7 +2745,7 @@ namespace Mono.CSharp { // analysis code to ensure that it's been fully initialized before control // leaves the constructor. // - public LocalInfo AddThisVariable (DeclSpace ds, Location l) + public LocalInfo AddThisVariable (TypeContainer ds, Location l) { if (this_variable == null) { this_variable = new LocalInfo (ds, this, l); @@ -2885,19 +2763,73 @@ namespace Mono.CSharp { set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; } } - public bool IsThisAssigned (EmitContext ec) - { - return this_variable == null || this_variable.IsThisAssigned (ec); + // + // Block has been converted to expression tree + // + public bool IsExpressionTree { + get { return (flags & Flags.IsExpressionTree) != 0; } } - public bool ResolveMeta (EmitContext ec, ParametersCompiled ip) + public bool IsThisAssigned (BlockContext ec) { - int errors = Report.Errors; - int orig_count = parameters.Count; + return this_variable == null || this_variable.IsThisAssigned (ec, this); + } - if (top_level_branching != null) + public bool Resolve (FlowBranching parent, BlockContext rc, ParametersCompiled ip, IMethodData md) + { + if (resolved) return true; + resolved = true; + + if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) + flags |= Flags.IsExpressionTree; + + try { + if (!ResolveMeta (rc, ip)) + return false; + + using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) { + FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent); + + if (!Resolve (rc)) + return false; + + unreachable = top_level.End (); + } + } catch (Exception e) { + if (e is CompletionResult || rc.Report.IsDisabled) + throw; + + if (rc.CurrentBlock != null) { + rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message); + } else { + rc.Report.Error (587, "Internal compiler error: {0}", e.Message); + } + + if (Report.DebugFlags > 0) + throw; + } + + if (rc.ReturnType != TypeManager.void_type && !unreachable) { + if (rc.CurrentAnonymousMethod == null) { + rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ()); + return false; + } else if (!rc.CurrentAnonymousMethod.IsIterator) { + rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'", + rc.CurrentAnonymousMethod.GetSignatureForError ()); + return false; + } + } + + return true; + } + + bool ResolveMeta (BlockContext ec, ParametersCompiled ip) + { + int errors = ec.Report.Errors; + int orig_count = parameters.Count; + if (ip != null) parameters = ip; @@ -2920,9 +2852,7 @@ namespace Mono.CSharp { ResolveMeta (ec, offset); - top_level_branching = ec.StartFlowBranching (this); - - return Report.Errors == errors; + return ec.Report.Errors == errors; } // @@ -2949,10 +2879,63 @@ namespace Mono.CSharp { } } - public override void EmitMeta (EmitContext ec) + public override void Emit (EmitContext ec) { - parameters.ResolveVariable (); + if (Report.Errors > 0) + return; + +#if PRODUCTION + try { +#endif + EmitMeta (ec); + + if (ec.HasReturnLabel) + ec.ReturnLabel = ec.DefineLabel (); + + base.Emit (ec); + + ec.Mark (EndLocation); + + if (ec.HasReturnLabel) + ec.MarkLabel (ec.ReturnLabel); + + if (ec.return_value != null) { + ec.Emit (OpCodes.Ldloc, ec.return_value); + ec.Emit (OpCodes.Ret); + } else { + // + // If `HasReturnLabel' is set, then we already emitted a + // jump to the end of the method, so we must emit a `ret' + // there. + // + // Unfortunately, System.Reflection.Emit automatically emits + // a leave to the end of a finally block. This is a problem + // if no code is following the try/finally block since we may + // jump to a point after the end of the method. + // As a workaround, we're always creating a return label in + // this case. + // + if (ec.HasReturnLabel || !unreachable) { + if (ec.ReturnType != TypeManager.void_type) + ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ()); + ec.Emit (OpCodes.Ret); + } + } + +#if PRODUCTION + } catch (Exception e){ + Console.WriteLine ("Exception caught by the compiler while emitting:"); + Console.WriteLine (" Block that caused the problem begin at: " + block.loc); + + Console.WriteLine (e.GetType ().FullName + ": " + e.Message); + throw; + } +#endif + } + + 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) @@ -2968,12 +2951,6 @@ namespace Mono.CSharp { base.EmitSymbolInfo (ec); } - - public override void Emit (EmitContext ec) - { - base.Emit (ec); - ec.Mark (EndLocation); - } } public class SwitchLabel { @@ -3016,7 +2993,7 @@ namespace Mono.CSharp { public Label GetILLabel (EmitContext ec) { if (!il_label_set){ - il_label = ec.ig.DefineLabel (); + il_label = ec.DefineLabel (); il_label_set = true; } return il_label; @@ -3025,7 +3002,7 @@ namespace Mono.CSharp { public Label GetILLabelCode (EmitContext ec) { if (!il_label_code_set){ - il_label_code = ec.ig.DefineLabel (); + il_label_code = ec.DefineLabel (); il_label_code_set = true; } return il_label_code; @@ -3035,7 +3012,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, bool allow_nullable) + public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable) { Expression e = label.Resolve (ec); @@ -3044,7 +3021,7 @@ namespace Mono.CSharp { Constant c = e as Constant; if (c == null){ - Report.Error (150, loc, "A constant value is expected"); + ec.Report.Error (150, loc, "A constant value is expected"); return false; } @@ -3066,7 +3043,7 @@ namespace Mono.CSharp { return true; } - public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with) + public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with) { string label; if (converted == null) @@ -3076,8 +3053,8 @@ namespace Mono.CSharp { else label = converted.ToString (); - Report.SymbolRelatedToPreviousError (collision_with.loc, null); - Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); + ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null); + ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); } public SwitchLabel Clone (CloneContext clonectx) @@ -3088,10 +3065,10 @@ namespace Mono.CSharp { public class SwitchSection { // An array of SwitchLabels. - public readonly ArrayList Labels; + public readonly List Labels; public readonly Block Block; - public SwitchSection (ArrayList labels, Block block) + public SwitchSection (List labels, Block block) { Labels = labels; Block = block; @@ -3099,7 +3076,7 @@ namespace Mono.CSharp { public SwitchSection Clone (CloneContext clonectx) { - ArrayList cloned_labels = new ArrayList (); + var cloned_labels = new List (); foreach (SwitchLabel sl in cloned_labels) cloned_labels.Add (sl.Clone (clonectx)); @@ -3109,18 +3086,18 @@ namespace Mono.CSharp { } public class Switch : Statement { - public ArrayList Sections; + public List Sections; public Expression Expr; /// /// Maps constants whose type type SwitchType to their SwitchLabels. /// - public IDictionary Elements; + public IDictionary Elements; /// /// The governing switch type /// - public Type SwitchType; + public TypeSpec SwitchType; // // Computed @@ -3137,28 +3114,22 @@ namespace Mono.CSharp { FieldExpr switch_cache_field; static int unique_counter; -#if GMCS_SOURCE // - // Nullable Types support for GMCS. + // Nullable Types support // 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 // - static Type [] allowed_types; - - public Switch (Expression e, ArrayList sects, Location l) + static TypeSpec [] allowed_types; + + public Switch (Expression e, List sects, Location l) { Expr = e; Sections = sects; @@ -3183,9 +3154,9 @@ namespace Mono.CSharp { // expression that includes any potential conversions to the // integral types or to string. // - Expression SwitchGoverningType (EmitContext ec, Expression expr) + Expression SwitchGoverningType (ResolveContext ec, Expression expr) { - Type t = expr.Type; + TypeSpec t = expr.Type; if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || @@ -3202,7 +3173,7 @@ namespace Mono.CSharp { return expr; if (allowed_types == null){ - allowed_types = new Type [] { + allowed_types = new TypeSpec [] { TypeManager.sbyte_type, TypeManager.byte_type, TypeManager.short_type, @@ -3223,7 +3194,7 @@ namespace Mono.CSharp { // conversions, we have to report an error // Expression converted = null; - foreach (Type tt in allowed_types){ + foreach (TypeSpec tt in allowed_types){ Expression e; e = Convert.ImplicitUserConversion (ec, expr, tt, loc); @@ -3238,7 +3209,7 @@ namespace Mono.CSharp { continue; if (converted != null){ - Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous "); + ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous "); return null; } @@ -3254,18 +3225,16 @@ namespace Mono.CSharp { // It also returns a hashtable with the keys that we will later // use to compute the switch tables // - bool CheckSwitch (EmitContext ec) + bool CheckSwitch (ResolveContext ec) { bool error = false; - Elements = Sections.Count > 10 ? - (IDictionary)new Hashtable () : - (IDictionary)new ListDictionary (); + Elements = new Dictionary (); foreach (SwitchSection ss in Sections){ foreach (SwitchLabel sl in ss.Labels){ if (sl.Label == null){ if (default_section != null){ - sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); + sl.Error_AlreadyOccurs (ec, SwitchType, (SwitchLabel)default_section.Labels [0]); error = true; } default_section = ss; @@ -3284,7 +3253,7 @@ namespace Mono.CSharp { try { Elements.Add (key, sl); } catch (ArgumentException) { - sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); + sl.Error_AlreadyOccurs (ec, SwitchType, Elements [key]); error = true; } } @@ -3292,50 +3261,50 @@ namespace Mono.CSharp { return !error; } - void EmitObjectInteger (ILGenerator ig, object k) + void EmitObjectInteger (EmitContext ec, object k) { if (k is int) - IntConstant.EmitInt (ig, (int) k); + ec.EmitInt ((int) k); else if (k is Constant) { - EmitObjectInteger (ig, ((Constant) k).GetValue ()); + EmitObjectInteger (ec, ((Constant) k).GetValue ()); } else if (k is uint) - IntConstant.EmitInt (ig, unchecked ((int) (uint) k)); + ec.EmitInt (unchecked ((int) (uint) k)); else if (k is long) { if ((long) k >= int.MinValue && (long) k <= int.MaxValue) { - IntConstant.EmitInt (ig, (int) (long) k); - ig.Emit (OpCodes.Conv_I8); + ec.EmitInt ((int) (long) k); + ec.Emit (OpCodes.Conv_I8); } else - LongConstant.EmitLong (ig, (long) k); + ec.EmitLong ((long) k); } else if (k is ulong) { ulong ul = (ulong) k; if (ul < (1L<<32)) { - IntConstant.EmitInt (ig, unchecked ((int) ul)); - ig.Emit (OpCodes.Conv_U8); + ec.EmitInt (unchecked ((int) ul)); + ec.Emit (OpCodes.Conv_U8); } else { - LongConstant.EmitLong (ig, unchecked ((long) ul)); + ec.EmitLong (unchecked ((long) ul)); } } else if (k is char) - IntConstant.EmitInt (ig, (int) ((char) k)); + ec.EmitInt ((int) ((char) k)); else if (k is sbyte) - IntConstant.EmitInt (ig, (int) ((sbyte) k)); + ec.EmitInt ((int) ((sbyte) k)); else if (k is byte) - IntConstant.EmitInt (ig, (int) ((byte) k)); + ec.EmitInt ((int) ((byte) k)); else if (k is short) - IntConstant.EmitInt (ig, (int) ((short) k)); + ec.EmitInt ((int) ((short) k)); else if (k is ushort) - IntConstant.EmitInt (ig, (int) ((ushort) k)); + ec.EmitInt ((int) ((ushort) k)); else if (k is bool) - IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0); + ec.EmitInt (((bool) k) ? 1 : 0); else throw new Exception ("Unhandled case"); } @@ -3349,7 +3318,7 @@ namespace Mono.CSharp { } public long first; public long last; - public ArrayList element_keys = null; + public List element_keys; // how many items are in the bucket public int Size = 1; public int Length @@ -3389,7 +3358,7 @@ namespace Mono.CSharp { Array.Sort (element_keys); // initialize the block list with one element per key - ArrayList key_blocks = new ArrayList (element_count); + var key_blocks = new List (element_count); foreach (object key in element_keys) key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); @@ -3398,7 +3367,7 @@ namespace Mono.CSharp { // there's probably a really cool way to do this with a tree... while (key_blocks.Count > 1) { - ArrayList key_blocks_new = new ArrayList (); + var key_blocks_new = new List (); current_kb = (KeyBlock) key_blocks [0]; for (int ikb = 1; ikb < key_blocks.Count; ikb++) { @@ -3424,7 +3393,7 @@ namespace Mono.CSharp { // initialize the key lists foreach (KeyBlock kb in key_blocks) - kb.element_keys = new ArrayList (); + kb.element_keys = new List (); // fill the key lists int iBlockCurr = 0; @@ -3444,25 +3413,24 @@ namespace Mono.CSharp { key_blocks.Sort (); // okay now we can start... - ILGenerator ig = ec.ig; - Label lbl_end = ig.DefineLabel (); // at the end ;-) + Label lbl_end = ec.DefineLabel (); // at the end ;-) Label lbl_default = default_target; Type type_keys = null; if (element_keys.Length > 0) type_keys = element_keys [0].GetType (); // used for conversions - Type compare_type; + TypeSpec compare_type; if (TypeManager.IsEnumType (SwitchType)) - compare_type = TypeManager.GetEnumUnderlyingType (SwitchType); + compare_type = EnumSpec.GetUnderlyingType (SwitchType); else compare_type = SwitchType; for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock) { KeyBlock kb = ((KeyBlock) key_blocks [iBlock]); - lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel (); + lbl_default = (iBlock == 0) ? default_target : ec.DefineLabel (); if (kb.Length <= 2) { foreach (object key in kb.element_keys) { @@ -3471,8 +3439,8 @@ namespace Mono.CSharp { val.EmitBranchable (ec, sl.GetILLabel (ec), false); } else { val.Emit (ec); - EmitObjectInteger (ig, key); - ig.Emit (OpCodes.Beq, sl.GetILLabel (ec)); + EmitObjectInteger (ec, key); + ec.Emit (OpCodes.Beq, sl.GetILLabel (ec)); } } } @@ -3487,20 +3455,20 @@ namespace Mono.CSharp { // check block range (could be > 2^31) val.Emit (ec); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); - ig.Emit (OpCodes.Blt, lbl_default); + EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys)); + ec.Emit (OpCodes.Blt, lbl_default); val.Emit (ec); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys)); - ig.Emit (OpCodes.Bgt, lbl_default); + EmitObjectInteger (ec, System.Convert.ChangeType (kb.last, type_keys)); + ec.Emit (OpCodes.Bgt, lbl_default); // normalize range val.Emit (ec); if (kb.first != 0) { - EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); - ig.Emit (OpCodes.Sub); + EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys)); + ec.Emit (OpCodes.Sub); } - ig.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels! + ec.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels! } else { @@ -3509,13 +3477,13 @@ namespace Mono.CSharp { int first = (int) kb.first; if (first > 0) { - IntConstant.EmitInt (ig, first); - ig.Emit (OpCodes.Sub); + ec.EmitInt (first); + ec.Emit (OpCodes.Sub); } else if (first < 0) { - IntConstant.EmitInt (ig, -first); - ig.Emit (OpCodes.Add); + ec.EmitInt (-first); + ec.Emit (OpCodes.Add); } } @@ -3536,12 +3504,12 @@ namespace Mono.CSharp { switch_labels [iJump] = lbl_default; } // emit the switch opcode - ig.Emit (OpCodes.Switch, switch_labels); + ec.Emit (OpCodes.Switch, switch_labels); } // mark the default for this block if (iBlock != 0) - ig.MarkLabel (lbl_default); + ec.MarkLabel (lbl_default); } // TODO: find the default case and emit it here, @@ -3550,7 +3518,7 @@ namespace Mono.CSharp { // the last default just goes to the end if (element_keys.Length > 0) - ig.Emit (OpCodes.Br, lbl_default); + ec.Emit (OpCodes.Br, lbl_default); // now emit the code for the sections bool found_default = false; @@ -3558,27 +3526,27 @@ namespace Mono.CSharp { foreach (SwitchSection ss in Sections) { foreach (SwitchLabel sl in ss.Labels) { if (sl.Converted == SwitchLabel.NullStringCase) { - ig.MarkLabel (null_target); + ec.MarkLabel (null_target); } else if (sl.Label == null) { - ig.MarkLabel (lbl_default); + ec.MarkLabel (lbl_default); found_default = true; if (!has_null_case) - ig.MarkLabel (null_target); + ec.MarkLabel (null_target); } - ig.MarkLabel (sl.GetILLabel (ec)); - ig.MarkLabel (sl.GetILLabelCode (ec)); + ec.MarkLabel (sl.GetILLabel (ec)); + ec.MarkLabel (sl.GetILLabelCode (ec)); } ss.Block.Emit (ec); } if (!found_default) { - ig.MarkLabel (lbl_default); + ec.MarkLabel (lbl_default); if (!has_null_case) { - ig.MarkLabel (null_target); + ec.MarkLabel (null_target); } } - ig.MarkLabel (lbl_end); + ec.MarkLabel (lbl_end); } SwitchSection FindSection (SwitchLabel label) @@ -3593,19 +3561,13 @@ namespace Mono.CSharp { return null; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - foreach (SwitchSection ss in Sections) - ss.Block.MutateHoistedGenericType (storey); - } - public static void Reset () { unique_counter = 0; allowed_types = null; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { Expr = Expr.Resolve (ec); if (Expr == null) @@ -3613,7 +3575,6 @@ namespace Mono.CSharp { new_expr = SwitchGoverningType (ec, Expr); -#if GMCS_SOURCE if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) { unwrap = Nullable.Unwrap.Create (Expr, false); if (unwrap == null) @@ -3621,10 +3582,11 @@ namespace Mono.CSharp { 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"); + ec.Report.Error (151, loc, + "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", + TypeManager.CSharpName (Expr.Type)); return false; } @@ -3632,7 +3594,7 @@ namespace Mono.CSharp { SwitchType = new_expr.Type; if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) { - Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); + ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); return false; } @@ -3649,12 +3611,14 @@ namespace Mono.CSharp { Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching); ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc); - is_constant = new_expr is Constant; - if (is_constant) { - object key = ((Constant) new_expr).GetValue (); - SwitchLabel label = (SwitchLabel) Elements [key]; + var constant = new_expr as Constant; + if (constant != null) { + is_constant = true; + object key = constant.GetValue (); + SwitchLabel label; + if (Elements.TryGetValue (key, out label)) + constant_section = FindSection (label); - constant_section = FindSection (label); if (constant_section == null) constant_section = default_section; } @@ -3702,68 +3666,71 @@ namespace Mono.CSharp { return true; } - void ResolveStringSwitchMap (EmitContext ec) + void ResolveStringSwitchMap (ResolveContext ec) { FullNamedExpression string_dictionary_type; -#if GMCS_SOURCE - MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", - new TypeArguments ( - new TypeExpression (TypeManager.string_type, loc), - new TypeExpression (TypeManager.int32_type, loc)), loc); -#else - MemberAccess system_collections_generic = new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); -#endif - Field field = new Field (ec.TypeContainer, string_dictionary_type, + if (TypeManager.generic_ienumerable_type != null) { + MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", + new TypeArguments ( + new TypeExpression (TypeManager.string_type, loc), + new TypeExpression (TypeManager.int32_type, loc)), loc); + } else { + MemberAccess system_collections_generic = new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); + } + + var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer; + Field field = new Field (ctype, string_dictionary_type, Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); if (!field.Define ()) return; - ec.TypeContainer.PartialContainer.AddField (field); + ctype.AddField (field); - ArrayList init = new ArrayList (); + var init = new List (); int counter = 0; Elements.Clear (); string value = null; foreach (SwitchSection section in Sections) { + int last_count = init.Count; foreach (SwitchLabel sl in section.Labels) { - if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) { - value = null; + if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) continue; - } value = (string) sl.Converted; - ArrayList init_args = new ArrayList (2); + var init_args = new List (2); init_args.Add (new StringLiteral (value, sl.Location)); init_args.Add (new IntConstant (counter, loc)); init.Add (new CollectionElementInitializer (init_args, loc)); } - if (value == null) + // + // Don't add empty sections + // + if (last_count == init.Count) continue; Elements.Add (counter, section.Labels [0]); ++counter; } - ArrayList args = new ArrayList (1); - args.Add (new Argument (new IntConstant (Sections.Count, loc))); + Arguments args = new Arguments (1); + args.Add (new Argument (new IntConstant (init.Count, loc))); Expression initializer = new NewInitialize (string_dictionary_type, args, new CollectionOrObjectInitializers (init, loc), loc); - switch_cache_field = new FieldExpr (field.FieldBuilder, loc); + switch_cache_field = new FieldExpr (field, loc); string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec)); } void DoEmitStringSwitch (LocalTemporary value, EmitContext ec) { - ILGenerator ig = ec.ig; - Label l_initialized = ig.DefineLabel (); + Label l_initialized = ec.DefineLabel (); // // Skip initialization when value is null @@ -3775,62 +3742,61 @@ namespace Mono.CSharp { // switch_cache_field.EmitBranchable (ec, l_initialized, true); string_dictionary.EmitStatement (ec); - ig.MarkLabel (l_initialized); + ec.MarkLabel (l_initialized); LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type); -#if GMCS_SOURCE - ArrayList get_value_args = new ArrayList (2); - get_value_args.Add (new Argument (value)); - get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); - Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec); - if (get_item == null) - return; + ResolveContext rc = new ResolveContext (ec.MemberContext); - // - // A value was not found, go to default case - // - get_item.EmitBranchable (ec, default_target, false); -#else - ArrayList get_value_args = new ArrayList (1); - get_value_args.Add (value); + if (TypeManager.generic_ienumerable_type != null) { + Arguments get_value_args = new Arguments (2); + get_value_args.Add (new Argument (value)); + get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); + Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc); + if (get_item == null) + return; - Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec); - if (get_item == null) - return; + // + // A value was not found, go to default case + // + get_item.EmitBranchable (ec, default_target, false); + } else { + Arguments get_value_args = new Arguments (1); + get_value_args.Add (new Argument (value)); - LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); - get_item_object.EmitAssign (ec, get_item, true, false); - ec.ig.Emit (OpCodes.Brfalse, default_target); + Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args, loc), loc).Resolve (rc); + if (get_item == null) + return; - ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, - new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec); + LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); + get_item_object.EmitAssign (ec, get_item, true, false); + ec.Emit (OpCodes.Brfalse, default_target); + + ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, + new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc); + + get_item_int.EmitStatement (ec); + get_item_object.Release (ec); + } - get_item_int.EmitStatement (ec); - get_item_object.Release (ec); -#endif TableSwitchEmit (ec, string_switch_variable); string_switch_variable.Release (ec); } protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - - default_target = ig.DefineLabel (); - null_target = ig.DefineLabel (); + default_target = ec.DefineLabel (); + null_target = ec.DefineLabel (); // Store variable for comparission purposes // TODO: Don't duplicate non-captured VariableReference LocalTemporary value; if (HaveUnwrap) { value = new LocalTemporary (SwitchType); -#if GMCS_SOURCE unwrap.EmitCheck (ec); - ig.Emit (OpCodes.Brfalse, null_target); + ec.Emit (OpCodes.Brfalse, null_target); new_expr.Emit (ec); value.Store (ec); -#endif } else if (!is_constant) { value = new LocalTemporary (SwitchType); new_expr.Emit (ec); @@ -3844,7 +3810,7 @@ namespace Mono.CSharp { Label old_end = ec.LoopEnd; Switch old_switch = ec.Switch; - ec.LoopEnd = ig.DefineLabel (); + ec.LoopEnd = ec.DefineLabel (); ec.Switch = this; // Emit Code. @@ -3861,7 +3827,7 @@ namespace Mono.CSharp { value.Release (ec); // Restore context state. - ig.MarkLabel (ec.LoopEnd); + ec.MarkLabel (ec.LoopEnd); // // Restore the previous context @@ -3875,7 +3841,7 @@ namespace Mono.CSharp { Switch target = (Switch) t; target.Expr = Expr.Clone (clonectx); - target.Sections = new ArrayList (); + target.Sections = new List (); foreach (SwitchSection ss in Sections){ target.Sections.Add (ss.Clone (clonectx)); } @@ -3892,7 +3858,7 @@ namespace Mono.CSharp { { if (!prepared) { prepared = true; - resume_point = ec.ig.DefineLabel (); + resume_point = ec.DefineLabel (); } return resume_point; } @@ -3910,6 +3876,9 @@ namespace Mono.CSharp { public abstract class ExceptionStatement : ResumableStatement { bool code_follows; + Iterator iter; + List resume_points; + int first_resume_pc; protected abstract void EmitPreTryBody (EmitContext ec); protected abstract void EmitTryBody (EmitContext ec); @@ -3917,47 +3886,45 @@ namespace Mono.CSharp { protected sealed override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - EmitPreTryBody (ec); if (resume_points != null) { - IntConstant.EmitInt (ig, (int) Iterator.State.Running); - ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC); + ec.EmitInt ((int) Iterator.State.Running); + ec.Emit (OpCodes.Stloc, iter.CurrentPC); } - ig.BeginExceptionBlock (); + ec.BeginExceptionBlock (); if (resume_points != null) { - ig.MarkLabel (resume_point); + ec.MarkLabel (resume_point); // For normal control flow, we want to fall-through the Switch // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above - ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC); - IntConstant.EmitInt (ig, first_resume_pc); - ig.Emit (OpCodes.Sub); + ec.Emit (OpCodes.Ldloc, iter.CurrentPC); + ec.EmitInt (first_resume_pc); + ec.Emit (OpCodes.Sub); Label [] labels = new Label [resume_points.Count]; for (int i = 0; i < resume_points.Count; ++i) labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec); - ig.Emit (OpCodes.Switch, labels); + ec.Emit (OpCodes.Switch, labels); } EmitTryBody (ec); - ig.BeginFinallyBlock (); + ec.BeginFinallyBlock (); - Label start_finally = ec.ig.DefineLabel (); + Label start_finally = ec.DefineLabel (); if (resume_points != null) { - ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally); - ig.Emit (OpCodes.Brfalse_S, start_finally); - ig.Emit (OpCodes.Endfinally); + ec.Emit (OpCodes.Ldloc, iter.SkipFinally); + ec.Emit (OpCodes.Brfalse_S, start_finally); + ec.Emit (OpCodes.Endfinally); } - ig.MarkLabel (start_finally); + ec.MarkLabel (start_finally); EmitFinallyBody (ec); - ig.EndExceptionBlock (); + ec.EndExceptionBlock (); } public void SomeCodeFollows () @@ -3965,21 +3932,21 @@ namespace Mono.CSharp { code_follows = true; } - protected void ResolveReachability (EmitContext ec) + public override bool Resolve (BlockContext ec) { // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause // So, ensure there's some IL code after this statement. if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable) ec.NeedReturnLabel (); + iter = ec.CurrentIterator; + return true; } - ArrayList resume_points; - int first_resume_pc; public void AddResumePoint (ResumableStatement stmt, int pc) { if (resume_points == null) { - resume_points = new ArrayList (); + resume_points = new List (); first_resume_pc = pc; } @@ -3995,7 +3962,7 @@ namespace Mono.CSharp { { if (!prepared_for_dispose) { prepared_for_dispose = true; - dispose_try_block = ec.ig.DefineLabel (); + dispose_try_block = ec.DefineLabel (); } return dispose_try_block; } @@ -4007,17 +3974,15 @@ namespace Mono.CSharp { emitted_dispose = true; - ILGenerator ig = ec.ig; - - Label end_of_try = ig.DefineLabel (); + Label end_of_try = ec.DefineLabel (); // Ensure that the only way we can get into this code is through a dispatcher if (have_dispatcher) - ig.Emit (OpCodes.Br, end); + ec.Emit (OpCodes.Br, end); - ig.BeginExceptionBlock (); + ec.BeginExceptionBlock (); - ig.MarkLabel (dispose_try_block); + ec.MarkLabel (dispose_try_block); Label [] labels = null; for (int i = 0; i < resume_points.Count; ++i) { @@ -4042,10 +4007,10 @@ namespace Mono.CSharp { if (emit_dispatcher) { //SymbolWriter.StartIteratorDispatcher (ec.ig); - ig.Emit (OpCodes.Ldloc, iterator.CurrentPC); - IntConstant.EmitInt (ig, first_resume_pc); - ig.Emit (OpCodes.Sub); - ig.Emit (OpCodes.Switch, labels); + ec.Emit (OpCodes.Ldloc, iterator.CurrentPC); + ec.EmitInt (first_resume_pc); + ec.Emit (OpCodes.Sub); + ec.Emit (OpCodes.Switch, labels); //SymbolWriter.EndIteratorDispatcher (ec.ig); } @@ -4053,13 +4018,13 @@ namespace Mono.CSharp { s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher); } - ig.MarkLabel (end_of_try); + ec.MarkLabel (end_of_try); - ig.BeginFinallyBlock (); + ec.BeginFinallyBlock (); EmitFinallyBody (ec); - ig.EndExceptionBlock (); + ec.EndExceptionBlock (); } } @@ -4075,14 +4040,14 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) return false; if (!TypeManager.IsReferenceType (expr.Type)){ - Report.Error (185, loc, + ec.Report.Error (185, loc, "`{0}' is not a reference type as required by the lock statement", TypeManager.CSharpName (expr.Type)); return false; @@ -4092,11 +4057,11 @@ namespace Mono.CSharp { bool ok = Statement.Resolve (ec); ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); // Avoid creating libraries that reference the internal // mcs NullType: - Type t = expr.Type; + TypeSpec t = expr.Type; if (t == TypeManager.null_type) t = TypeManager.object_type; @@ -4104,7 +4069,7 @@ namespace Mono.CSharp { 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); + TypeSpec monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", MemberKind.Class, true); TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod ( monitor_type, "Enter", loc, TypeManager.object_type); TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod ( @@ -4116,11 +4081,9 @@ namespace Mono.CSharp { protected override void EmitPreTryBody (EmitContext ec) { - ILGenerator ig = ec.ig; - temp.EmitAssign (ec, expr); temp.Emit (ec); - ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object); + ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object); } protected override void EmitTryBody (EmitContext ec) @@ -4131,16 +4094,9 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { temp.Emit (ec); - ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object); + ec.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr.MutateHoistedGenericType (storey); - temp.MutateHoistedGenericType (storey); - Statement.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Lock target = (Lock) t; @@ -4153,29 +4109,25 @@ namespace Mono.CSharp { public class Unchecked : Statement { public Block Block; - public Unchecked (Block b) + public Unchecked (Block b, Location loc) { Block = b; b.Unchecked = true; + this.loc = loc; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + using (ec.With (ResolveContext.Options.AllCheckStateFlags, false)) return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + using (ec.With (EmitContext.Options.AllCheckStateFlags, false)) Block.Emit (ec); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - Block.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Unchecked target = (Unchecked) t; @@ -4187,29 +4139,25 @@ namespace Mono.CSharp { public class Checked : Statement { public Block Block; - public Checked (Block b) + public Checked (Block b, Location loc) { Block = b; b.Unchecked = false; + this.loc = loc; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) - return Block.Resolve (ec); + using (ec.With (ResolveContext.Options.AllCheckStateFlags, true)) + return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + using (ec.With (EmitContext.Options.AllCheckStateFlags, true)) Block.Emit (ec); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - Block.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Checked target = (Checked) t; @@ -4221,27 +4169,25 @@ namespace Mono.CSharp { public class Unsafe : Statement { public Block Block; - public Unsafe (Block b) + public Unsafe (Block b, Location loc) { Block = b; Block.Unsafe = true; + this.loc = loc; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.InUnsafe, true)) + if (ec.CurrentIterator != null) + ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators"); + + using (ec.Set (ResolveContext.Options.UnsafeScope)) return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.InUnsafe, true)) - Block.Emit (ec); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - Block.MutateHoistedGenericType (storey); + Block.Emit (ec); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -4257,9 +4203,9 @@ namespace Mono.CSharp { // public class Fixed : Statement { Expression type; - ArrayList declarators; + List> declarators; Statement statement; - Type expr_type; + TypeSpec expr_type; Emitter[] data; bool has_ret; @@ -4294,8 +4240,8 @@ namespace Mono.CSharp { public override void EmitExit (EmitContext ec) { - ec.ig.Emit (OpCodes.Ldc_I4_0); - ec.ig.Emit (OpCodes.Conv_U); + ec.Emit (OpCodes.Ldc_I4_0); + ec.Emit (OpCodes.Conv_U); vi.EmitAssign (ec); } } @@ -4311,44 +4257,45 @@ namespace Mono.CSharp { pinned_string.Pinned = true; } + public StringEmitter Resolve (ResolveContext rc) + { + pinned_string.Resolve (rc); + + if (TypeManager.int_get_offset_to_string_data == null) { + TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty ( + TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type); + } + + return this; + } + public override void Emit (EmitContext ec) { - pinned_string.Resolve (ec); pinned_string.ResolveVariable (ec); converted.Emit (ec); pinned_string.EmitAssign (ec); - PropertyInfo p = TypeManager.int_get_offset_to_string_data; - if (p == null) { - // TODO: Move to resolve - p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty ( - TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type); - - if (p == null) - return; - } - // TODO: Should use Binary::Add pinned_string.Emit (ec); - ec.ig.Emit (OpCodes.Conv_I); + ec.Emit (OpCodes.Conv_I); - PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location); + PropertyExpr pe = new PropertyExpr (TypeManager.int_get_offset_to_string_data, pinned_string.Location); //pe.InstanceExpression = pinned_string; - pe.Resolve (ec).Emit (ec); + pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec); - ec.ig.Emit (OpCodes.Add); + ec.Emit (OpCodes.Add); vi.EmitAssign (ec); } public override void EmitExit (EmitContext ec) { - ec.ig.Emit (OpCodes.Ldnull); + ec.Emit (OpCodes.Ldnull); pinned_string.EmitAssign (ec); } } - public Fixed (Expression type, ArrayList decls, Statement stmt, Location l) + public Fixed (Expression type, List> decls, Statement stmt, Location l) { this.type = type; declarators = decls; @@ -4360,17 +4307,17 @@ namespace Mono.CSharp { get { return statement; } } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - if (!ec.InUnsafe){ - Expression.UnsafeError (loc); + if (!ec.IsUnsafe){ + Expression.UnsafeError (ec, loc); return 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"); + ec.Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable"); return false; } @@ -4380,14 +4327,14 @@ namespace Mono.CSharp { data = new Emitter [declarators.Count]; if (!expr_type.IsPointer){ - Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type"); + ec.Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type"); return false; } int i = 0; - foreach (Pair p in declarators){ - LocalInfo vi = (LocalInfo) p.First; - Expression e = (Expression) p.Second; + foreach (var p in declarators){ + LocalInfo vi = p.Key; + Expression e = p.Value; vi.VariableInfo.SetAssigned (ec); vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed); @@ -4404,13 +4351,14 @@ namespace Mono.CSharp { // if (e is Cast){ - Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); + ec.Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); return false; } - ec.InFixedInitializer = true; - e = e.Resolve (ec); - ec.InFixedInitializer = false; + using (ec.Set (ResolveContext.Options.FixedInitializerScope)) { + e = e.Resolve (ec); + } + if (e == null) return false; @@ -4418,12 +4366,12 @@ namespace Mono.CSharp { // Case 2: Array // if (e.Type.IsArray){ - Type array_type = TypeManager.GetElementType (e.Type); + TypeSpec array_type = TypeManager.GetElementType (e.Type); // // Provided that array_type is unmanaged, // - if (!TypeManager.VerifyUnManaged (array_type, loc)) + if (!TypeManager.VerifyUnmanaged (ec.Compiler, array_type, loc)) return false; // @@ -4440,11 +4388,11 @@ namespace Mono.CSharp { // // 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))), + converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr, + new Binary (Binary.Operator.Equality, e, new NullLiteral (loc), loc), + new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc), loc), loc)), new NullPointer (loc), - converted); + converted, loc); converted = converted.Resolve (ec); @@ -4458,7 +4406,7 @@ namespace Mono.CSharp { // Case 3: string // if (e.Type == TypeManager.string_type){ - data [i] = new StringEmitter (e, vi, loc); + data [i] = new StringEmitter (e, vi, loc).Resolve (ec); i++; continue; } @@ -4481,7 +4429,7 @@ namespace Mono.CSharp { } if (data [i++] == null) - Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression"); + ec.Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression"); e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc); } @@ -4513,24 +4461,15 @@ namespace Mono.CSharp { } } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - // Fixed statement cannot be used inside anonymous methods or lambdas - throw new NotSupportedException (); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Fixed target = (Fixed) t; target.type = type.Clone (clonectx); - 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.declarators = new List> (declarators.Count); + foreach (var p in declarators) { + target.declarators.Add (new KeyValuePair ( + clonectx.LookupVariable (p.Key), p.Value.Clone (clonectx))); } target.statement = statement.Clone (clonectx); @@ -4543,7 +4482,7 @@ namespace Mono.CSharp { public Block VarBlock; Expression type_expr; - Type type; + TypeSpec type; public Catch (Expression type, string name, Block block, Block var_block, Location l) { @@ -4554,7 +4493,7 @@ namespace Mono.CSharp { loc = l; } - public Type CatchType { + public TypeSpec CatchType { get { return type; } @@ -4568,12 +4507,10 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - if (CatchType != null) - ig.BeginCatchBlock (CatchType); + ec.BeginCatchBlock (CatchType); else - ig.BeginCatchBlock (TypeManager.object_type); + ec.BeginCatchBlock (TypeManager.object_type); if (VarBlock != null) VarBlock.Emit (ec); @@ -4581,13 +4518,11 @@ namespace Mono.CSharp { if (Name != null) { // TODO: Move to resolve LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); - lvr.Resolve (ec); + lvr.Resolve (new ResolveContext (ec.MemberContext)); -#if GMCS_SOURCE // Only to make verifier happy if (TypeManager.IsGenericParameter (lvr.Type)) - ig.Emit (OpCodes.Unbox_Any, lvr.Type); -#endif + ec.Emit (OpCodes.Unbox_Any, lvr.Type); Expression source; if (lvr.IsHoisted) { @@ -4601,14 +4536,14 @@ namespace Mono.CSharp { lvr.EmitAssign (ec, source, false, false); } else - ig.Emit (OpCodes.Pop); + ec.Emit (OpCodes.Pop); Block.Emit (ec); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.InCatch, true)) { + using (ec.With (ResolveContext.Options.CatchScope, true)) { if (type_expr != null) { TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); if (te == null) @@ -4617,7 +4552,7 @@ namespace Mono.CSharp { type = te.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"); + ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); return false; } } else @@ -4635,15 +4570,6 @@ namespace Mono.CSharp { } } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - if (type != null) - type = storey.MutateType (type); - if (VarBlock != null) - VarBlock.MutateHoistedGenericType (storey); - Block.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { Catch target = (Catch) t; @@ -4667,7 +4593,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -4678,14 +4604,14 @@ namespace Mono.CSharp { if (ok) ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally); - using (ec.With (EmitContext.Flags.InFinally, true)) { + using (ec.With (ResolveContext.Options.FinallyScope, true)) { if (!fini.Resolve (ec)) ok = false; } ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); return ok; } @@ -4704,12 +4630,6 @@ namespace Mono.CSharp { fini.Emit (ec); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - stmt.MutateHoistedGenericType (storey); - fini.MutateHoistedGenericType (storey); - } - protected override void CloneTo (CloneContext clonectx, Statement t) { TryFinally target = (TryFinally) t; @@ -4722,32 +4642,26 @@ namespace Mono.CSharp { public class TryCatch : Statement { public Block Block; - public ArrayList Specific; + public List Specific; public Catch General; bool inside_try_finally, code_follows; - public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally) + public TryCatch (Block block, List catch_clauses, Location l, bool inside_try_finally) { this.Block = block; this.Specific = catch_clauses; - this.General = null; this.inside_try_finally = inside_try_finally; - for (int i = 0; i < catch_clauses.Count; ++i) { - Catch c = (Catch) catch_clauses [i]; - if (c.IsGeneral) { - if (i != catch_clauses.Count - 1) - Report.Error (1017, c.loc, "Try statement already has an empty catch block"); - this.General = c; - catch_clauses.RemoveAt (i); - i--; - } + Catch c = catch_clauses [0]; + if (c.IsGeneral) { + this.General = c; + catch_clauses.RemoveAt (0); } loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -4756,7 +4670,7 @@ namespace Mono.CSharp { if (!Block.Resolve (ec)) ok = false; - Type[] prev_catches = new Type [Specific.Count]; + TypeSpec[] prev_catches = new TypeSpec [Specific.Count]; int last_index = 0; foreach (Catch c in Specific){ ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch); @@ -4769,13 +4683,15 @@ namespace Mono.CSharp { vi.VariableInfo = null; } - if (!c.Resolve (ec)) + if (!c.Resolve (ec)) { ok = false; + continue; + } - Type resolved_type = c.CatchType; + TypeSpec resolved_type = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) { - Report.Error (160, c.loc, + ec.Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", TypeManager.CSharpName (prev_catches [ii])); ok = false; @@ -4788,8 +4704,8 @@ namespace Mono.CSharp { if (General != null) { if (CodeGen.Assembly.WrapNonExceptionThrows) { foreach (Catch c in Specific){ - if (c.CatchType == TypeManager.exception_type) { - Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); + if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) { + ec.Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); } } } @@ -4817,10 +4733,8 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - if (!inside_try_finally) - ig.BeginExceptionBlock (); + ec.BeginExceptionBlock (); Block.Emit (ec); @@ -4831,19 +4745,7 @@ namespace Mono.CSharp { General.Emit (ec); if (!inside_try_finally) - ig.EndExceptionBlock (); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - Block.MutateHoistedGenericType (storey); - - if (General != null) - General.MutateHoistedGenericType (storey); - if (Specific != null) { - foreach (Catch c in Specific) - c.MutateHoistedGenericType (storey); - } + ec.EndExceptionBlock (); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -4854,57 +4756,94 @@ namespace Mono.CSharp { if (General != null) target.General = (Catch) General.Clone (clonectx); if (Specific != null){ - target.Specific = new ArrayList (); + target.Specific = new List (); foreach (Catch c in Specific) - target.Specific.Add (c.Clone (clonectx)); + target.Specific.Add ((Catch) c.Clone (clonectx)); } } } // FIXME: Why is it almost exact copy of Using ?? - public class UsingTemporary : ExceptionStatement { - TemporaryVariable local_copy; - public Statement Statement; + public class UsingTemporary : ExceptionStatement + { + protected TemporaryVariable local_copy; + Statement statement; Expression expr; - Type expr_type; + protected Statement dispose_call; public UsingTemporary (Expression expr, Statement stmt, Location l) { this.expr = expr; - Statement = stmt; + statement = stmt; loc = l; } - public override bool Resolve (EmitContext ec) + #region Properties + public Expression Expression { + get { + return expr; + } + } + + public Statement Statement { + get { + return statement; + } + } + + #endregion + + protected virtual bool DoResolve (BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) return false; - expr_type = expr.Type; - - if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) { - if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { - Using.Error_IsNotConvertibleToIDisposable (expr); + if (!expr.Type.ImplementsInterface (TypeManager.idisposable_type) && + Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { + if (expr.Type != InternalType.Dynamic) { + Using.Error_IsNotConvertibleToIDisposable (ec, expr); return false; } + + expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc); } + var expr_type = expr.Type; + local_copy = new TemporaryVariable (expr_type, loc); local_copy.Resolve (ec); + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes); + } + + var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc); + dispose_mg.InstanceExpression = TypeManager.IsNullableType (expr_type) ? + new Cast (new TypeExpression (TypeManager.idisposable_type, loc), local_copy, loc).Resolve (ec) : + local_copy; + + dispose_call = new StatementExpression (new Invocation (dispose_mg, null)); + + // Add conditional call when disposing possible null variable + if (!expr_type.IsStruct || TypeManager.IsNullableType (expr_type)) + dispose_call = new If (new Binary (Binary.Operator.Inequality, local_copy, new NullLiteral (loc), loc), dispose_call, loc); + + return dispose_call.Resolve (ec); + } + + public override bool Resolve (BlockContext ec) + { + bool ok = DoResolve (ec); + ec.StartFlowBranching (this); - bool ok = Statement.Resolve (ec); + ok &= statement.Resolve (ec); ec.EndFlowBranching (); - ResolveReachability (ec); - - if (TypeManager.void_dispose_void == null) { - TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( - TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); - } + ok &= base.Resolve (ec); return ok; } @@ -4916,56 +4855,12 @@ namespace Mono.CSharp { protected override void EmitTryBody (EmitContext ec) { - Statement.Emit (ec); + statement.Emit (ec); } protected override void EmitFinallyBody (EmitContext ec) { - ILGenerator ig = ec.ig; - if (!TypeManager.IsStruct (expr_type)) { - Label skip = ig.DefineLabel (); - local_copy.Emit (ec); - ig.Emit (OpCodes.Brfalse, skip); - local_copy.Emit (ec); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - ig.MarkLabel (skip); - return; - } - - Expression ml = Expression.MemberLookup ( - ec.ContainerType, TypeManager.idisposable_type, expr_type, - "Dispose", Location.Null); - - if (!(ml is MethodGroupExpr)) { - local_copy.Emit (ec); - ig.Emit (OpCodes.Box, expr_type); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - return; - } - - MethodInfo mi = null; - - foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) { - if (TypeManager.GetParameterData (mk).Count == 0) { - mi = mk; - break; - } - } - - if (mi == null) { - Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); - return; - } - - local_copy.AddressOf (ec, AddressOp.Load); - ig.Emit (OpCodes.Call, mi); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - expr_type = storey.MutateType (expr_type); - local_copy.MutateHoistedGenericType (storey); - Statement.MutateHoistedGenericType (storey); + dispose_call.Emit (ec); } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -4973,7 +4868,7 @@ namespace Mono.CSharp { UsingTemporary target = (UsingTemporary) t; target.expr = expr.Clone (clonectx); - target.Statement = Statement.Clone (clonectx); + target.statement = statement.Clone (clonectx); } } @@ -4996,11 +4891,11 @@ namespace Mono.CSharp { loc = l; } - static public void Error_IsNotConvertibleToIDisposable (Expression expr) + static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, Expression expr) { - 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 ()); + ec.Report.SymbolRelatedToPreviousError (expr.Type); + ec.Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", + TypeManager.CSharpName (expr.Type)); } protected override void EmitPreTryBody (EmitContext ec) @@ -5015,29 +4910,21 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { - ILGenerator ig = ec.ig; - Label skip = ig.DefineLabel (); + Label skip = ec.DefineLabel (); bool emit_null_check = !TypeManager.IsValueType (var.Type); if (emit_null_check) { var.Emit (ec); - ig.Emit (OpCodes.Brfalse, skip); + ec.Emit (OpCodes.Brfalse, skip); } - Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, new ArrayList (0), loc); + Invocation.EmitCall (ec, var, TypeManager.void_dispose_void, null, loc); if (emit_null_check) - ig.MarkLabel (skip); + ec.MarkLabel (skip); } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - assign.MutateHoistedGenericType (storey); - var.MutateHoistedGenericType (storey); - stmt.MutateHoistedGenericType (storey); - } - - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (!ResolveVariable (ec)) return false; @@ -5048,31 +4935,37 @@ namespace Mono.CSharp { ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); if (TypeManager.void_dispose_void == null) { TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( - TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); + TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes); } return ok; } - bool ResolveVariable (EmitContext ec) + bool ResolveVariable (BlockContext ec) { assign = new SimpleAssign (var, init, loc); assign = assign.ResolveStatement (ec); if (assign == null) return false; - if (assign.Type == TypeManager.idisposable_type || - TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) { + if (assign.Type == TypeManager.idisposable_type || assign.Type.ImplementsInterface (TypeManager.idisposable_type)) { return true; } Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location); if (e == null) { - Error_IsNotConvertibleToIDisposable (var); + if (assign.Type == InternalType.Dynamic) { + e = Convert.ImplicitConversionRequired (ec, assign, TypeManager.idisposable_type, loc); + var = new TemporaryVariable (e.Type, loc); + assign = new SimpleAssign (var, e, loc).ResolveStatement (ec); + return true; + } + + Error_IsNotConvertibleToIDisposable (ec, var); return false; } @@ -5105,9 +4998,9 @@ namespace Mono.CSharp { { } - public void ResolveIncrement (EmitContext ec) + public void ResolveIncrement (BlockContext ec) { - increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this)); + increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc)); increment.Resolve (ec); } @@ -5150,13 +5043,13 @@ namespace Mono.CSharp { throw new NotImplementedException (); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { copy = new TemporaryVariable (for_each.expr.Type, loc); copy.Resolve (ec); int rank = length_exprs.Length; - ArrayList list = new ArrayList (rank); + Arguments list = new Arguments (rank); for (int i = 0; i < rank; i++) { counter [i] = new ArrayCounter (loc); counter [i].ResolveIncrement (ec); @@ -5167,15 +5060,15 @@ namespace Mono.CSharp { lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); lengths [i].Resolve (ec); - ArrayList args = new ArrayList (1); + Arguments args = new Arguments (1); args.Add (new Argument (new IntConstant (i, loc))); length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec); } - list.Add (counter [i]); + list.Add (new Argument (counter [i])); } - access = new ElementAccess (copy, list).Resolve (ec); + access = new ElementAccess (copy, list, loc).Resolve (ec); if (access == null) return false; @@ -5199,7 +5092,7 @@ namespace Mono.CSharp { ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); ec.CurrentBranching.CreateSibling (); - for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc); + for_each.variable = for_each.variable.ResolveLValue (ec, conv); if (for_each.variable == null) ok = false; @@ -5218,8 +5111,6 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - copy.EmitAssign (ec, for_each.expr); int rank = length_exprs.Length; @@ -5227,8 +5118,8 @@ namespace Mono.CSharp { Label[] loop = new Label [rank]; for (int i = 0; i < rank; i++) { - test [i] = ig.DefineLabel (); - loop [i] = ig.DefineLabel (); + test [i] = ec.DefineLabel (); + loop [i] = ec.DefineLabel (); if (lengths != null) lengths [i].EmitAssign (ec, length_exprs [i]); @@ -5238,20 +5129,20 @@ namespace Mono.CSharp { for (int i = 0; i < rank; i++) { counter [i].EmitAssign (ec, zero); - ig.Emit (OpCodes.Br, test [i]); - ig.MarkLabel (loop [i]); + ec.Emit (OpCodes.Br, test [i]); + ec.MarkLabel (loop [i]); } ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false); statement.Emit (ec); - ig.MarkLabel (ec.LoopBegin); + ec.MarkLabel (ec.LoopBegin); for (int i = rank - 1; i >= 0; i--){ counter [i].EmitIncrement (ec); - ig.MarkLabel (test [i]); + ec.MarkLabel (test [i]); counter [i].Emit (ec); if (lengths != null) @@ -5259,38 +5150,23 @@ namespace Mono.CSharp { else length_exprs [i].Emit (ec); - ig.Emit (OpCodes.Blt, loop [i]); + ec.Emit (OpCodes.Blt, loop [i]); } - ig.MarkLabel (ec.LoopEnd); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - for_each.expr.MutateHoistedGenericType (storey); - - copy.MutateHoistedGenericType (storey); - conv.MutateHoistedGenericType (storey); - statement.MutateHoistedGenericType (storey); - - for (int i = 0; i < counter.Length; i++) { - counter [i].MutateHoistedGenericType (storey); - if (lengths != null) - lengths [i].MutateHoistedGenericType (storey); - } + ec.MarkLabel (ec.LoopEnd); } } - sealed class CollectionForeach : Statement + sealed class CollectionForeach : Statement, MethodGroupExpr.IErrorHandler { - class CollectionForeachStatement : Statement + class Body : Statement { - Type type; + TypeSpec type; Expression variable, current, conv; Statement statement; Assign assign; - public CollectionForeachStatement (Type type, Expression variable, + public Body (TypeSpec type, Expression variable, Expression current, Statement statement, Location loc) { @@ -5306,7 +5182,7 @@ namespace Mono.CSharp { throw new NotImplementedException (); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { current = current.Resolve (ec); if (current == null) @@ -5331,28 +5207,61 @@ namespace Mono.CSharp { assign.EmitStatement (ec); statement.Emit (ec); } + } + + class Dispose : UsingTemporary + { + LocalTemporary dispose; + + public Dispose (TemporaryVariable variable, LocalTemporary dispose, Expression expr, Statement statement, Location loc) + : base (expr, statement, loc) + { + base.local_copy = variable; + this.dispose = dispose; + } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + protected override bool DoResolve (BlockContext ec) { - assign.MutateHoistedGenericType (storey); - statement.MutateHoistedGenericType (storey); + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes); + } + + Expression dispose_var = (Expression) dispose ?? local_copy; + + var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc); + dispose_mg.InstanceExpression = dispose_var; + + dispose_call = new StatementExpression (new Invocation (dispose_mg, null)); + + if (!dispose_var.Type.IsStruct) + dispose_call = new If (new Binary (Binary.Operator.Inequality, dispose_var, new NullLiteral (loc), loc), dispose_call, loc); + + return dispose_call.Resolve (ec); + } + + protected override void EmitFinallyBody (EmitContext ec) + { + Label call_dispose = ec.DefineLabel (); + if (dispose != null) { + local_copy.Emit (ec, false); + ec.Emit (OpCodes.Isinst, dispose.Type); + dispose.Store (ec); + } + + base.EmitFinallyBody (ec); + + if (dispose != null) { + ec.MarkLabel (call_dispose); + dispose.Release (ec); + } } } Expression variable, expr; Statement statement; - - TemporaryVariable enumerator; - Expression init; - Statement loop; - Statement wrapper; - - MethodGroupExpr get_enumerator; - PropertyExpr get_current; - MethodInfo move_next; Expression var_type; - Type enumerator_type; - bool enumerator_found; + ExpressionStatement init; public CollectionForeach (Expression var_type, Expression var, Expression expr, Statement stmt, Location l) @@ -5369,444 +5278,215 @@ namespace Mono.CSharp { throw new NotImplementedException (); } - bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi) + void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator) { - Type return_type = mi.ReturnType; + rc.Report.SymbolRelatedToPreviousError (enumerator); + rc.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", + enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ()); + } + MethodGroupExpr ResolveGetEnumerator (ResolveContext rc) + { // - // Ok, we can access it, now make sure that we can do something - // with this `GetEnumerator' + // Option 1: Try to match by name GetEnumerator first // - - if (return_type == TypeManager.ienumerator_type || - TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) { - // - // If it is not an interface, lets try to find the methods ourselves. - // For example, if we have: - // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}} - // We can avoid the iface call. This is a runtime perf boost. - // even bigger if we have a ValueType, because we avoid the cost - // of boxing. - // - // We have to make sure that both methods exist for us to take - // this path. If one of the methods does not exist, we will just - // use the interface. Sadly, this complex if statement is the only - // 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); + var mexpr = Expression.MemberLookup (rc.Compiler, rc.CurrentType, null, expr.Type, "GetEnumerator", -1, + MemberKind.All, BindingRestriction.DefaultMemberLookup | BindingRestriction.AccessibleOnly, loc); + + var mg = mexpr as MethodGroupExpr; + if (mg != null) { + mg.InstanceExpression = expr; + mg.CustomErrorHandler = this; + Arguments args = new Arguments (0); + mg = mg.OverloadResolve (rc, ref args, false, loc); + + if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) { + return mg; } + } - if (TypeManager.ienumerator_getcurrent == null) { - TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty ( - TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type); - } + // + // Option 2: Try to match using IEnumerable interfaces with preference of generic version + // + TypeSpec iface_candidate = null; + for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) { + var ifaces = t.Interfaces; + if (ifaces != null) { + foreach (var iface in ifaces) { + if (TypeManager.generic_ienumerable_type != null && iface.MemberDefinition == TypeManager.generic_ienumerable_type.MemberDefinition) { + if (iface_candidate != null && iface_candidate != TypeManager.ienumerable_type) { + rc.Report.SymbolRelatedToPreviousError (expr.Type); + rc.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", + expr.Type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ()); + + return null; + } + + iface_candidate = iface; + continue; + } -#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; + if (iface == TypeManager.ienumerable_type && iface_candidate == null) { + iface_candidate = iface; + } + } } -#endif + } - if (return_type.IsInterface || - !FetchMoveNext (return_type) || - !FetchGetCurrent (ec, return_type)) { - enumerator_type = return_type; - move_next = TypeManager.bool_movenext_void; - get_current = new PropertyExpr ( - ec.ContainerType, TypeManager.ienumerator_getcurrent, loc); - return true; - } - } else { - // - // Ok, so they dont return an IEnumerable, we will have to - // find if they support the GetEnumerator pattern. - // + if (iface_candidate == null) { + rc.Report.Error (1579, loc, + "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is not accessible", + expr.Type.GetSignatureForError (), "GetEnumerator"); - 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; - } + return null; } - enumerator_type = return_type; + var method = TypeManager.GetPredefinedMethod (iface_candidate, + MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc); - return true; + if (method == null) + return null; + + mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc); + mg.InstanceExpression = expr; + return mg; } - // - // Retrieves a `public bool MoveNext ()' method from the Type `t' - // - bool FetchMoveNext (Type t) + MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator) { - MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t, - MemberTypes.Method, - BindingFlags.Public | BindingFlags.Instance, - "MoveNext", null); + var ms = MemberCache.FindMember (enumerator.ReturnType, + MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.bool_type), + BindingRestriction.InstanceOnly) as MethodSpec; - foreach (MemberInfo m in move_next_list){ - MethodInfo mi = (MethodInfo) m; - - if ((TypeManager.GetParameterData (mi).Count == 0) && - TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) { - move_next = mi; - return true; - } + if (ms == null || !ms.IsPublic) { + Error_WrongEnumerator (rc, enumerator); + return null; } - return false; - } - - // - // Retrieves a `public T get_Current ()' method from the Type `t' - // - bool FetchGetCurrent (EmitContext ec, Type t) - { - PropertyExpr pe = Expression.MemberLookup ( - ec.ContainerType, t, "Current", MemberTypes.Property, - Expression.AllBindingFlags, loc) as PropertyExpr; - if (pe == null) - return false; - - get_current = pe; - return true; + return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc); } - void Error_Enumerator () + PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator) { - if (enumerator_found) { - return; + var ps = MemberCache.FindMember (enumerator.ReturnType, + MemberFilter.Property ("Current", null), + BindingRestriction.InstanceOnly) as PropertySpec; + + if (ps == null || !ps.IsPublic) { + Error_WrongEnumerator (rc, enumerator); + return null; } - Report.Error (1579, loc, - "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible", - TypeManager.CSharpName (expr.Type)); + return ps; } - bool IsOverride (MethodInfo m) + public override bool Resolve (BlockContext ec) { - m = (MethodInfo) TypeManager.DropGenericMethodArguments (m); + bool is_dynamic = expr.Type == InternalType.Dynamic; + if (is_dynamic) + expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc); - if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0)) + var get_enumerator_mg = ResolveGetEnumerator (ec); + if (get_enumerator_mg == null) { return false; - if (m is MethodBuilder) - return true; - - MethodInfo base_method = m.GetBaseDefinition (); - return base_method != m; - } - - bool TryType (EmitContext ec, Type t) - { - MethodGroupExpr mg = Expression.MemberLookup ( - ec.ContainerType, t, "GetEnumerator", MemberTypes.Method, - Expression.AllBindingFlags, loc) as MethodGroupExpr; - if (mg == null) - return false; - - 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 ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public) - continue; - - if (IsOverride (mi)) - continue; - - enumerator_found = true; - - if (!GetEnumeratorFilter (ec, mi)) - continue; - - if (result != null) { - if (TypeManager.IsGenericType (result.ReturnType)) { - if (!TypeManager.IsGenericType (mi.ReturnType)) - continue; - - MethodBase mb = TypeManager.DropGenericMethodArguments (mi); - 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 (mb)); - return false; - } - - // Always prefer generics enumerators - if (!TypeManager.IsGenericType (mi.ReturnType)) { - if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) || - TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType)) - 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)); - return false; - } - } - 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, enumerator_type, loc); - - if (t != expr.Type) { - expr = Convert.ExplicitConversion ( - ec, expr, t, loc); - if (expr == null) - throw new InternalErrorException (); - } - - get_enumerator.InstanceExpression = expr; - get_enumerator.IsBase = t != expr.Type; + var get_enumerator = get_enumerator_mg.BestCandidate; + var enumerator = new TemporaryVariable (get_enumerator.ReturnType, loc); + enumerator.Resolve (ec); - return true; + // Prepare bool MoveNext () + var move_next_mg = ResolveMoveNext (ec, get_enumerator); + if (move_next_mg == null) { + return false; } - return false; - } + move_next_mg.InstanceExpression = enumerator; - 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) + // Prepare ~T~ Current { get; } + var current_prop = ResolveCurrent (ec, get_enumerator); + if (current_prop == null) { return false; - - // - // Now try to find the method in the interfaces - // - Type [] ifaces = TypeManager.GetInterfaces (t); - foreach (Type i in ifaces){ - if (TryType (ec, i)) - return true; } - return false; - } - - public override bool Resolve (EmitContext ec) - { - enumerator_type = TypeManager.ienumerator_type; - - if (!ProbeCollectionType (ec, expr.Type)) { - Error_Enumerator (); + var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator }.Resolve (ec); + if (current_pe == null) 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 = new TypeExpression (current_pe.Type, 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, null); - init = init.Resolve (ec); - if (init == null) - return false; - - Expression move_next_expr; - { - MemberInfo[] mi = new MemberInfo[] { move_next }; - MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc); - mg.InstanceExpression = enumerator; - - move_next_expr = new Invocation (mg, null); - } - - get_current.InstanceExpression = enumerator; - Statement block = new CollectionForeachStatement ( - var_type.Type, variable, get_current, statement, loc); + var init = new Invocation (get_enumerator_mg, null); + init.Resolve (ec); - loop = new While (move_next_expr, block, loc); + statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)), + new Body (var_type.Type, variable, current_pe, statement, loc), loc); + var enum_type = enumerator.Type; - bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type); - if (implements_idisposable || !enumerator_type.IsSealed) { - wrapper = new DisposableWrapper (this, implements_idisposable); + // + // Add Dispose method call when enumerator can be IDisposable + // + if (!enumerator.Type.ImplementsInterface (TypeManager.idisposable_type)) { + if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) { + // + // Runtime Dispose check + // + var tv = new LocalTemporary (TypeManager.idisposable_type); + statement = new Dispose (enumerator, tv, init, statement, loc); + } else { + // + // No Dispose call needed + // + this.init = new SimpleAssign (enumerator, init); + this.init.Resolve (ec); + } } else { - wrapper = new NonDisposableWrapper (this); + // + // Static Dispose check + // + statement = new Dispose (enumerator, null, init, statement, loc); } - return wrapper.Resolve (ec); + return statement.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - wrapper.Emit (ec); - } - - class NonDisposableWrapper : Statement { - CollectionForeach parent; - - internal NonDisposableWrapper (CollectionForeach parent) - { - this.parent = parent; - } - - protected override void CloneTo (CloneContext clonectx, Statement target) - { - throw new NotSupportedException (); - } + if (init != null) + init.EmitStatement (ec); - public override bool Resolve (EmitContext ec) - { - return parent.ResolveLoop (ec); - } - - protected override void DoEmit (EmitContext ec) - { - parent.EmitLoopInit (ec); - parent.EmitLoopBody (ec); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - throw new NotSupportedException (); - } + statement.Emit (ec); } - sealed class DisposableWrapper : ExceptionStatement - { - CollectionForeach parent; - bool implements_idisposable; - - internal DisposableWrapper (CollectionForeach parent, bool implements) - { - this.parent = parent; - this.implements_idisposable = implements; - } + #region IErrorHandler Members - protected override void CloneTo (CloneContext clonectx, Statement target) - { - throw new NotSupportedException (); - } - - public override bool Resolve (EmitContext ec) - { - bool ok = true; - - ec.StartFlowBranching (this); - - if (!parent.ResolveLoop (ec)) - ok = false; - - ec.EndFlowBranching (); - - ResolveReachability (ec); - - if (TypeManager.void_dispose_void == null) { - TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( - TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); - } - return ok; - } - - protected override void EmitPreTryBody (EmitContext ec) - { - parent.EmitLoopInit (ec); - } - - protected override void EmitTryBody (EmitContext ec) - { - parent.EmitLoopBody (ec); - } - - protected override void EmitFinallyBody (EmitContext ec) - { - Expression instance = parent.enumerator; - if (!TypeManager.IsValueType (parent.enumerator_type)) { - ILGenerator ig = ec.ig; - - parent.enumerator.Emit (ec); - - Label call_dispose = ig.DefineLabel (); - - if (!implements_idisposable) { - ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); - LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type); - temp.Store (ec); - temp.Emit (ec); - instance = temp; - } - - ig.Emit (OpCodes.Brtrue_S, call_dispose); - - // using 'endfinally' to empty the evaluation stack - ig.Emit (OpCodes.Endfinally); - ig.MarkLabel (call_dispose); - } - - Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, new ArrayList (0), loc); - } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - throw new NotSupportedException (); - } - } - - bool ResolveLoop (EmitContext ec) + bool MethodGroupExpr.IErrorHandler.AmbiguousCall (ResolveContext ec, MethodGroupExpr mg, MethodSpec ambiguous) { - return loop.Resolve (ec); - } + ec.Report.SymbolRelatedToPreviousError (mg.BestCandidate); + ec.Report.Warning (278, 2, loc, + "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'", + mg.DeclaringType.GetSignatureForError (), "enumerable", + mg.BestCandidate.GetSignatureForError (), ambiguous.GetSignatureForError ()); - void EmitLoopInit (EmitContext ec) - { - enumerator.EmitAssign (ec, init); + return true; } - void EmitLoopBody (EmitContext ec) + bool MethodGroupExpr.IErrorHandler.NoExactMatch (ResolveContext ec, MethodSpec method) { - loop.Emit (ec); + return false; } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - enumerator_type = storey.MutateType (enumerator_type); - init.MutateHoistedGenericType (storey); - loop.MutateHoistedGenericType (storey); - } + #endregion } Expression type; @@ -5828,24 +5508,24 @@ namespace Mono.CSharp { get { return statement; } } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) return false; if (expr.IsNull) { - Report.Error (186, loc, "Use of null is not valid in this context"); + ec.Report.Error (186, loc, "Use of null is not valid in this context"); return false; } if (expr.Type == TypeManager.string_type) { statement = new ArrayForeach (this, 1); - } else if (expr.Type.IsArray) { - statement = new ArrayForeach (this, expr.Type.GetArrayRank ()); + } else if (expr.Type is ArrayContainer) { + statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank); } else { if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { - Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", + ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", expr.ExprClassName); return false; } @@ -5858,11 +5538,9 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ILGenerator ig = ec.ig; - Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd; - ec.LoopBegin = ig.DefineLabel (); - ec.LoopEnd = ig.DefineLabel (); + ec.LoopBegin = ec.DefineLabel (); + ec.LoopEnd = ec.DefineLabel (); statement.Emit (ec); @@ -5879,10 +5557,5 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); target.statement = statement.Clone (clonectx); } - - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - statement.MutateHoistedGenericType (storey); - } } }