X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=e3159d390829546bd4d4340b79469adb24841a25;hb=cc21ca3500fc936982e24d92f616165106c9e628;hp=58ffd5c1cfe0ad1956d15227faf6b9103e4c4528;hpb=a5b083f12836cca74f07d32e9494ed039ce266a5;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 58ffd5c1cfe..e3159d39082 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -6,8 +6,8 @@ // Martin Baulig (martin@ximian.com) // Marek Safar (marek.safar@seznam.cz) // -// (C) 2001, 2002, 2003 Ximian, Inc. -// (C) 2003, 2004 Novell, Inc. +// Copyright 2001, 2002, 2003 Ximian, Inc. +// Copyright 2003, 2004 Novell, Inc. // using System; @@ -103,6 +103,12 @@ namespace Mono.CSharp { return s; } + public virtual Expression CreateExpressionTree (EmitContext ec) + { + Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); + return null; + } + public Statement PerformClone () { CloneContext clonectx = new CloneContext (); @@ -110,6 +116,7 @@ namespace Mono.CSharp { return Clone (clonectx); } + public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey); } // @@ -195,6 +202,15 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + // nothing needed. + } } public class If : Statement { @@ -204,24 +220,32 @@ namespace Mono.CSharp { bool is_true_ret; - public If (Expression expr, Statement trueStatement, Location l) + public If (Expression expr, Statement true_statement, Location l) { this.expr = expr; - TrueStatement = trueStatement; + TrueStatement = true_statement; loc = l; } public If (Expression expr, - Statement trueStatement, - Statement falseStatement, + Statement true_statement, + Statement false_statement, Location l) { this.expr = expr; - TrueStatement = trueStatement; - FalseStatement = falseStatement; + TrueStatement = true_statement; + FalseStatement = false_statement; loc = l; } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr.MutateHoistedGenericType (storey); + TrueStatement.MutateHoistedGenericType (storey); + if (FalseStatement != null) + FalseStatement.MutateHoistedGenericType (storey); + } + public override bool Resolve (EmitContext ec) { bool ok = true; @@ -242,8 +266,8 @@ namespace Mono.CSharp { // // Dead code elimination // - if (expr is BoolConstant){ - bool take = ((BoolConstant) expr).Value; + if (expr is Constant){ + bool take = !((Constant) expr).IsDefaultValue; if (take){ if (!TrueStatement.Resolve (ec)) @@ -291,19 +315,20 @@ namespace Mono.CSharp { Label end; // - // If we're a boolean expression, Resolve() already + // If we're a boolean constant, Resolve() already // eliminated dead code for us. // - if (expr is BoolConstant){ - bool take = ((BoolConstant) expr).Value; + Constant c = expr as Constant; + if (c != null){ + c.EmitSideEffect (ec); - if (take) + if (!c.IsDefaultValue) TrueStatement.Emit (ec); else if (FalseStatement != null) FalseStatement.Emit (ec); return; - } + } expr.EmitBranchable (ec, false_target, false); @@ -342,11 +367,10 @@ namespace Mono.CSharp { public class Do : Statement { public Expression expr; public Statement EmbeddedStatement; - bool infinite; - public Do (Statement statement, Expression boolExpr, Location l) + public Do (Statement statement, Expression bool_expr, Location l) { - expr = boolExpr; + expr = bool_expr; EmbeddedStatement = statement; loc = l; } @@ -370,14 +394,11 @@ namespace Mono.CSharp { expr = Expression.ResolveBoolean (ec, expr, loc); if (expr == null) ok = false; - else if (expr is BoolConstant){ - bool res = ((BoolConstant) expr).Value; - - if (res) - infinite = true; + else if (expr is Constant){ + bool infinite = !((Constant) expr).IsDefaultValue; + if (infinite) + ec.CurrentBranching.CurrentUsageVector.Goto (); } - if (infinite) - ec.CurrentBranching.CurrentUsageVector.Goto (); ec.EndFlowBranching (); @@ -401,9 +422,10 @@ namespace Mono.CSharp { // // Dead code elimination // - if (expr is BoolConstant){ - bool res = ((BoolConstant) expr).Value; + if (expr is Constant){ + bool res = !((Constant) expr).IsDefaultValue; + expr.EmitSideEffect (ec); if (res) ec.ig.Emit (OpCodes.Br, loop); } else @@ -415,6 +437,12 @@ namespace Mono.CSharp { 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; @@ -429,9 +457,9 @@ namespace Mono.CSharp { public Statement Statement; bool infinite, empty; - public While (Expression boolExpr, Statement statement, Location l) + public While (Expression bool_expr, Statement statement, Location l) { - this.expr = boolExpr; + this.expr = bool_expr; Statement = statement; loc = l; } @@ -447,10 +475,10 @@ namespace Mono.CSharp { // // Inform whether we are infinite or not // - if (expr is BoolConstant){ - BoolConstant bc = (BoolConstant) expr; + if (expr is Constant){ + bool value = !((Constant) expr).IsDefaultValue; - if (bc.Value == false){ + if (value == false){ if (!Statement.ResolveUnreachable (ec, true)) return false; empty = true; @@ -478,8 +506,10 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - if (empty) + if (empty) { + expr.EmitSideEffect (ec); return; + } ILGenerator ig = ec.ig; Label old_begin = ec.LoopBegin; @@ -491,8 +521,10 @@ namespace Mono.CSharp { // // Inform whether we are infinite or not // - if (expr is BoolConstant){ + if (expr is Constant){ + // expr is 'true', since the 'empty' case above handles the 'false' case ig.MarkLabel (ec.LoopBegin); + expr.EmitSideEffect (ec); Statement.Emit (ec); ig.Emit (OpCodes.Br, ec.LoopBegin); @@ -510,6 +542,7 @@ namespace Mono.CSharp { Statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); + ec.Mark (loc, true); expr.EmitBranchable (ec, while_loop, true); @@ -520,6 +553,11 @@ namespace Mono.CSharp { ec.LoopEnd = old_end; } + public override void Emit (EmitContext ec) + { + DoEmit (ec); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { While target = (While) t; @@ -527,6 +565,12 @@ 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 { @@ -536,13 +580,13 @@ namespace Mono.CSharp { public Statement Statement; bool infinite, empty; - public For (Statement initStatement, + public For (Statement init_statement, Expression test, Statement increment, Statement statement, Location l) { - InitStatement = initStatement; + InitStatement = init_statement; Test = test; Increment = increment; Statement = statement; @@ -562,10 +606,10 @@ namespace Mono.CSharp { Test = Expression.ResolveBoolean (ec, Test, loc); if (Test == null) ok = false; - else if (Test is BoolConstant){ - BoolConstant bc = (BoolConstant) Test; + else if (Test is Constant){ + bool value = !((Constant) Test).IsDefaultValue; - if (bc.Value == false){ + if (value == false){ if (!Statement.ResolveUnreachable (ec, true)) return false; if ((Increment != null) && @@ -607,20 +651,22 @@ namespace Mono.CSharp { return ok; } - + protected override void DoEmit (EmitContext ec) { - if (empty) + if (InitStatement != null && InitStatement != EmptyStatement.Value) + InitStatement.Emit (ec); + + if (empty) { + Test.EmitSideEffect (ec); return; + } ILGenerator ig = ec.ig; Label old_begin = ec.LoopBegin; Label old_end = ec.LoopEnd; Label loop = ig.DefineLabel (); Label test = ig.DefineLabel (); - - if (InitStatement != null && InitStatement != EmptyStatement.Value) - InitStatement.Emit (ec); ec.LoopBegin = ig.DefineLabel (); ec.LoopEnd = ig.DefineLabel (); @@ -641,13 +687,15 @@ namespace Mono.CSharp { if (Test != null){ // // The Resolve code already catches the case for - // Test == BoolConstant (false) so we know that + // Test == Constant (false) so we know that // this is true // - if (Test is BoolConstant) + if (Test is Constant) { + Test.EmitSideEffect (ec); ig.Emit (OpCodes.Br, loop); - else + } else { Test.EmitBranchable (ec, loop, true); + } } else ig.Emit (OpCodes.Br, loop); @@ -657,6 +705,18 @@ namespace Mono.CSharp { 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; @@ -692,6 +752,11 @@ namespace Mono.CSharp { expr.EmitStatement (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr.MutateHoistedGenericType (storey); + } + public override string ToString () { return "StatementExpression (" + expr + ")"; @@ -705,20 +770,42 @@ namespace Mono.CSharp { } } + // A 'return' or a 'yield break' + public abstract class ExitStatement : Statement + { + protected bool unwind_protect; + protected abstract bool DoResolve (EmitContext ec); + + public virtual void Error_FinallyClause () + { + Report.Error (157, loc, "Control cannot leave the body of a finally clause"); + } + + public sealed override bool Resolve (EmitContext ec) + { + if (!DoResolve (ec)) + return false; + + unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this); + if (unwind_protect) + ec.NeedReturnLabel (); + ec.CurrentBranching.CurrentUsageVector.Goto (); + return true; + } + } + /// /// Implements the return statement /// - public class Return : Statement { - Expression Expr; - bool unwind_protect; - + public class Return : ExitStatement { + protected Expression Expr; public Return (Expression expr, Location l) { Expr = expr; loc = l; } - bool DoResolve (EmitContext ec) + protected override bool DoResolve (EmitContext ec) { if (Expr == null) { if (ec.ReturnType == TypeManager.void_type) @@ -730,7 +817,7 @@ namespace Mono.CSharp { return false; } - AnonymousContainer am = ec.CurrentAnonymousMethod; + AnonymousExpression am = ec.CurrentAnonymousMethod; if ((am != null) && am.IsIterator && ec.InIterator) { Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + "statement to return a value, or yield break to end the iteration"); @@ -748,6 +835,12 @@ namespace Mono.CSharp { if (Expr.Type != ec.ReturnType) { if (ec.InferReturnType) { + // + // void cannot be used in contextual return + // + if (Expr.Type == TypeManager.void_type) + return false; + ec.ReturnType = Expr.Type; } else { Expr = Convert.ImplicitConversionRequired ( @@ -756,7 +849,7 @@ namespace Mono.CSharp { if (Expr == null) { if (am != null) { Report.Error (1662, loc, - "Cannot convert `{0}' to delegate type `D' because some of the return types in the block are not implicitly convertible to the delegate return type", + "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; @@ -766,18 +859,6 @@ namespace Mono.CSharp { return true; } - - public override bool Resolve (EmitContext ec) - { - if (!DoResolve (ec)) - return false; - - unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc); - if (unwind_protect) - ec.NeedReturnLabel (); - ec.CurrentBranching.CurrentUsageVector.Goto (); - return true; - } protected override void DoEmit (EmitContext ec) { @@ -794,11 +875,18 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Ret); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + if (Expr != null) + Expr.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Return target = (Return) t; - - target.Expr = Expr.Clone (clonectx); + // It's null for simple return; + if (Expr != null) + target.Expr = Expr.Clone (clonectx); } } @@ -838,6 +926,10 @@ namespace Mono.CSharp { Label l = label.LabelTarget (ec); ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } } public class LabeledStatement : Statement { @@ -904,6 +996,10 @@ namespace Mono.CSharp { ec.ig.MarkLabel (label); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } + public void AddReference () { referenced = true; @@ -940,6 +1036,10 @@ namespace Mono.CSharp { } ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } } /// @@ -1008,12 +1108,16 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec)); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { GotoCase target = (GotoCase) t; target.expr = expr.Clone (clonectx); - target.sl = sl.Clone (clonectx); } } @@ -1030,39 +1134,27 @@ namespace Mono.CSharp { { ec.CurrentBranching.CurrentUsageVector.Goto (); - if (expr != null){ - expr = expr.Resolve (ec); - if (expr == null) - return false; - - ExprClass eclass = expr.eclass; + if (expr == null) + return ec.CurrentBranching.CheckRethrow (loc); - if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || - eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { - expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc); - return false; - } + expr = expr.Resolve (ec); + if (expr == null) + return false; - Type t = expr.Type; - - if ((t != TypeManager.exception_type) && - !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && - !(expr is NullLiteral)) { - Error (155, - "The type caught or thrown must be derived " + - "from System.Exception"); - return false; - } - return true; - } + ExprClass eclass = expr.eclass; - if (!ec.InCatch) { - Error (156, "A throw statement with no arguments is not allowed outside of a catch clause"); + if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || + eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { + expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc); return false; } - if (ec.InFinally) { - Error (724, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause"); + Type t = expr.Type; + + if ((t != TypeManager.exception_type) && + !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && + !(expr is NullLiteral)) { + Error (155, "The type caught or thrown must be derived from System.Exception"); return false; } return true; @@ -1079,11 +1171,18 @@ namespace Mono.CSharp { } } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + if (expr != null) + expr.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Throw target = (Throw) t; - target.expr = expr.Clone (clonectx); + if (expr != null) + target.expr = expr.Clone (clonectx); } } @@ -1108,6 +1207,15 @@ namespace Mono.CSharp { { ec.ig.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 + } } public class Continue : Statement { @@ -1131,29 +1239,22 @@ namespace Mono.CSharp { { ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); } - } - - public abstract class Variable - { - public abstract Type Type { - get; - } - public abstract bool HasInstance { - get; + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { } - public abstract bool NeedsTemporary { - get; + protected override void CloneTo (CloneContext clonectx, Statement t) + { + // nothing needed. } + } - public abstract void EmitInstance (EmitContext ec); - - public abstract void Emit (EmitContext ec); - - public abstract void EmitAssign (EmitContext ec); - - public abstract void EmitAddressOf (EmitContext ec); + public interface ILocalVariable + { + void Emit (EmitContext ec); + void EmitAssign (EmitContext ec); + void EmitAddressOf (EmitContext ec); } public interface IKnownVariable { @@ -1164,8 +1265,8 @@ namespace Mono.CSharp { // // The information about a user-perceived local variable // - public class LocalInfo : IKnownVariable { - public Expression Type; + public class LocalInfo : IKnownVariable, ILocalVariable { + public readonly Expression Type; public Type VariableType; public readonly string Name; @@ -1173,11 +1274,7 @@ namespace Mono.CSharp { public readonly Block Block; public VariableInfo VariableInfo; - - Variable var; - public Variable Variable { - get { return var; } - } + public HoistedVariable HoistedVariableReference; [Flags] enum Flags : byte { @@ -1185,7 +1282,6 @@ namespace Mono.CSharp { ReadOnly = 2, Pinned = 4, IsThis = 8, - Captured = 16, AddressTaken = 32, CompilerGenerated = 64, IsConstant = 128 @@ -1218,11 +1314,10 @@ namespace Mono.CSharp { public void ResolveVariable (EmitContext ec) { - Block theblock = Block; - if (theblock.ScopeInfo != null) - var = theblock.ScopeInfo.GetCapturedVariable (this); + if (HoistedVariableReference != null) + return; - if (var == null) { + if (builder == null) { if (Pinned) // // This is needed to compile on both .NET 1.x and .NET 2.x @@ -1231,15 +1326,28 @@ namespace Mono.CSharp { builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType); else builder = ec.ig.DeclareLocal (VariableType); - - var = new LocalVariable (this, builder); } } + public void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloc, builder); + } + + public void EmitAssign (EmitContext ec) + { + ec.ig.Emit (OpCodes.Stloc, builder); + } + + public void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldloca, builder); + } + public void EmitSymbolInfo (EmitContext ec, string name) { if (builder != null) - ec.DefineLocalVariable (name, builder); + ec.DefineLocalVariable (Name, builder); } public bool IsThisAssigned (EmitContext ec) @@ -1263,13 +1371,14 @@ namespace Mono.CSharp { public bool Resolve (EmitContext ec) { - if (VariableType == null) { - TypeExpr texpr = Type.ResolveAsContextualType (ec, false); - if (texpr == null) - return false; + if (VariableType != null) + return true; + + TypeExpr texpr = Type.ResolveAsContextualType (ec, false); + if (texpr == null) + return false; - VariableType = texpr.Type; - } + VariableType = texpr.Type; if (TypeManager.IsGenericParameter (VariableType)) return true; @@ -1290,11 +1399,6 @@ namespace Mono.CSharp { return true; } - public bool IsCaptured { - get { return (flags & Flags.Captured) != 0; } - set { flags |= Flags.Captured; } - } - public bool IsConstant { get { return (flags & Flags.IsConstant) != 0; } set { flags |= Flags.IsConstant; } @@ -1369,54 +1473,20 @@ namespace Mono.CSharp { get { return Location; } } - protected class LocalVariable : Variable - { - public readonly LocalInfo LocalInfo; - LocalBuilder builder; - - public LocalVariable (LocalInfo local, LocalBuilder builder) - { - this.LocalInfo = local; - this.builder = builder; - } - - public override Type Type { - get { return LocalInfo.VariableType; } - } - - public override bool HasInstance { - get { return false; } - } - - public override bool NeedsTemporary { - get { return false; } - } - - public override void EmitInstance (EmitContext ec) - { - // Do nothing. - } - - public override void Emit (EmitContext ec) - { - ec.ig.Emit (OpCodes.Ldloc, builder); - } - - public override void EmitAssign (EmitContext ec) - { - ec.ig.Emit (OpCodes.Stloc, builder); - } - - public override void EmitAddressOf (EmitContext ec) - { - ec.ig.Emit (OpCodes.Ldloca, builder); - } - } - public LocalInfo Clone (CloneContext clonectx) { - // Only this kind is created by the parser. - return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + // + // Variables in anonymous block are not resolved yet + // + if (VariableType == null) + return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + + // + // Variables in method block are resolved + // + LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location); + li.VariableType = VariableType; + return li; } } @@ -1440,7 +1510,7 @@ namespace Mono.CSharp { public Location EndLocation = Location.Null; public ExplicitBlock Explicit; - public ToplevelBlock Toplevel; + public ToplevelBlock Toplevel; // TODO: Use Explicit [Flags] public enum Flags : byte { @@ -1449,9 +1519,7 @@ namespace Mono.CSharp { VariablesInitialized = 4, HasRet = 8, IsDestructor = 16, - Unsafe = 32, - HasVarargs = 64, // Used in ToplevelBlock - IsIterator = 128 + Unsafe = 32 } protected Flags flags; @@ -1469,8 +1537,6 @@ namespace Mono.CSharp { // The statements in this block // protected ArrayList statements; - protected int current_statement; - int num_statements; // // An array of Blocks. We keep track of children just @@ -1484,7 +1550,7 @@ namespace Mono.CSharp { // // Labels. (label, block) pairs. // - Hashtable labels; + protected HybridDictionary labels; // // Keeps track of (name, type) pairs @@ -1493,7 +1559,7 @@ namespace Mono.CSharp { // // Keeps track of constants - Hashtable constants; + HybridDictionary constants; // // Temporary variables. @@ -1505,7 +1571,7 @@ namespace Mono.CSharp { // Block switch_block; - ExpressionStatement scope_init; + ArrayList scope_initializers; ArrayList anonymous_children; @@ -1514,7 +1580,6 @@ namespace Mono.CSharp { int this_id; int assignable_slots; - protected ScopeInfo scope_info; bool unreachable_shown; bool unreachable; @@ -1546,7 +1611,7 @@ namespace Mono.CSharp { this.EndLocation = end; this.loc = start; this_id = id++; - statements = new ArrayList (); + statements = new ArrayList (4); } public Block CreateSwitchBlock (Location start) @@ -1572,7 +1637,7 @@ namespace Mono.CSharp { void AddChild (Block b) { if (children == null) - children = new ArrayList (); + children = new ArrayList (1); children.Add (b); } @@ -1643,7 +1708,7 @@ namespace Mono.CSharp { Toplevel.CheckError158 (name, target.loc); if (labels == null) - labels = new Hashtable (); + labels = new HybridDictionary(); labels.Add (name, target); return true; @@ -1742,8 +1807,7 @@ namespace Mono.CSharp { if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); if (Explicit == vi.Block.Explicit) - Report.Error (128, l, - "A local variable named `{0}' is already defined in this scope", name); + Error_AlreadyDeclared (l, name, null); else Error_AlreadyDeclared (l, name, "parent"); return null; @@ -1754,7 +1818,18 @@ namespace Mono.CSharp { Report.SymbolRelatedToPreviousError (pi.Location, name); Error_AlreadyDeclared (loc, name, pi.Block == Toplevel ? "method argument" : "parent or current"); + return null; } + + if (Toplevel.GenericMethod != null) { + foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) { + if (tp.Name == name) { + Report.SymbolRelatedToPreviousError (tp); + Error_AlreadyDeclaredTypeParameter (loc, name); + return null; + } + } + } IKnownVariable kvi = Explicit.GetKnownVariable (name); if (kvi != null) { @@ -1764,30 +1839,51 @@ namespace Mono.CSharp { } vi = new LocalInfo (type, name, this, l); - Variables.Add (name, vi); - Explicit.AddKnownVariable (name, vi); + AddVariable (vi); if ((flags & Flags.VariablesInitialized) != 0) throw new InternalErrorException ("block has already been resolved"); return vi; } + + protected virtual void AddVariable (LocalInfo li) + { + Variables.Add (li.Name, li); + Explicit.AddKnownVariable (li.Name, li); + } - protected static void Error_AlreadyDeclared (Location loc, string var, string reason) + protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason) { + if (reason == null) { + Error_AlreadyDeclared (loc, var); + return; + } + Report.Error (136, loc, "A local variable named `{0}' cannot be declared " + "in this scope because it would give a different meaning " + "to `{0}', which is already used in a `{1}' scope " + "to denote something else", var, reason); } + protected virtual void Error_AlreadyDeclared (Location loc, string name) + { + Report.Error (128, loc, + "A local variable named `{0}' is already defined in this scope", name); + } + + protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name) + { + GenericMethod.Error_ParameterNameCollision (loc, name, "local variable"); + } + public bool AddConstant (Expression type, string name, Expression value, Location l) { if (AddVariable (type, name, l) == null) return false; if (constants == null) - constants = new Hashtable (); + constants = new HybridDictionary(); constants.Add (name, value); @@ -1843,16 +1939,22 @@ namespace Mono.CSharp { } return null; } - - public void AddStatement (Statement s) + + // + // It should be used by expressions which require to + // register a statement during resolve process. + // + public void AddScopeStatement (StatementExpression s) { - statements.Add (s); - flags |= Flags.BlockUsed; + if (scope_initializers == null) + scope_initializers = new ArrayList (); + + scope_initializers.Add (s); } - public void InsertStatementAfterCurrent (Statement statement) + public void AddStatement (Statement s) { - statements.Insert (current_statement + 1, statement); + statements.Add (s); flags |= Flags.BlockUsed; } @@ -1886,18 +1988,6 @@ namespace Mono.CSharp { } } - public ScopeInfo ScopeInfo { - get { return scope_info; } - } - - public ScopeInfo CreateScopeInfo () - { - if (scope_info == null) - scope_info = ScopeInfo.CreateScope (this); - - return scope_info; - } - public ArrayList AnonymousChildren { get { return anonymous_children; } } @@ -1923,8 +2013,12 @@ namespace Mono.CSharp { LocalInfo vi = (LocalInfo) de.Value; Type variable_type = vi.VariableType; - if (variable_type == null) + if (variable_type == null) { + if (vi.Type is VarExpr) + Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); + continue; + } Expression cv = (Expression) constants [name]; if (cv == null) @@ -2001,48 +2095,38 @@ namespace Mono.CSharp { // public virtual void EmitMeta (EmitContext ec) { - Report.Debug (64, "BLOCK EMIT META", this, Parent, Toplevel, ScopeInfo, ec); - if (ScopeInfo != null) { - scope_init = ScopeInfo.GetScopeInitializer (ec); - Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo, - ec, scope_init); - } - if (variables != null){ foreach (LocalInfo vi in variables.Values) vi.ResolveVariable (ec); } if (temporary_variables != null) { - foreach (LocalInfo vi in temporary_variables) - vi.ResolveVariable (ec); + for (int i = 0; i < temporary_variables.Count; i++) + ((LocalInfo)temporary_variables[i]).ResolveVariable(ec); } - if (children != null){ - foreach (Block b in children) - b.EmitMeta (ec); + if (children != null) { + for (int i = 0; i < children.Count; i++) + ((Block)children[i]).EmitMeta(ec); } } - void UsageWarning (FlowBranching.UsageVector vector) + void UsageWarning () { - string name; - - if ((variables != null) && (Report.WarningLevel >= 3)) { - foreach (DictionaryEntry de in variables){ - LocalInfo vi = (LocalInfo) de.Value; + if (variables == null || Report.WarningLevel < 3) + return; - if (vi.Used) - continue; + foreach (DictionaryEntry de in variables) { + LocalInfo vi = (LocalInfo) de.Value; - name = (string) de.Key; + if (!vi.Used) { + string name = (string) de.Key; // vi.VariableInfo can be null for 'catch' variables - if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){ + 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); - } else { + else Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name); - } } } } @@ -2066,10 +2150,12 @@ namespace Mono.CSharp { body = ((Foreach) s).Statement; else if (s is While) body = ((While) s).Statement; - else if (s is Using) - body = ((Using) s).Statement; else if (s is Fixed) body = ((Fixed) s).Statement; + else if (s is Using) + body = ((Using) s).EmbeddedStatement; + else if (s is UsingTemporary) + body = ((UsingTemporary) s).Statement; else return; @@ -2095,12 +2181,13 @@ namespace Mono.CSharp { // from the beginning of the function. The outer Resolve() that detected the unreachability is // responsible for handling the situation. // - for (current_statement = 0; current_statement < statements.Count; current_statement++) { - Statement s = (Statement) statements [current_statement]; + int statement_count = statements.Count; + for (int ix = 0; ix < statement_count; ix++){ + Statement s = (Statement) statements [ix]; // Check possible empty statement (CS0642) if (Report.WarningLevel >= 3 && - current_statement + 1 < statements.Count && - statements [current_statement + 1] is Block) + ix + 1 < statement_count && + statements [ix + 1] is Block) CheckPossibleMistakenEmptyStatement (s); // @@ -2128,18 +2215,16 @@ namespace Mono.CSharp { // if (!s.Resolve (ec)) { + ok = false; if (ec.IsInProbingMode) - return false; + break; - ok = false; - statements [current_statement] = EmptyStatement.Value; + statements [ix] = EmptyStatement.Value; continue; } if (unreachable && !(s is LabeledStatement) && !(s is Block)) - statements [current_statement] = EmptyStatement.Value; - - num_statements = current_statement + 1; + statements [ix] = EmptyStatement.Value; unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable; if (unreachable && s is LabeledStatement) @@ -2147,38 +2232,31 @@ namespace Mono.CSharp { } Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, - ec.CurrentBranching, statements.Count, num_statements); - - if (!ok) - return false; + ec.CurrentBranching, statement_count); while (ec.CurrentBranching is FlowBranchingLabeled) ec.EndFlowBranching (); - FlowBranching.UsageVector vector = ec.DoEndFlowBranching (); + bool flow_unreachable = ec.EndFlowBranching (); ec.CurrentBlock = prev_block; - // If we're a non-static `struct' constructor which doesn't have an + if (flow_unreachable) + flags |= Flags.HasRet; + + // If we're a non-static `struct' constructor which doesn't have an // initializer, then we must initialize all of the struct's fields. - if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable) + if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable) ok = false; if ((labels != null) && (Report.WarningLevel >= 2)) { foreach (LabeledStatement label in labels.Values) if (!label.HasBeenReferenced) - Report.Warning (164, 2, label.loc, - "This label has not been referenced"); + Report.Warning (164, 2, label.loc, "This label has not been referenced"); } - Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector); - - if (vector.IsUnreachable) - flags |= Flags.HasRet; - - if (ok && (errors == Report.Errors)) { - UsageWarning (vector); - } + if (ok && errors == Report.Errors) + UsageWarning (); return ok; } @@ -2200,7 +2278,7 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - for (int ix = 0; ix < num_statements; ix++){ + for (int ix = 0; ix < statements.Count; ix++){ Statement s = (Statement) statements [ix]; s.Emit (ec); } @@ -2209,37 +2287,58 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { Block prev_block = ec.CurrentBlock; - ec.CurrentBlock = this; - bool emit_debug_info = (CodeGen.SymbolWriter != null); - bool is_lexical_block = this == Explicit && Parent != null; + if (scope_initializers != null) { + SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); - if (emit_debug_info) { - if (is_lexical_block) - ec.BeginScope (); + bool omit_debug_info = ec.OmitDebuggingInfo; + ec.OmitDebuggingInfo = true; + foreach (StatementExpression s in scope_initializers) + s.Emit (ec); + ec.OmitDebuggingInfo = omit_debug_info; + + SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); } + ec.Mark (StartLocation, true); - if (scope_init != null) - scope_init.EmitStatement (ec); DoEmit (ec); - ec.Mark (EndLocation, true); - if (emit_debug_info) { - if (is_lexical_block) - ec.EndScope (); + ec.CurrentBlock = prev_block; + } - if (variables != null) { - foreach (DictionaryEntry de in variables) { - string name = (string) de.Key; - LocalInfo vi = (LocalInfo) de.Value; + protected virtual void EmitSymbolInfo (EmitContext ec) + { + if (variables != null) { + foreach (DictionaryEntry de in variables) { + string name = (string) de.Key; + LocalInfo vi = (LocalInfo) de.Value; - vi.EmitSymbolInfo (ec, name); - } + vi.EmitSymbolInfo (ec, name); } } + } - ec.CurrentBlock = prev_block; + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + MutateVariables (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 () @@ -2257,17 +2356,6 @@ namespace Mono.CSharp { target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit); if (Parent != null) target.Parent = clonectx.RemapBlockCopy (Parent); - - target.statements = new ArrayList (statements.Count); - foreach (Statement s in statements) - target.statements.Add (s.Clone (clonectx)); - - if (target.children != null){ - target.children = new ArrayList (children.Count); - foreach (Block b in children){ - target.children.Add (clonectx.RemapBlockCopy (b)); - } - } if (variables != null){ target.variables = new Hashtable (); @@ -2279,6 +2367,17 @@ namespace Mono.CSharp { } } + target.statements = new ArrayList (statements.Count); + foreach (Statement s in statements) + target.statements.Add (s.Clone (clonectx)); + + if (target.children != null){ + target.children = new ArrayList (children.Count); + foreach (Block b in children){ + target.children.Add (clonectx.LookupBlock (b)); + } + } + // // TODO: labels, switch_block, constants (?), anonymous_children // @@ -2286,6 +2385,9 @@ namespace Mono.CSharp { } public class ExplicitBlock : Block { + HybridDictionary known_variables; + protected AnonymousMethodStorey am_storey; + public ExplicitBlock (Block parent, Location start, Location end) : this (parent, (Flags) 0, start, end) { @@ -2297,8 +2399,6 @@ namespace Mono.CSharp { this.Explicit = this; } - Hashtable known_variables; - // // Marks a variable with name @name as being used in this or a child block. // If a variable name has been used in a child block, it's illegal to @@ -2307,7 +2407,7 @@ namespace Mono.CSharp { internal void AddKnownVariable (string name, IKnownVariable info) { if (known_variables == null) - known_variables = new Hashtable (); + known_variables = new HybridDictionary(); known_variables [name] = info; @@ -2315,11 +2415,125 @@ namespace Mono.CSharp { Parent.Explicit.AddKnownVariable (name, info); } + public AnonymousMethodStorey AnonymousMethodStorey { + get { return am_storey; } + } + + // + // Creates anonymous method storey in current block + // + public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec) + { + // + // When referencing a variable in iterator storey from children anonymous method + // + if (Toplevel.am_storey is IteratorStorey) { + ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey); + return Toplevel.am_storey; + } + + // + // An iterator has only 1 storey block + // + if (ec.CurrentIterator != null) + return ec.CurrentIterator.Storey; + + if (am_storey == null) { + MemberBase mc = ec.ResolveContext as MemberBase; + GenericMethod gm = mc == null ? null : mc.GenericMethod; + + // + // Create anonymous method storey for this block + // + am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey"); + } + + // + // Creates a link between this block and the anonymous method + // + // An anonymous method can reference variables from any outer block, but they are + // hoisted in their own ExplicitBlock. When more than one block is referenced we + // need to create another link between those variable storeys + // + ec.CurrentAnonymousMethod.AddStoreyReference (am_storey); + return am_storey; + } + + public override void Emit (EmitContext ec) + { + if (am_storey != null) + am_storey.EmitHoistedVariables (ec); + + bool emit_debug_info = SymbolWriter.HasSymbolWriter; + bool is_lexical_block = Parent != null && !(am_storey is IteratorStorey); + if (emit_debug_info && is_lexical_block) + ec.BeginScope (); + + base.Emit (ec); + + if (emit_debug_info) { + EmitSymbolInfo (ec); + if (is_lexical_block) + ec.EndScope (); + } + } + + public override void EmitMeta (EmitContext ec) + { + base.EmitMeta (ec); + + // + // It has to be done when all storey references are resolved + // + if (am_storey != null && am_storey.HasHoistedVariables) + am_storey.DefineMembers (); + } + + protected override void EmitSymbolInfo (EmitContext ec) + { + if (am_storey != null) + SymbolWriter.DefineScopeVariable (am_storey.ID); + + base.EmitSymbolInfo (ec); + } + internal IKnownVariable GetKnownVariable (string name) { return known_variables == null ? null : (IKnownVariable) known_variables [name]; } + public void PropagateStoreyReference (AnonymousMethodStorey s) + { + if (Parent != null && am_storey != s) { + if (am_storey != null) + am_storey.AddParentStoreyReference (s); + + Parent.Explicit.PropagateStoreyReference (s); + } + } + + public override bool Resolve (EmitContext ec) + { + bool ok = base.Resolve (ec); + + // + // Define an anonymous method storey when this block has hoisted variables + // otherwise the storey can be discarded + // + if (am_storey != null) { + if (am_storey.HasHoistedVariables) { + am_storey.DefineType (); + am_storey.DefineMembers (); + am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey); + } else { + am_storey.Undo (); + am_storey = null; + } + } + + return ok; + } + protected override void CloneTo (CloneContext clonectx, Statement t) { ExplicitBlock target = (ExplicitBlock) t; @@ -2361,19 +2575,11 @@ namespace Mono.CSharp { public class ToplevelBlock : ExplicitBlock { GenericMethod generic; FlowBranchingToplevel top_level_branching; - AnonymousContainer anonymous_container; - RootScopeInfo root_scope; Parameters parameters; ToplevelParameterInfo[] parameter_info; + LocalInfo this_variable; - public bool HasVarargs { - get { return (flags & Flags.HasVarargs) != 0; } - set { flags |= Flags.HasVarargs; } - } - - public bool IsIterator { - get { return (flags & Flags.IsIterator) != 0; } - } + public HoistedVariable HoistedThisVariable; // // The parameters for the block. @@ -2382,29 +2588,6 @@ namespace Mono.CSharp { get { return parameters; } } - public bool CompleteContexts (EmitContext ec) - { - Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope); - - if (root_scope != null) - root_scope.LinkScopes (); - - if (Parent == null && root_scope != null) { - Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope); - - if (root_scope.DefineType () == null) - return false; - if (!root_scope.ResolveType ()) - return false; - if (!root_scope.ResolveMembers ()) - return false; - if (!root_scope.DefineMembers ()) - return false; - } - - return true; - } - public GenericMethod GenericMethod { get { return generic; } } @@ -2413,11 +2596,6 @@ namespace Mono.CSharp { get { return Parent == null ? null : Parent.Toplevel; } } - public AnonymousContainer AnonymousContainer { - get { return anonymous_container; } - set { anonymous_container = value; } - } - public ToplevelBlock (Block parent, Parameters parameters, Location start) : this (parent, (Flags) 0, parameters, start) { @@ -2434,7 +2612,7 @@ namespace Mono.CSharp { { } - public ToplevelBlock (Flags flags, Parameters parameters, Location start) : + ToplevelBlock (Flags flags, Parameters parameters, Location start) : this (null, flags, parameters, start) { } @@ -2487,6 +2665,11 @@ namespace Mono.CSharp { return true; } + public virtual Expression GetTransparentIdentifier (string name) + { + return null; + } + void ProcessParameters () { int n = parameters.Count; @@ -2533,64 +2716,38 @@ namespace Mono.CSharp { return true; } - public RootScopeInfo CreateRootScope (TypeContainer host) + public override Expression CreateExpressionTree (EmitContext ec) { - if (root_scope != null) - return root_scope; - - if (Container == null) - root_scope = new RootScopeInfo ( - this, host, generic, StartLocation); - - if (scope_info != null) - throw new InternalErrorException (); - - scope_info = root_scope; - return root_scope; + return ((Statement) statements [0]).CreateExpressionTree (ec); } - public void CreateIteratorHost (RootScopeInfo root) + // + // Reformats this block to be top-level iterator block + // + public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source) { - Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope); + // Create block with original statements + ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation); - if (Parent != null || root_scope != null) - throw new InternalErrorException (); + // TODO: Change to iter_block.statements = statements; + foreach (Statement stmt in source.statements) + iter_block.AddStatement (stmt); + labels = source.labels; + + AddStatement (new IteratorStatement (iterator, iter_block)); - scope_info = root_scope = root; - } + source.statements = new ArrayList (1); + source.AddStatement (new Return (iterator, iterator.Location)); - public RootScopeInfo RootScope { - get { - if (root_scope != null) - return root_scope; - else if (Container != null) - return Container.RootScope; - else - return null; - } + IteratorStorey iterator_storey = new IteratorStorey (iterator); + source.am_storey = iterator_storey; + return iterator_storey; } public FlowBranchingToplevel TopLevelBranching { get { return top_level_branching; } } - // - // This is used if anonymous methods are used inside an iterator - // (see 2test-22.cs for an example). - // - // The AnonymousMethod is created while parsing - at a time when we don't - // know yet that we're inside an iterator, so it's `Container' is initially - // null. Later on, when resolving the iterator, we need to move the - // anonymous method into that iterator. - // - public void ReParent (ToplevelBlock new_parent) - { - if ((flags & Flags.VariablesInitialized) != 0) - throw new InternalErrorException ("block has already been resolved"); - - Parent = new_parent; - } - // // Returns a `ParameterReference' for the given name, or null if there // is no such parameter @@ -2612,29 +2769,6 @@ namespace Mono.CSharp { return null; } - // - // Whether the parameter named `name' is local to this block, - // or false, if the parameter belongs to an encompassing block. - // - public bool IsLocalParameter (string name) - { - return Parameters.GetParameterByName (name) != null; - } - - // - // Whether the `name' is a parameter reference - // - public bool IsParameterReference (string name) - { - for (ToplevelBlock t = this; t != null; t = t.Container) { - if (t.IsLocalParameter (name)) - return true; - } - return false; - } - - LocalInfo this_variable = null; - // // Returns the "this" instance variable of this block. // See AddThisVariable() for more information. @@ -2643,7 +2777,6 @@ namespace Mono.CSharp { get { return this_variable; } } - // // This is used by non-static `struct' constructors which do not have an // initializer - in this case, the constructor must initialize all of the @@ -2730,48 +2863,19 @@ namespace Mono.CSharp { public override void EmitMeta (EmitContext ec) { - base.EmitMeta (ec); - parameters.ResolveVariable (this); - } - - public void MakeIterator (Iterator iterator) - { - flags |= Flags.IsIterator; - - Block block = new ExplicitBlock (this, StartLocation, EndLocation); - foreach (Statement stmt in statements) - block.AddStatement (stmt); - statements.Clear (); - statements.Add (new MoveNextStatement (iterator, block)); - } - - protected class MoveNextStatement : Statement { - Iterator iterator; - Block block; - - public MoveNextStatement (Iterator iterator, Block block) - { - this.iterator = iterator; - this.block = block; - this.loc = iterator.Location; - } - - public override bool Resolve (EmitContext ec) - { - return block.Resolve (ec); - } + parameters.ResolveVariable (); - protected override void DoEmit (EmitContext ec) - { - iterator.EmitMoveNext (ec, block); - } + // Avoid declaring an IL variable for this_variable since it is not accessed + // from the generated IL + if (this_variable != null) + Variables.Remove ("this"); + base.EmitMeta (ec); } - public override string ToString () + public override void Emit (EmitContext ec) { - return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation, - root_scope, anonymous_container != null ? - anonymous_container.Scope : null); + base.Emit (ec); + ec.Mark (EndLocation, true); } } @@ -2852,7 +2956,7 @@ namespace Mono.CSharp { converted = NullStringCase; return true; } - + c = c.ImplicitConversionRequired (required_type, loc); if (c == null) return false; @@ -2861,19 +2965,19 @@ namespace Mono.CSharp { return true; } - public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith) + public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with) { string label; if (converted == null) label = "default"; else if (converted == NullStringCase) label = "null"; - else if (TypeManager.IsEnumType (switchType)) - label = TypeManager.CSharpEnumValue (switchType, converted); + else if (TypeManager.IsEnumType (switch_type)) + label = TypeManager.CSharpEnumValue (switch_type, converted); else label = converted.ToString (); - Report.SymbolRelatedToPreviousError (collisionWith.loc, null); + Report.SymbolRelatedToPreviousError (collision_with.loc, null); Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); } @@ -2977,7 +3081,7 @@ namespace Mono.CSharp { // Expression SwitchGoverningType (EmitContext ec, Expression expr) { - Type t = TypeManager.DropGenericTypeArguments (expr.Type); + Type t = expr.Type; if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || @@ -2990,7 +3094,7 @@ namespace Mono.CSharp { t == TypeManager.char_type || t == TypeManager.string_type || t == TypeManager.bool_type || - t.IsSubclassOf (TypeManager.enum_type)) + TypeManager.IsEnumType (t)) return expr; if (allowed_types == null){ @@ -3061,7 +3165,7 @@ namespace Mono.CSharp { foreach (SwitchLabel sl in ss.Labels){ if (sl.Label == null){ if (default_section != null){ - sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); + sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); error = true; } default_section = ss; @@ -3077,7 +3181,7 @@ namespace Mono.CSharp { try { Elements.Add (key, sl); } catch (ArgumentException) { - sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); + sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); error = true; } } @@ -3136,22 +3240,22 @@ namespace Mono.CSharp { // structure used to hold blocks of keys while calculating table switch class KeyBlock : IComparable { - public KeyBlock (long _nFirst) + public KeyBlock (long _first) { - nFirst = nLast = _nFirst; + first = last = _first; } - public long nFirst; - public long nLast; - public ArrayList rgKeys = null; + public long first; + public long last; + public ArrayList element_keys = null; // how many items are in the bucket public int Size = 1; public int Length { - get { return (int) (nLast - nFirst + 1); } + get { return (int) (last - first + 1); } } - public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast) + public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last) { - return kbLast.nLast - kbFirst.nFirst + 1; + return kb_last.last - kb_first.first + 1; } public int CompareTo (object obj) { @@ -3159,7 +3263,7 @@ namespace Mono.CSharp { int nLength = Length; int nLengthOther = kb.Length; if (nLengthOther == nLength) - return (int) (kb.nFirst - nFirst); + return (int) (kb.first - first); return nLength - nLengthOther; } } @@ -3176,89 +3280,89 @@ namespace Mono.CSharp { /// void TableSwitchEmit (EmitContext ec, LocalBuilder val) { - int cElements = Elements.Count; - object [] rgKeys = new object [cElements]; - Elements.Keys.CopyTo (rgKeys, 0); - Array.Sort (rgKeys); + int element_count = Elements.Count; + object [] element_keys = new object [element_count]; + Elements.Keys.CopyTo (element_keys, 0); + Array.Sort (element_keys); // initialize the block list with one element per key - ArrayList rgKeyBlocks = new ArrayList (); - foreach (object key in rgKeys) - rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); + ArrayList key_blocks = new ArrayList (); + foreach (object key in element_keys) + key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); - KeyBlock kbCurr; + KeyBlock current_kb; // iteratively merge the blocks while they are at least half full // there's probably a really cool way to do this with a tree... - while (rgKeyBlocks.Count > 1) + while (key_blocks.Count > 1) { - ArrayList rgKeyBlocksNew = new ArrayList (); - kbCurr = (KeyBlock) rgKeyBlocks [0]; - for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++) + ArrayList key_blocks_new = new ArrayList (); + current_kb = (KeyBlock) key_blocks [0]; + for (int ikb = 1; ikb < key_blocks.Count; ikb++) { - KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb]; - if ((kbCurr.Size + kb.Size) * 2 >= KeyBlock.TotalLength (kbCurr, kb)) + KeyBlock kb = (KeyBlock) key_blocks [ikb]; + if ((current_kb.Size + kb.Size) * 2 >= KeyBlock.TotalLength (current_kb, kb)) { // merge blocks - kbCurr.nLast = kb.nLast; - kbCurr.Size += kb.Size; + current_kb.last = kb.last; + current_kb.Size += kb.Size; } else { // start a new block - rgKeyBlocksNew.Add (kbCurr); - kbCurr = kb; + key_blocks_new.Add (current_kb); + current_kb = kb; } } - rgKeyBlocksNew.Add (kbCurr); - if (rgKeyBlocks.Count == rgKeyBlocksNew.Count) + key_blocks_new.Add (current_kb); + if (key_blocks.Count == key_blocks_new.Count) break; - rgKeyBlocks = rgKeyBlocksNew; + key_blocks = key_blocks_new; } // initialize the key lists - foreach (KeyBlock kb in rgKeyBlocks) - kb.rgKeys = new ArrayList (); + foreach (KeyBlock kb in key_blocks) + kb.element_keys = new ArrayList (); // fill the key lists int iBlockCurr = 0; - if (rgKeyBlocks.Count > 0) { - kbCurr = (KeyBlock) rgKeyBlocks [0]; - foreach (object key in rgKeys) + if (key_blocks.Count > 0) { + current_kb = (KeyBlock) key_blocks [0]; + foreach (object key in element_keys) { - bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast : - System.Convert.ToInt64 (key) > kbCurr.nLast; - if (fNextBlock) - kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr]; - kbCurr.rgKeys.Add (key); + bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last : + System.Convert.ToInt64 (key) > current_kb.last; + if (next_block) + current_kb = (KeyBlock) key_blocks [++iBlockCurr]; + current_kb.element_keys.Add (key); } } // sort the blocks so we can tackle the largest ones first - rgKeyBlocks.Sort (); + key_blocks.Sort (); // okay now we can start... ILGenerator ig = ec.ig; - Label lblEnd = ig.DefineLabel (); // at the end ;-) - Label lblDefault = ig.DefineLabel (); + Label lbl_end = ig.DefineLabel (); // at the end ;-) + Label lbl_default = ig.DefineLabel (); - Type typeKeys = null; - if (rgKeys.Length > 0) - typeKeys = rgKeys [0].GetType (); // used for conversions + Type type_keys = null; + if (element_keys.Length > 0) + type_keys = element_keys [0].GetType (); // used for conversions Type compare_type; if (TypeManager.IsEnumType (SwitchType)) - compare_type = TypeManager.EnumToUnderlying (SwitchType); + compare_type = TypeManager.GetEnumUnderlyingType (SwitchType); else compare_type = SwitchType; - for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock) + for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock) { - KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]); - lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel (); + KeyBlock kb = ((KeyBlock) key_blocks [iBlock]); + lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel (); if (kb.Length <= 2) { - foreach (object key in kb.rgKeys) + foreach (object key in kb.element_keys) { ig.Emit (OpCodes.Ldloc, val); EmitObjectInteger (ig, key); @@ -3277,17 +3381,17 @@ namespace Mono.CSharp { // check block range (could be > 2^31) ig.Emit (OpCodes.Ldloc, val); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys)); - ig.Emit (OpCodes.Blt, lblDefault); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); + ig.Emit (OpCodes.Blt, lbl_default); ig.Emit (OpCodes.Ldloc, val); - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nLast, typeKeys)); - ig.Emit (OpCodes.Bgt, lblDefault); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys)); + ig.Emit (OpCodes.Bgt, lbl_default); // normalize range ig.Emit (OpCodes.Ldloc, val); - if (kb.nFirst != 0) + if (kb.first != 0) { - EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys)); + EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); ig.Emit (OpCodes.Sub); } ig.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels! @@ -3296,15 +3400,15 @@ namespace Mono.CSharp { { // normalize range ig.Emit (OpCodes.Ldloc, val); - int nFirst = (int) kb.nFirst; - if (nFirst > 0) + int first = (int) kb.first; + if (first > 0) { - IntConstant.EmitInt (ig, nFirst); + IntConstant.EmitInt (ig, first); ig.Emit (OpCodes.Sub); } - else if (nFirst < 0) + else if (first < 0) { - IntConstant.EmitInt (ig, -nFirst); + IntConstant.EmitInt (ig, -first); ig.Emit (OpCodes.Add); } } @@ -3312,26 +3416,26 @@ namespace Mono.CSharp { // first, build the list of labels for the switch int iKey = 0; int cJumps = kb.Length; - Label [] rgLabels = new Label [cJumps]; + Label [] switch_labels = new Label [cJumps]; for (int iJump = 0; iJump < cJumps; iJump++) { - object key = kb.rgKeys [iKey]; - if (System.Convert.ToInt64 (key) == kb.nFirst + iJump) + object key = kb.element_keys [iKey]; + if (System.Convert.ToInt64 (key) == kb.first + iJump) { SwitchLabel sl = (SwitchLabel) Elements [key]; - rgLabels [iJump] = sl.GetILLabel (ec); + switch_labels [iJump] = sl.GetILLabel (ec); iKey++; } else - rgLabels [iJump] = lblDefault; + switch_labels [iJump] = lbl_default; } // emit the switch opcode - ig.Emit (OpCodes.Switch, rgLabels); + ig.Emit (OpCodes.Switch, switch_labels); } // mark the default for this block if (iBlock != 0) - ig.MarkLabel (lblDefault); + ig.MarkLabel (lbl_default); } // TODO: find the default case and emit it here, @@ -3339,16 +3443,16 @@ namespace Mono.CSharp { // make sure to mark other labels in the default section // the last default just goes to the end - ig.Emit (OpCodes.Br, lblDefault); + ig.Emit (OpCodes.Br, lbl_default); // now emit the code for the sections - bool fFoundDefault = false; - bool fFoundNull = false; + bool found_default = false; + bool found_null = false; foreach (SwitchSection ss in Sections) { foreach (SwitchLabel sl in ss.Labels) if (sl.Converted == SwitchLabel.NullStringCase) - fFoundNull = true; + found_null = true; } foreach (SwitchSection ss in Sections) @@ -3360,23 +3464,23 @@ namespace Mono.CSharp { if (sl.Converted == SwitchLabel.NullStringCase) ig.MarkLabel (null_target); else if (sl.Label == null) { - ig.MarkLabel (lblDefault); - fFoundDefault = true; - if (!fFoundNull) + ig.MarkLabel (lbl_default); + found_default = true; + if (!found_null) ig.MarkLabel (null_target); } } ss.Block.Emit (ec); } - if (!fFoundDefault) { - ig.MarkLabel (lblDefault); - if (HaveUnwrap && !fFoundNull) { + if (!found_default) { + ig.MarkLabel (lbl_default); + if (HaveUnwrap && !found_null) { ig.MarkLabel (null_target); } } - ig.MarkLabel (lblEnd); + ig.MarkLabel (lbl_end); } // // This simple emit switch works, but does not take advantage of the @@ -3491,6 +3595,12 @@ namespace Mono.CSharp { return null; } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + foreach (SwitchSection ss in Sections) + ss.Block.MutateHoistedGenericType (storey); + } + public override bool Resolve (EmitContext ec) { Expr = Expr.Resolve (ec); @@ -3518,7 +3628,7 @@ namespace Mono.CSharp { SwitchType = new_expr.Type; if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) { - Report.FeatureIsNotISO1 (loc, "switch expression of boolean type"); + Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); return false; } @@ -3546,6 +3656,7 @@ namespace Mono.CSharp { } bool first = true; + bool ok = true; foreach (SwitchSection ss in Sections){ if (!first) ec.CurrentBranching.CreateSibling ( @@ -3558,11 +3669,12 @@ namespace Mono.CSharp { // one single section - mark all the others as // unreachable. ec.CurrentBranching.CurrentUsageVector.Goto (); - if (!ss.Block.ResolveUnreachable (ec, true)) - return false; + if (!ss.Block.ResolveUnreachable (ec, true)) { + ok = false; + } } else { if (!ss.Block.Resolve (ec)) - return false; + ok = false; } } @@ -3575,7 +3687,12 @@ namespace Mono.CSharp { Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching); - return true; + if (TypeManager.string_isinterned_string == null) { + TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type, + "IsInterned", loc, TypeManager.string_type); + } + + return ok; } protected override void DoEmit (EmitContext ec) @@ -3642,102 +3759,264 @@ namespace Mono.CSharp { } } - public abstract class ExceptionStatement : Statement + // A place where execution can restart in an iterator + public abstract class ResumableStatement : Statement { - public abstract void EmitFinally (EmitContext ec); - - protected bool emit_finally = true; - ArrayList parent_vectors; + bool prepared; + protected Label resume_point; - protected void DoEmitFinally (EmitContext ec) + public Label PrepareForEmit (EmitContext ec) { - if (emit_finally) - ec.ig.BeginFinallyBlock (); - else if (ec.InIterator) - ec.CurrentIterator.MarkFinally (ec, parent_vectors); - EmitFinally (ec); + if (!prepared) { + prepared = true; + resume_point = ec.ig.DefineLabel (); + } + return resume_point; } - protected void ResolveFinally (FlowBranchingException branching) + public virtual Label PrepareForDispose (EmitContext ec, Label end) { - emit_finally = branching.EmitFinally; - if (!emit_finally) - branching.Parent.StealFinallyClauses (ref parent_vectors); + return end; } - } - - public class Lock : ExceptionStatement { - Expression expr; - public Statement Statement; - TemporaryVariable temp; - - public Lock (Expression expr, Statement stmt, Location l) + public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher) { - this.expr = expr; - Statement = stmt; - loc = l; } + } - public override bool Resolve (EmitContext ec) + // Base class for statements that are implemented in terms of try...finally + public abstract class ExceptionStatement : ResumableStatement + { + bool code_follows; + + protected abstract void EmitPreTryBody (EmitContext ec); + protected abstract void EmitTryBody (EmitContext ec); + protected abstract void EmitFinallyBody (EmitContext ec); + + protected sealed override void DoEmit (EmitContext ec) { - expr = expr.Resolve (ec); - if (expr == null) - return false; + ILGenerator ig = ec.ig; - if (expr.Type.IsValueType){ - Report.Error (185, loc, - "`{0}' is not a reference type as required by the lock statement", - TypeManager.CSharpName (expr.Type)); - return false; + EmitPreTryBody (ec); + + if (resume_points != null) { + IntConstant.EmitInt (ig, (int) Iterator.State.Running); + ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC); } - FlowBranchingException branching = ec.StartFlowBranching (this); - bool ok = Statement.Resolve (ec); + ig.BeginExceptionBlock (); - ResolveFinally (branching); + if (resume_points != null) { + ig.MarkLabel (resume_point); - ec.EndFlowBranching (); + // 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); - // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block. - // So, ensure there's some IL code after the finally block. - ec.NeedReturnLabel (); + 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); + } - // Avoid creating libraries that reference the internal - // mcs NullType: - Type t = expr.Type; - if (t == TypeManager.null_type) - t = TypeManager.object_type; - - temp = new TemporaryVariable (t, loc); - temp.Resolve (ec); - - return ok; + EmitTryBody (ec); + + ig.BeginFinallyBlock (); + + Label start_finally = ec.ig.DefineLabel (); + if (resume_points != null) { + ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally); + ig.Emit (OpCodes.Brfalse_S, start_finally); + ig.Emit (OpCodes.Endfinally); + } + + ig.MarkLabel (start_finally); + EmitFinallyBody (ec); + + ig.EndExceptionBlock (); + } + + public void SomeCodeFollows () + { + code_follows = true; + } + + protected void ResolveReachability (EmitContext 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 (); + + } + + ArrayList resume_points; + int first_resume_pc; + public void AddResumePoint (ResumableStatement stmt, Location loc, int pc) + { + if (resume_points == null) { + resume_points = new ArrayList (); + first_resume_pc = pc; + } + + if (pc != first_resume_pc + resume_points.Count) + throw new InternalErrorException ("missed an intervening AddResumePoint?"); + + resume_points.Add (stmt); + } + + Label dispose_try_block; + bool prepared_for_dispose, emitted_dispose; + public override Label PrepareForDispose (EmitContext ec, Label end) + { + if (!prepared_for_dispose) { + prepared_for_dispose = true; + dispose_try_block = ec.ig.DefineLabel (); + } + return dispose_try_block; + } + + public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher) + { + if (emitted_dispose) + return; + + emitted_dispose = true; + + ILGenerator ig = ec.ig; + + Label end_of_try = ig.DefineLabel (); + + // Ensure that the only way we can get into this code is through a dispatcher + if (have_dispatcher) + ig.Emit (OpCodes.Br, end); + + ig.BeginExceptionBlock (); + + ig.MarkLabel (dispose_try_block); + + Label [] labels = null; + for (int i = 0; i < resume_points.Count; ++i) { + ResumableStatement s = (ResumableStatement) resume_points [i]; + Label ret = s.PrepareForDispose (ec, end_of_try); + if (ret.Equals (end_of_try) && labels == null) + continue; + if (labels == null) { + labels = new Label [resume_points.Count]; + for (int j = 0; j < i; ++j) + labels [j] = end_of_try; + } + labels [i] = ret; + } + + if (labels != null) { + int j; + for (j = 1; j < labels.Length; ++j) + if (!labels [0].Equals (labels [j])) + break; + bool emit_dispatcher = j < labels.Length; + + 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); + //SymbolWriter.EndIteratorDispatcher (ec.ig); + } + + foreach (ResumableStatement s in resume_points) + s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher); + } + + ig.MarkLabel (end_of_try); + + ig.BeginFinallyBlock (); + + EmitFinallyBody (ec); + + ig.EndExceptionBlock (); + } + } + + public class Lock : ExceptionStatement { + Expression expr; + public Statement Statement; + TemporaryVariable temp; + + public Lock (Expression expr, Statement stmt, Location l) + { + this.expr = expr; + Statement = stmt; + loc = l; + } + + public override bool Resolve (EmitContext ec) + { + expr = expr.Resolve (ec); + if (expr == null) + return false; + + if (expr.Type.IsValueType){ + Report.Error (185, loc, + "`{0}' is not a reference type as required by the lock statement", + TypeManager.CSharpName (expr.Type)); + return false; + } + + ec.StartFlowBranching (this); + bool ok = Statement.Resolve (ec); + ec.EndFlowBranching (); + + ResolveReachability (ec); + + // Avoid creating libraries that reference the internal + // mcs NullType: + Type t = expr.Type; + if (t == TypeManager.null_type) + t = TypeManager.object_type; + + temp = new TemporaryVariable (t, loc); + temp.Resolve (ec); + + if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) { + Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true); + TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod ( + monitor_type, "Enter", loc, TypeManager.object_type); + TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod ( + monitor_type, "Exit", loc, TypeManager.object_type); + } + + return ok; } - protected override void DoEmit (EmitContext ec) + protected override void EmitPreTryBody (EmitContext ec) { ILGenerator ig = ec.ig; - temp.Store (ec, expr); + temp.EmitAssign (ec, expr); temp.Emit (ec); ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object); + } - // try - if (emit_finally) - ig.BeginExceptionBlock (); + protected override void EmitTryBody (EmitContext ec) + { Statement.Emit (ec); - - // finally - DoEmitFinally (ec); - if (emit_finally) - ig.EndExceptionBlock (); } - public override void EmitFinally (EmitContext ec) + protected override void EmitFinallyBody (EmitContext ec) { temp.Emit (ec); ec.ig.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) { @@ -3769,6 +4048,11 @@ namespace Mono.CSharp { Block.Emit (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + Block.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Unchecked target = (Unchecked) t; @@ -3798,6 +4082,11 @@ namespace Mono.CSharp { Block.Emit (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + Block.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Checked target = (Checked) t; @@ -3826,6 +4115,12 @@ namespace Mono.CSharp { using (ec.With (EmitContext.Flags.InUnsafe, true)) Block.Emit (ec); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + Block.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Unsafe target = (Unsafe) t; @@ -3871,18 +4166,60 @@ namespace Mono.CSharp { // Store pointer in pinned location // converted.Emit (ec); - vi.Variable.EmitAssign (ec); + vi.EmitAssign (ec); } public override void EmitExit (EmitContext ec) { ec.ig.Emit (OpCodes.Ldc_I4_0); ec.ig.Emit (OpCodes.Conv_U); - vi.Variable.EmitAssign (ec); + vi.EmitAssign (ec); } } class StringEmitter : Emitter { + class StringPtr : Expression + { + LocalBuilder b; + + public StringPtr (LocalBuilder b, Location l) + { + this.b = b; + eclass = ExprClass.Value; + type = TypeManager.char_ptr_type; + loc = l; + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + + public override Expression DoResolve (EmitContext ec) + { + // This should never be invoked, we are born in fully + // initialized state. + + return this; + } + + public override void Emit (EmitContext ec) + { + if (TypeManager.int_get_offset_to_string_data == null) { + // TODO: Move to resolve !! + TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod ( + TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes); + } + + ILGenerator ig = ec.ig; + + ig.Emit (OpCodes.Ldloc, b); + ig.Emit (OpCodes.Conv_I); + ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data); + ig.Emit (OpCodes.Add); + } + } + LocalBuilder pinned_string; Location loc; @@ -3908,7 +4245,7 @@ namespace Mono.CSharp { return; converted.Emit (ec); - vi.Variable.EmitAssign (ec); + vi.EmitAssign (ec); } public override void EmitExit (EmitContext ec) @@ -3937,9 +4274,13 @@ namespace Mono.CSharp { return false; } - TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false); - if (texpr == null) + 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"); + return false; + } expr_type = texpr.Type; @@ -4039,6 +4380,17 @@ namespace Mono.CSharp { ec, array_ptr, vi.VariableType, loc); if (converted == null) return false; + + // + // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0]) + // + converted = new Conditional (new Binary (Binary.Operator.LogicalOr, + new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)), + new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))), + NullPointer.Null, + converted); + + converted = converted.Resolve (ec); data [i] = new ExpressionEmitter (converted, vi); i++; @@ -4103,14 +4455,26 @@ 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 (); - foreach (LocalInfo var in declarators) - target.declarators.Add (clonectx.LookupVariable (var)); + target.declarators = new ArrayList (declarators.Count); + foreach (Pair p in declarators) { + LocalInfo vi = (LocalInfo) p.First; + Expression e = (Expression) p.Second; + + target.declarators.Add ( + new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx))); + } + target.statement = statement.Clone (clonectx); } } @@ -4144,7 +4508,7 @@ namespace Mono.CSharp { } } - protected override void DoEmit(EmitContext ec) + protected override void DoEmit (EmitContext ec) { ILGenerator ig = ec.ig; @@ -4157,19 +4521,21 @@ namespace Mono.CSharp { VarBlock.Emit (ec); if (Name != null) { - LocalInfo vi = Block.GetLocalInfo (Name); - if (vi == null) - throw new Exception ("Variable does not exist in this block"); - - if (vi.Variable.NeedsTemporary) { - LocalBuilder e = ig.DeclareLocal (vi.VariableType); - ig.Emit (OpCodes.Stloc, e); + // TODO: Move to resolve + LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); + lvr.Resolve (ec); + + Expression source; + if (lvr.IsHoisted) { + LocalTemporary lt = new LocalTemporary (lvr.Type); + lt.Store (ec); + source = lt; + } else { + // Variable is at the top of the stack + source = EmptyExpression.Null; + } - vi.Variable.EmitInstance (ec); - ig.Emit (OpCodes.Ldloc, e); - vi.Variable.EmitAssign (ec); - } else - vi.Variable.EmitAssign (ec); + lvr.EmitAssign (ec, source, false, false); } else ig.Emit (OpCodes.Pop); @@ -4186,7 +4552,7 @@ namespace Mono.CSharp { type = te.Type; - if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){ + if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){ Error (155, "The type caught or thrown must be derived from System.Exception"); return false; } @@ -4205,61 +4571,131 @@ 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; - target.type_expr = type_expr.Clone (clonectx); + if (type_expr != null) + target.type_expr = type_expr.Clone (clonectx); + if (VarBlock != null) + target.VarBlock = clonectx.LookupBlock (VarBlock); target.Block = clonectx.LookupBlock (Block); - target.VarBlock = clonectx.LookupBlock (VarBlock); } } - public class Try : ExceptionStatement { - public Block Fini, Block; + public class TryFinally : ExceptionStatement { + Statement stmt; + Block fini; + + public TryFinally (Statement stmt, Block fini, Location l) + { + this.stmt = stmt; + this.fini = fini; + loc = l; + } + + public override bool Resolve (EmitContext ec) + { + bool ok = true; + + ec.StartFlowBranching (this); + + if (!stmt.Resolve (ec)) + ok = false; + + if (ok) + ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally); + using (ec.With (EmitContext.Flags.InFinally, true)) { + if (!fini.Resolve (ec)) + ok = false; + } + + ec.EndFlowBranching (); + + ResolveReachability (ec); + + return ok; + } + + protected override void EmitPreTryBody (EmitContext ec) + { + } + + protected override void EmitTryBody (EmitContext ec) + { + stmt.Emit (ec); + } + + protected override void EmitFinallyBody (EmitContext ec) + { + 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; + + target.stmt = (Statement) stmt.Clone (clonectx); + if (fini != null) + target.fini = clonectx.LookupBlock (fini); + } + } + + public class TryCatch : Statement { + public Block Block; public ArrayList Specific; public Catch General; + bool inside_try_finally, code_follows; - bool need_exc_block; - - // - // specific, general and fini might all be null. - // - public Try (Block block, ArrayList specific, Catch general, Block fini, Location l) + public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally) { - if (specific == null && general == null){ - Console.WriteLine ("CIR.Try: Either specific or general have to be non-null"); - } - this.Block = block; - this.Specific = specific; - this.General = general; - this.Fini = fini; + 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--; + } + } + loc = l; } public override bool Resolve (EmitContext ec) { bool ok = true; - - FlowBranchingException branching = ec.StartFlowBranching (this); - Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation); + ec.StartFlowBranching (this); if (!Block.Resolve (ec)) ok = false; - FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector; - - Report.Debug (1, "START OF CATCH BLOCKS", vector); - - Type[] prevCatches = new Type [Specific.Count]; + Type[] prev_catches = new Type [Specific.Count]; int last_index = 0; foreach (Catch c in Specific){ - ec.CurrentBranching.CreateSibling ( - c.Block, FlowBranching.SiblingType.Catch); - - Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching); + ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch); if (c.Name != null) { LocalInfo vi = c.Block.GetLocalInfo (c.Name); @@ -4270,23 +4706,20 @@ namespace Mono.CSharp { } if (!c.Resolve (ec)) - return false; + ok = false; - Type resolvedType = c.CatchType; + Type resolved_type = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { - if (resolvedType == prevCatches [ii] || resolvedType.IsSubclassOf (prevCatches [ii])) { - Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prevCatches [ii].FullName); - return false; + if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) { + Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName); + ok = false; } } - prevCatches [last_index++] = resolvedType; - need_exc_block = true; + prev_catches [last_index++] = resolved_type; } - Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching); - - if (General != null){ + if (General != null) { if (CodeGen.Assembly.WrapNonExceptionThrows) { foreach (Catch c in Specific){ if (c.CatchType == TypeManager.exception_type) { @@ -4295,58 +4728,34 @@ namespace Mono.CSharp { } } - ec.CurrentBranching.CreateSibling ( - General.Block, FlowBranching.SiblingType.Catch); - - Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching); + ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch); if (!General.Resolve (ec)) ok = false; - - need_exc_block = true; } - Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching); - - if (Fini != null) { - if (ok) - ec.CurrentBranching.CreateSibling (Fini, FlowBranching.SiblingType.Finally); - - Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector); - using (ec.With (EmitContext.Flags.InFinally, true)) { - if (!Fini.Resolve (ec)) - ok = false; - } - - if (!ec.InIterator) - need_exc_block = true; - } - - if (ec.InIterator) { - ResolveFinally (branching); - need_exc_block |= emit_finally; - } else - emit_finally = Fini != null; - ec.EndFlowBranching (); - // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block. - // So, ensure there's some IL code after the finally block. - ec.NeedReturnLabel (); - - FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector; - - Report.Debug (1, "END OF TRY", ec.CurrentBranching, vector, f_vector); + // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause + // So, ensure there's some IL code after this statement + if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable) + ec.NeedReturnLabel (); return ok; } + + public void SomeCodeFollows () + { + code_follows = true; + } protected override void DoEmit (EmitContext ec) { ILGenerator ig = ec.ig; - if (need_exc_block) + if (!inside_try_finally) ig.BeginExceptionBlock (); + Block.Emit (ec); foreach (Catch c in Specific) @@ -4355,31 +4764,27 @@ namespace Mono.CSharp { if (General != null) General.Emit (ec); - DoEmitFinally (ec); - if (need_exc_block) + if (!inside_try_finally) ig.EndExceptionBlock (); } - public override void EmitFinally (EmitContext ec) + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { - if (Fini != null) - Fini.Emit (ec); - } + Block.MutateHoistedGenericType (storey); - public bool HasCatch - { - get { - return General != null || Specific.Count > 0; + if (General != null) + General.MutateHoistedGenericType (storey); + if (Specific != null) { + foreach (Catch c in Specific) + c.MutateHoistedGenericType (storey); } } protected override void CloneTo (CloneContext clonectx, Statement t) { - Try target = (Try) t; + TryCatch target = (TryCatch) t; target.Block = clonectx.LookupBlock (Block); - if (Fini != null) - target.Fini = clonectx.LookupBlock (Fini); if (General != null) target.General = (Catch) General.Clone (clonectx); if (Specific != null){ @@ -4390,206 +4795,200 @@ namespace Mono.CSharp { } } - public class Using : ExceptionStatement { - object expression_or_block; + public class UsingTemporary : ExceptionStatement { + TemporaryVariable local_copy; public Statement Statement; - ArrayList var_list; Expression expr; Type expr_type; - Expression [] resolved_vars; - Expression [] converted_vars; - Expression [] assign; - TemporaryVariable local_copy; - - public Using (object expression_or_block, Statement stmt, Location l) + + public UsingTemporary (Expression expr, Statement stmt, Location l) { - this.expression_or_block = expression_or_block; + this.expr = expr; Statement = stmt; loc = l; } - // - // Resolves for the case of using using a local variable declaration. - // - bool ResolveLocalVariableDecls (EmitContext ec) + public override bool Resolve (EmitContext ec) { - resolved_vars = new Expression[var_list.Count]; - assign = new Expression [var_list.Count]; - converted_vars = new Expression[var_list.Count]; + expr = expr.Resolve (ec); + if (expr == null) + return false; - for (int i = 0; i < assign.Length; ++i) { - DictionaryEntry e = (DictionaryEntry) var_list [i]; - Expression var = (Expression) e.Key; - Expression new_expr = (Expression) e.Value; + expr_type = expr.Type; - Expression a = new Assign (var, new_expr, loc); - a = a.Resolve (ec); - if (a == null) + if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) { + if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { + Using.Error_IsNotConvertibleToIDisposable (expr); return false; + } + } - resolved_vars [i] = var; - assign [i] = a; + local_copy = new TemporaryVariable (expr_type, loc); + local_copy.Resolve (ec); - if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) { - converted_vars [i] = var; - continue; - } + ec.StartFlowBranching (this); - a = Convert.ImplicitConversion (ec, a, TypeManager.idisposable_type, var.Location); - if (a == null) { - Error_IsNotConvertibleToIDisposable (var); - return false; - } + bool ok = Statement.Resolve (ec); - converted_vars [i] = a; + ec.EndFlowBranching (); + + ResolveReachability (ec); + + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); } - return true; + return ok; } - static void Error_IsNotConvertibleToIDisposable (Expression expr) + protected override void EmitPreTryBody (EmitContext ec) { - 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 ()); + local_copy.EmitAssign (ec, expr); } - bool ResolveExpression (EmitContext ec) + protected override void EmitTryBody (EmitContext ec) { - if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){ - if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { - Error_IsNotConvertibleToIDisposable (expr); - return false; - } - } - - local_copy = new TemporaryVariable (expr_type, loc); - local_copy.Resolve (ec); - - return true; + Statement.Emit (ec); } - - // - // Emits the code for the case of using using a local variable declaration. - // - void EmitLocalVariableDecls (EmitContext ec) + + protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; - int i = 0; + if (!expr_type.IsValueType) { + 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; + } - for (i = 0; i < assign.Length; i++) { - ExpressionStatement es = assign [i] as ExpressionStatement; + Expression ml = Expression.MemberLookup ( + ec.ContainerType, TypeManager.idisposable_type, expr_type, + "Dispose", Location.Null); - if (es != null) - es.EmitStatement (ec); - else { - assign [i].Emit (ec); - ig.Emit (OpCodes.Pop); + 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 (emit_finally) - ig.BeginExceptionBlock (); + if (mi == null) { + Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); + return; } - Statement.Emit (ec); - var_list.Reverse (); + local_copy.AddressOf (ec, AddressOp.Load); + ig.Emit (OpCodes.Call, mi); + } - DoEmitFinally (ec); + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr_type = storey.MutateType (expr_type); + local_copy.MutateHoistedGenericType (storey); + Statement.MutateHoistedGenericType (storey); } - void EmitLocalVariableDeclFinally (EmitContext ec) + protected override void CloneTo (CloneContext clonectx, Statement t) { - ILGenerator ig = ec.ig; + UsingTemporary target = (UsingTemporary) t; - int i = assign.Length; - for (int ii = 0; ii < var_list.Count; ++ii){ - Expression var = resolved_vars [--i]; - Label skip = ig.DefineLabel (); + target.expr = expr.Clone (clonectx); + target.Statement = Statement.Clone (clonectx); + } + } - if (emit_finally) - ig.BeginFinallyBlock (); - - if (!var.Type.IsValueType) { - var.Emit (ec); - ig.Emit (OpCodes.Brfalse, skip); - converted_vars [i].Emit (ec); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } else { - Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null); + public class Using : ExceptionStatement { + Statement stmt; + public Statement EmbeddedStatement { + get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; } + } - if (!(ml is MethodGroupExpr)) { - var.Emit (ec); - ig.Emit (OpCodes.Box, var.Type); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } else { - MethodInfo mi = null; + Expression var; + Expression init; - foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) { - if (TypeManager.GetParameterData (mk).Count == 0) { - mi = mk; - break; - } - } + Expression converted_var; + ExpressionStatement assign; - if (mi == null) { - Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); - return; - } + public Using (Expression var, Expression init, Statement stmt, Location l) + { + this.var = var; + this.init = init; + this.stmt = stmt; + loc = l; + } - IMemoryLocation mloc = (IMemoryLocation) var; + bool ResolveVariable (EmitContext ec) + { + ExpressionStatement a = new SimpleAssign (var, init, loc); + a = a.ResolveStatement (ec); + if (a == null) + return false; - mloc.AddressOf (ec, AddressOp.Load); - ig.Emit (OpCodes.Call, mi); - } - } + assign = a; - ig.MarkLabel (skip); + if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) { + converted_var = var; + return true; + } - if (emit_finally) { - ig.EndExceptionBlock (); - if (i > 0) - ig.BeginFinallyBlock (); - } + Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location); + if (e == null) { + Error_IsNotConvertibleToIDisposable (var); + return false; } + + converted_var = e; + + return true; } - void EmitExpression (EmitContext ec) + static public void Error_IsNotConvertibleToIDisposable (Expression expr) { - // - // Make a copy of the expression and operate on that. - // - ILGenerator ig = ec.ig; - - local_copy.Store (ec, 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 ()); + } - if (emit_finally) - ig.BeginExceptionBlock (); + protected override void EmitPreTryBody (EmitContext ec) + { + assign.EmitStatement (ec); + } - Statement.Emit (ec); - - DoEmitFinally (ec); - if (emit_finally) - ig.EndExceptionBlock (); + protected override void EmitTryBody (EmitContext ec) + { + stmt.Emit (ec); } - void EmitExpressionFinally (EmitContext ec) + protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; - if (!expr_type.IsValueType) { + + if (!var.Type.IsValueType) { Label skip = ig.DefineLabel (); - local_copy.Emit (ec); + var.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); - local_copy.Emit (ec); + converted_var.Emit (ec); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); ig.MarkLabel (skip); } else { - Expression ml = Expression.MemberLookup ( - ec.ContainerType, TypeManager.idisposable_type, expr_type, - "Dispose", Location.Null); + Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null); if (!(ml is MethodGroupExpr)) { - local_copy.Emit (ec); - ig.Emit (OpCodes.Box, expr_type); + var.Emit (ec); + ig.Emit (OpCodes.Box, var.Type); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); } else { MethodInfo mi = null; @@ -4606,75 +5005,49 @@ namespace Mono.CSharp { return; } - local_copy.AddressOf (ec, AddressOp.Load); + IMemoryLocation mloc = (IMemoryLocation) var; + + mloc.AddressOf (ec, AddressOp.Load); ig.Emit (OpCodes.Call, mi); } } } - + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + assign.MutateHoistedGenericType (storey); + var.MutateHoistedGenericType (storey); + stmt.MutateHoistedGenericType (storey); + } + public override bool Resolve (EmitContext ec) { - if (expression_or_block is DictionaryEntry){ - expr = (Expression) ((DictionaryEntry) expression_or_block).Key; - var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value; + if (!ResolveVariable (ec)) + return false; - if (!ResolveLocalVariableDecls (ec)) - return false; + ec.StartFlowBranching (this); - } else if (expression_or_block is Expression){ - expr = (Expression) expression_or_block; + bool ok = stmt.Resolve (ec); - expr = expr.Resolve (ec); - if (expr == null) - return false; + ec.EndFlowBranching (); - expr_type = expr.Type; + ResolveReachability (ec); - if (!ResolveExpression (ec)) - return false; + if (TypeManager.void_dispose_void == null) { + TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( + TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes); } - FlowBranchingException branching = ec.StartFlowBranching (this); - - bool ok = Statement.Resolve (ec); - - ResolveFinally (branching); - - ec.EndFlowBranching (); - - // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block. - // So, ensure there's some IL code after the finally block. - ec.NeedReturnLabel (); - return ok; } - - protected override void DoEmit (EmitContext ec) - { - if (expression_or_block is DictionaryEntry) - EmitLocalVariableDecls (ec); - else if (expression_or_block is Expression) - EmitExpression (ec); - } - - public override void EmitFinally (EmitContext ec) - { - if (expression_or_block is DictionaryEntry) - EmitLocalVariableDeclFinally (ec); - else if (expression_or_block is Expression) - EmitExpressionFinally (ec); - } protected override void CloneTo (CloneContext clonectx, Statement t) { Using target = (Using) t; - if (expression_or_block is Expression) - target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx); - else - target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx); - - target.Statement = Statement.Clone (clonectx); + target.var = var.Clone (clonectx); + target.init = init.Clone (clonectx); + target.stmt = stmt.Clone (clonectx); } } @@ -4686,8 +5059,6 @@ namespace Mono.CSharp { Expression variable; Expression expr; Statement statement; - ArrayForeach array; - CollectionForeach collection; public Foreach (Expression type, LocalVariableReference var, Expression expr, Statement stmt, Location l) @@ -4709,7 +5080,7 @@ namespace Mono.CSharp { if (expr == null) return false; - if (expr.Type == TypeManager.null_type) { + if (expr.IsNull) { Report.Error (186, loc, "Use of null is not valid in this context"); return false; } @@ -4720,26 +5091,13 @@ namespace Mono.CSharp { return false; } - // - // We need an instance variable. Not sure this is the best - // way of doing this. - // - // FIXME: When we implement propertyaccess, will those turn - // out to return values in ExprClass? I think they should. - // - if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value || - expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){ - collection.Error_Enumerator (); - return false; - } - if (expr.Type.IsArray) { - array = new ArrayForeach (type, variable, expr, statement, loc); - return array.Resolve (ec); + statement = new ArrayForeach (type, variable, expr, statement, loc); + } else { + statement = new CollectionForeach (type, variable, expr, statement, loc); } - collection = new CollectionForeach (type, variable, expr, statement, loc); - return collection.Resolve (ec); + return statement.Resolve (ec); } protected override void DoEmit (EmitContext ec) @@ -4750,10 +5108,7 @@ namespace Mono.CSharp { ec.LoopBegin = ig.DefineLabel (); ec.LoopEnd = ig.DefineLabel (); - if (collection != null) - collection.Emit (ec); - else - array.Emit (ec); + statement.Emit (ec); ec.LoopBegin = old_begin; ec.LoopEnd = old_end; @@ -4761,24 +5116,22 @@ namespace Mono.CSharp { protected class ArrayCounter : TemporaryVariable { + StatementExpression increment; + public ArrayCounter (Location loc) : base (TypeManager.int32_type, loc) - { } + { + } - public void Initialize (EmitContext ec) + public void ResolveIncrement (EmitContext ec) { - EmitThis (ec); - ec.ig.Emit (OpCodes.Ldc_I4_0); - EmitStore (ec); + increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc)); + increment.Resolve (ec); } - public void Increment (EmitContext ec) + public void EmitIncrement (EmitContext ec) { - EmitThis (ec); - Emit (ec); - ec.ig.Emit (OpCodes.Ldc_I4_1); - ec.ig.Emit (OpCodes.Add); - EmitStore (ec); + increment.Emit (ec); } } @@ -4794,6 +5147,7 @@ namespace Mono.CSharp { TemporaryVariable copy; Expression access; + Expression[] length_exprs; public ArrayForeach (Expression var_type, Expression var, Expression expr, Statement stmt, Location l) @@ -4815,15 +5169,24 @@ namespace Mono.CSharp { counter = new ArrayCounter [rank]; lengths = new TemporaryVariable [rank]; + length_exprs = new Expression [rank]; - ArrayList list = new ArrayList (); + ArrayList list = new ArrayList (rank); for (int i = 0; i < rank; i++) { counter [i] = new ArrayCounter (loc); - counter [i].Resolve (ec); + counter [i].ResolveIncrement (ec); lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); lengths [i].Resolve (ec); + if (rank == 1) { + length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec); + } else { + ArrayList args = new ArrayList (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]); } @@ -4871,7 +5234,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - copy.Store (ec, expr); + copy.EmitAssign (ec, expr); Label[] test = new Label [rank]; Label[] loop = new Label [rank]; @@ -4880,13 +5243,12 @@ namespace Mono.CSharp { test [i] = ig.DefineLabel (); loop [i] = ig.DefineLabel (); - lengths [i].EmitThis (ec); - ((ArrayAccess) access).EmitGetLength (ec, i); - lengths [i].EmitStore (ec); + lengths [i].EmitAssign (ec, length_exprs [i]); } + IntConstant zero = new IntConstant (0, loc); for (int i = 0; i < rank; i++) { - counter [i].Initialize (ec); + counter [i].EmitAssign (ec, zero); ig.Emit (OpCodes.Br, test [i]); ig.MarkLabel (loop [i]); @@ -4899,7 +5261,7 @@ namespace Mono.CSharp { ig.MarkLabel (ec.LoopBegin); for (int i = rank - 1; i >= 0; i--){ - counter [i].Increment (ec); + counter [i].EmitIncrement (ec); ig.MarkLabel (test [i]); counter [i].Emit (ec); @@ -4909,9 +5271,22 @@ namespace Mono.CSharp { ig.MarkLabel (ec.LoopEnd); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + copy.MutateHoistedGenericType (storey); + conv.MutateHoistedGenericType (storey); + variable.MutateHoistedGenericType (storey); + statement.MutateHoistedGenericType (storey); + + for (int i = 0; i < rank; i++) { + counter [i].MutateHoistedGenericType (storey); + lengths [i].MutateHoistedGenericType (storey); + } + } } - protected class CollectionForeach : ExceptionStatement + protected class CollectionForeach : Statement { Expression variable, expr; Statement statement; @@ -4919,13 +5294,13 @@ namespace Mono.CSharp { TemporaryVariable enumerator; Expression init; Statement loop; + Statement wrapper; MethodGroupExpr get_enumerator; PropertyExpr get_current; MethodInfo move_next; Expression var_type; Type enumerator_type; - bool is_disposable; bool enumerator_found; public CollectionForeach (Expression var_type, Expression var, @@ -4973,6 +5348,16 @@ namespace Mono.CSharp { // way I could do this without a goto // + if (TypeManager.bool_movenext_void == null) { + TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod ( + TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes); + } + + if (TypeManager.ienumerator_getcurrent == null) { + TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty ( + TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type); + } + #if GMCS_SOURCE // // Prefer a generic enumerator over a non-generic one. @@ -5011,9 +5396,6 @@ namespace Mono.CSharp { } enumerator_type = return_type; - is_disposable = !enumerator_type.IsSealed || - TypeManager.ImplementsInterface ( - enumerator_type, TypeManager.idisposable_type); return true; } @@ -5085,7 +5467,7 @@ namespace Mono.CSharp { return null; } - public void Error_Enumerator () + void Error_Enumerator () { if (enumerator_found) { return; @@ -5096,7 +5478,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (expr.Type)); } - public static bool IsOverride (MethodInfo m) + bool IsOverride (MethodInfo m) { m = (MethodInfo) TypeManager.DropGenericMethodArguments (m); @@ -5176,7 +5558,7 @@ namespace Mono.CSharp { get_current = tmp_get_cur; enumerator_type = tmp_enumerator_type; MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result }; - get_enumerator = new MethodGroupExpr (mi, loc); + get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc); if (t != expr.Type) { expr = Convert.ExplicitConversion ( @@ -5221,13 +5603,15 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { enumerator_type = TypeManager.ienumerator_type; - is_disposable = true; if (!ProbeCollectionType (ec, expr.Type)) { Error_Enumerator (); return false; } + bool is_disposable = !enumerator_type.IsSealed || + TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type); + VarExpr ve = var_type as VarExpr; if (ve != null) { // Infer implicitly typed local variable from foreach enumerable type @@ -5249,7 +5633,7 @@ namespace Mono.CSharp { Expression move_next_expr; { MemberInfo[] mi = new MemberInfo[] { move_next }; - MethodGroupExpr mg = new MethodGroupExpr (mi, loc); + MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc); mg.InstanceExpression = enumerator; move_next_expr = new Invocation (mg, null); @@ -5262,58 +5646,114 @@ namespace Mono.CSharp { loop = new While (move_next_expr, block, loc); - bool ok = true; + wrapper = is_disposable ? + (Statement) new DisposableWrapper (this) : + (Statement) new NonDisposableWrapper (this); + return wrapper.Resolve (ec); + } - FlowBranchingException branching = null; - if (is_disposable) - branching = ec.StartFlowBranching (this); + protected override void DoEmit (EmitContext ec) + { + wrapper.Emit (ec); + } - if (!loop.Resolve (ec)) - ok = false; + class NonDisposableWrapper : Statement { + CollectionForeach parent; - if (is_disposable) { - ResolveFinally (branching); - ec.EndFlowBranching (); - } else - emit_finally = true; + internal NonDisposableWrapper (CollectionForeach parent) + { + this.parent = parent; + } - return ok; + 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 (); + } } - protected override void DoEmit (EmitContext ec) - { - ILGenerator ig = ec.ig; + class DisposableWrapper : ExceptionStatement { + CollectionForeach parent; + + internal DisposableWrapper (CollectionForeach parent) + { + this.parent = parent; + } - enumerator.Store (ec, init); + public override bool Resolve (EmitContext ec) + { + bool ok = true; - // - // Protect the code in a try/finalize block, so that - // if the beast implement IDisposable, we get rid of it - // - if (is_disposable && emit_finally) - ig.BeginExceptionBlock (); - - loop.Emit (ec); + ec.StartFlowBranching (this); - // - // Now the finally block - // - if (is_disposable) { - DoEmitFinally (ec); - if (emit_finally) - ig.EndExceptionBlock (); + 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) + { + parent.EmitFinallyBody (ec); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + throw new NotSupportedException (); + } + } + + bool ResolveLoop (EmitContext ec) + { + return loop.Resolve (ec); } + void EmitLoopInit (EmitContext ec) + { + enumerator.EmitAssign (ec, init); + } + + void EmitLoopBody (EmitContext ec) + { + loop.Emit (ec); + } - public override void EmitFinally (EmitContext ec) + void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; if (enumerator_type.IsValueType) { MethodInfo mi = FetchMethodDispose (enumerator_type); if (mi != null) { - enumerator.EmitLoadAddress (ec); + enumerator.AddressOf (ec, AddressOp.Load); ig.Emit (OpCodes.Call, mi); } else { enumerator.Emit (ec); @@ -5327,16 +5767,22 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Brtrue_S, call_dispose); - ig.Emit (OpCodes.Pop); - Label end_finally = ig.DefineLabel (); - ig.Emit (OpCodes.Br, end_finally); + // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block + // (Partition III, Section 3.35) + ig.Emit (OpCodes.Endfinally); ig.MarkLabel (call_dispose); ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - ig.MarkLabel (end_finally); } } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + enumerator_type = storey.MutateType (enumerator_type); + init.MutateHoistedGenericType (storey); + loop.MutateHoistedGenericType (storey); + } } protected class CollectionForeachStatement : Statement @@ -5367,7 +5813,7 @@ namespace Mono.CSharp { if (conv == null) return false; - assign = new Assign (variable, conv, loc); + assign = new SimpleAssign (variable, conv, loc); if (assign.Resolve (ec) == null) return false; @@ -5382,6 +5828,12 @@ namespace Mono.CSharp { assign.EmitStatement (ec); statement.Emit (ec); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + assign.MutateHoistedGenericType (storey); + statement.MutateHoistedGenericType (storey); + } } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -5393,5 +5845,10 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); target.statement = statement.Clone (clonectx); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + statement.MutateHoistedGenericType (storey); + } } }