X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=5491e925f963f24cbf65a2f24be2ad8741c85cdd;hb=3c28dc153645532e837e42ecbd8979d05dc944a8;hp=0d0d0ff196b26270b56d7d6ca484b09783c18453;hpb=1c7e870076eb1e99761e09678fad43ed492c599b;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 0d0d0ff196b..5491e925f96 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -83,7 +83,7 @@ namespace Mono.CSharp { /// public virtual void Emit (EmitContext ec) { - ec.Mark (loc, true); + ec.Mark (loc); DoEmit (ec); } @@ -91,10 +91,7 @@ namespace Mono.CSharp { // This routine must be overrided in derived classes and make copies // of all the data that might be modified if resolved // - protected virtual void CloneTo (CloneContext clonectx, Statement target) - { - throw new InternalErrorException ("{0} does not implement Statement.CloneTo", this.GetType ()); - } + protected abstract void CloneTo (CloneContext clonectx, Statement target); public Statement Clone (CloneContext clonectx) { @@ -116,6 +113,7 @@ namespace Mono.CSharp { return Clone (clonectx); } + public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey); } // @@ -202,6 +200,10 @@ namespace Mono.CSharp { { } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } + protected override void CloneTo (CloneContext clonectx, Statement target) { // nothing needed. @@ -233,6 +235,14 @@ namespace Mono.CSharp { 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; @@ -354,7 +364,6 @@ namespace Mono.CSharp { public class Do : Statement { public Expression expr; public Statement EmbeddedStatement; - bool infinite; public Do (Statement statement, Expression bool_expr, Location l) { @@ -383,13 +392,10 @@ namespace Mono.CSharp { if (expr == null) ok = false; else if (expr is Constant){ - bool res = !((Constant) expr).IsDefaultValue; - - if (res) - infinite = true; + bool infinite = !((Constant) expr).IsDefaultValue; + if (infinite) + ec.CurrentBranching.CurrentUsageVector.Goto (); } - if (infinite) - ec.CurrentBranching.CurrentUsageVector.Goto (); ec.EndFlowBranching (); @@ -428,6 +434,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; @@ -527,7 +539,7 @@ namespace Mono.CSharp { Statement.Emit (ec); ig.MarkLabel (ec.LoopBegin); - ec.Mark (loc, true); + ec.Mark (loc); expr.EmitBranchable (ec, while_loop, true); @@ -550,6 +562,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 { @@ -630,7 +648,7 @@ namespace Mono.CSharp { return ok; } - + protected override void DoEmit (EmitContext ec) { if (InitStatement != null && InitStatement != EmptyStatement.Value) @@ -684,6 +702,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; @@ -719,6 +749,11 @@ namespace Mono.CSharp { expr.EmitStatement (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr.MutateHoistedGenericType (storey); + } + public override string ToString () { return "StatementExpression (" + expr + ")"; @@ -779,12 +814,12 @@ namespace Mono.CSharp { return false; } - AnonymousContainer am = ec.CurrentAnonymousMethod; - if ((am != null) && am.IsIterator && ec.InIterator) { + if (ec.CurrentBlock.Toplevel.IsIterator) { Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + "statement to return a value, or yield break to end the iteration"); } + AnonymousExpression am = ec.CurrentAnonymousMethod; if (am == null && ec.ReturnType == TypeManager.void_type) { MemberCore mc = ec.ResolveContext as MemberCore; Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void", @@ -837,6 +872,12 @@ 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; @@ -875,6 +916,11 @@ namespace Mono.CSharp { label.AddReference (); } + protected override void CloneTo (CloneContext clonectx, Statement target) + { + // Nothing to clone + } + protected override void DoEmit (EmitContext ec) { if (label == null) @@ -882,6 +928,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 { @@ -933,6 +983,11 @@ namespace Mono.CSharp { vectors = vector; } + protected override void CloneTo (CloneContext clonectx, Statement target) + { + // nothing to clone + } + public override bool Resolve (EmitContext ec) { // this flow-branching will be terminated when the surrounding block ends @@ -948,6 +1003,10 @@ namespace Mono.CSharp { ec.ig.MarkLabel (label); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } + public void AddReference () { referenced = true; @@ -965,6 +1024,11 @@ namespace Mono.CSharp { loc = l; } + protected override void CloneTo (CloneContext clonectx, Statement target) + { + // nothing to clone + } + public override bool Resolve (EmitContext ec) { ec.CurrentBranching.CurrentUsageVector.Goto (); @@ -984,6 +1048,10 @@ namespace Mono.CSharp { } ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } } /// @@ -1006,6 +1074,8 @@ namespace Mono.CSharp { return false; } + ec.CurrentBranching.CurrentUsageVector.Goto (); + expr = expr.Resolve (ec); if (expr == null) return false; @@ -1017,21 +1087,18 @@ namespace Mono.CSharp { } Type type = ec.Switch.SwitchType; - if (!Convert.ImplicitStandardConversionExists (c, type)) - Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " + - "convertible to type `{0}'", TypeManager.CSharpName (type)); - - bool fail = false; - object val = c.GetValue (); - if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type)) - val = TypeManager.ChangeType (val, type, out fail); - - if (fail) { - Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'", - c.GetSignatureForError (), TypeManager.CSharpName (type)); + Constant res = c.TryReduce (ec, type, c.Location); + if (res == null) { + c.Error_ValueCannotBeConverted (ec, loc, type, true); return false; } + if (!Convert.ImplicitStandardConversionExists (c, type)) + Report.Warning (469, 2, loc, + "The `goto case' value is not implicitly convertible to type `{0}'", + TypeManager.CSharpName (type)); + + object val = res.GetValue (); if (val == null) val = SwitchLabel.NullStringCase; @@ -1043,7 +1110,6 @@ namespace Mono.CSharp { return false; } - ec.CurrentBranching.CurrentUsageVector.Goto (); return true; } @@ -1052,12 +1118,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); } } @@ -1072,28 +1142,22 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - ec.CurrentBranching.CurrentUsageVector.Goto (); - - if (expr == null) + if (expr == null) { + ec.CurrentBranching.CurrentUsageVector.Goto (); return ec.CurrentBranching.CheckRethrow (loc); + } - expr = expr.Resolve (ec); - if (expr == null) - return false; - - ExprClass eclass = expr.eclass; + expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue); + ec.CurrentBranching.CurrentUsageVector.Goto (); - 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); + if (expr == null) return false; - } Type t = expr.Type; if ((t != TypeManager.exception_type) && !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && - !(expr is NullLiteral)) { + t != TypeManager.null_type) { Error (155, "The type caught or thrown must be derived from System.Exception"); return false; } @@ -1111,6 +1175,12 @@ 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; @@ -1141,6 +1211,10 @@ 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) { @@ -1170,33 +1244,21 @@ namespace Mono.CSharp { ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + } + protected override void CloneTo (CloneContext clonectx, Statement t) { // nothing needed. } } - public abstract class Variable + public interface ILocalVariable { - public abstract Type Type { - get; - } - - public abstract bool HasInstance { - get; - } - - public abstract bool NeedsTemporary { - get; - } - - public abstract void EmitInstance (EmitContext ec); - - public abstract void Emit (EmitContext ec); - - public abstract void EmitAssign (EmitContext ec); - - public abstract void EmitAddressOf (EmitContext ec); + void Emit (EmitContext ec); + void EmitAssign (EmitContext ec); + void EmitAddressOf (EmitContext ec); } public interface IKnownVariable { @@ -1207,8 +1269,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 FullNamedExpression Type; public Type VariableType; public readonly string Name; @@ -1216,11 +1278,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 { @@ -1228,7 +1286,6 @@ namespace Mono.CSharp { ReadOnly = 2, Pinned = 4, IsThis = 8, - Captured = 16, AddressTaken = 32, CompilerGenerated = 64, IsConstant = 128 @@ -1243,8 +1300,8 @@ namespace Mono.CSharp { Flags flags; ReadOnlyContext ro_context; LocalBuilder builder; - - public LocalInfo (Expression type, string name, Block block, Location l) + + public LocalInfo (FullNamedExpression type, string name, Block block, Location l) { Type = type; Name = name; @@ -1261,11 +1318,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 @@ -1274,12 +1330,25 @@ namespace Mono.CSharp { builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType); else builder = ec.ig.DeclareLocal (VariableType); - - var = new LocalVariable (this, builder); } } - public void EmitSymbolInfo (EmitContext ec, string name) + 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) { if (builder != null) ec.DefineLocalVariable (Name, builder); @@ -1306,22 +1375,18 @@ 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; - if (VariableType == TypeManager.void_type) { - Expression.Error_VoidInvalidInTheContext (Location); - return false; - } - if (VariableType.IsAbstract && VariableType.IsSealed) { FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType); return false; @@ -1333,11 +1398,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; } @@ -1380,12 +1440,12 @@ namespace Mono.CSharp { throw new InternalErrorException ("Variable is not readonly"); switch (ro_context) { - case ReadOnlyContext.Fixed: - return "fixed variable"; - case ReadOnlyContext.Foreach: - return "foreach iteration variable"; - case ReadOnlyContext.Using: - return "using variable"; + case ReadOnlyContext.Fixed: + return "fixed variable"; + case ReadOnlyContext.Foreach: + return "foreach iteration variable"; + case ReadOnlyContext.Using: + return "using variable"; } throw new NotImplementedException (); } @@ -1412,57 +1472,13 @@ 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) { // // Variables in anonymous block are not resolved yet // if (VariableType == null) - return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); + return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location); // // Variables in method block are resolved @@ -1489,11 +1505,11 @@ namespace Mono.CSharp { /// public class Block : Statement { public Block Parent; - public readonly Location StartLocation; + public Location StartLocation; public Location EndLocation = Location.Null; public ExplicitBlock Explicit; - public ToplevelBlock Toplevel; + public ToplevelBlock Toplevel; // TODO: Use Explicit [Flags] public enum Flags : byte { @@ -1501,15 +1517,16 @@ namespace Mono.CSharp { BlockUsed = 2, VariablesInitialized = 4, HasRet = 8, - IsDestructor = 16, - Unsafe = 32, - IsIterator = 64 + Unsafe = 16, + IsIterator = 32, + HasCapturedVariable = 64, + HasCapturedThis = 128 } protected Flags flags; public bool Unchecked { get { return (flags & Flags.Unchecked) != 0; } - set { flags |= Flags.Unchecked; } + set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; } } public bool Unsafe { @@ -1534,7 +1551,7 @@ namespace Mono.CSharp { // // Labels. (label, block) pairs. // - HybridDictionary labels; + protected HybridDictionary labels; // // Keeps track of (name, type) pairs @@ -1555,9 +1572,7 @@ namespace Mono.CSharp { // Block switch_block; - // TODO: merge with scope_initializers - ExpressionStatement scope_init; - ArrayList scope_initializers; + protected ArrayList scope_initializers; ArrayList anonymous_children; @@ -1566,7 +1581,6 @@ namespace Mono.CSharp { int this_id; int assignable_slots; - protected ScopeInfo scope_info; bool unreachable_shown; bool unreachable; @@ -1582,6 +1596,20 @@ namespace Mono.CSharp { : this (parent, (Flags) 0, start, end) { } + // + // Useful when TopLevel block is downgraded to normal block + // + public Block (ToplevelBlock parent, ToplevelBlock source) + : this (parent, source.flags, source.StartLocation, source.EndLocation) + { + statements = source.statements; + children = source.children; + labels = source.labels; + variables = source.variables; + constants = source.constants; + switch_block = source.switch_block; + } + public Block (Block parent, Flags flags, Location start, Location end) { if (parent != null) { @@ -1779,6 +1807,12 @@ namespace Mono.CSharp { if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; + if (this is ToplevelBlock) { + Report.SymbolRelatedToPreviousError (kvi.Location, name); + e.Error_VariableIsUsedBeforeItIsDeclared (name); + return false; + } + // // Even though we detected the error when the name is used, we // treat it as if the variable declaration was in error. @@ -1788,31 +1822,45 @@ namespace Mono.CSharp { return false; } - public LocalInfo AddVariable (Expression type, string name, Location l) + protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l) { LocalInfo vi = GetLocalInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); - if (Explicit == vi.Block.Explicit) + if (Explicit == vi.Block.Explicit) { Error_AlreadyDeclared (l, name, null); - else - Error_AlreadyDeclared (l, name, "parent"); - return null; + } else { + Error_AlreadyDeclared (l, name, this is ToplevelBlock ? + "parent or current" : "parent"); + } + return false; } - ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name); - if (pi != null) { - Report.SymbolRelatedToPreviousError (pi.Location, name); - Error_AlreadyDeclared (loc, name, - pi.Block == Toplevel ? "method argument" : "parent or current"); - return null; + if (block != null) { + Expression e = block.GetParameterReference (name, Location.Null); + if (e != null) { + ParameterReference pr = e as ParameterReference; + if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess)) + Error_AlreadyDeclared (loc, name); + else + Error_AlreadyDeclared (loc, name, "parent or current"); + return false; + } } - + + return true; + } + + public LocalInfo AddVariable (Expression type, string name, Location l) + { + if (!CheckParentConflictName (Toplevel, name, l)) + return null; + if (Toplevel.GenericMethod != null) { foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) { if (tp.Name == name) { Report.SymbolRelatedToPreviousError (tp); - Error_AlreadyDeclaredTypeParameter (loc, name); + Error_AlreadyDeclaredTypeParameter (loc, name, "local variable"); return null; } } @@ -1825,7 +1873,7 @@ namespace Mono.CSharp { return null; } - vi = new LocalInfo (type, name, this, l); + LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l); AddVariable (vi); if ((flags & Flags.VariablesInitialized) != 0) @@ -1859,10 +1907,11 @@ namespace Mono.CSharp { "A local variable named `{0}' is already defined in this scope", name); } - protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name) + public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict) { - GenericMethod.Error_ParameterNameCollision (loc, name, "local variable"); - } + Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'", + name, conflict); + } public bool AddConstant (Expression type, string name, Expression value, Location l) { @@ -1899,13 +1948,15 @@ namespace Mono.CSharp { public LocalInfo GetLocalInfo (string name) { + LocalInfo ret; for (Block b = this; b != null; b = b.Parent) { if (b.variables != null) { - LocalInfo ret = b.variables [name] as LocalInfo; + ret = (LocalInfo) b.variables [name]; if (ret != null) return ret; } } + return null; } @@ -1931,7 +1982,7 @@ namespace Mono.CSharp { // It should be used by expressions which require to // register a statement during resolve process. // - public void AddScopeStatement (StatementExpression s) + public void AddScopeStatement (Statement s) { if (scope_initializers == null) scope_initializers = new ArrayList (); @@ -1958,35 +2009,15 @@ namespace Mono.CSharp { get { return (flags & Flags.HasRet) != 0; } } - public bool IsDestructor { - get { return (flags & Flags.IsDestructor) != 0; } - } - - public void SetDestructor () - { - flags |= Flags.IsDestructor; - } - public int AssignableSlots { get { - if ((flags & Flags.VariablesInitialized) == 0) - throw new Exception ("Variables have not been initialized yet"); +// TODO: Re-enable +// if ((flags & Flags.VariablesInitialized) == 0) +// throw new Exception ("Variables have not been initialized yet"); return assignable_slots; } } - 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; } } @@ -2049,10 +2080,10 @@ namespace Mono.CSharp { e = ce.ConvertImplicitly (variable_type); if (e == null) { - if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue) - Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name); + if (TypeManager.IsReferenceType (variable_type)) + Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name); else - ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false); + ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false); continue; } @@ -2094,13 +2125,6 @@ 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); @@ -2137,7 +2161,7 @@ namespace Mono.CSharp { } } - private void CheckPossibleMistakenEmptyStatement (Statement s) + static void CheckPossibleMistakenEmptyStatement (Statement s) { Statement body; @@ -2193,7 +2217,7 @@ namespace Mono.CSharp { // Check possible empty statement (CS0642) if (Report.WarningLevel >= 3 && ix + 1 < statement_count && - statements [ix + 1] is Block) + statements [ix + 1] is ExplicitBlock) CheckPossibleMistakenEmptyStatement (s); // @@ -2203,13 +2227,14 @@ namespace Mono.CSharp { if (s is EmptyStatement) continue; - if (s is Block) - ((Block) s).unreachable = true; - if (!unreachable_shown && !(s is LabeledStatement)) { Report.Warning (162, 2, s.loc, "Unreachable code detected"); unreachable_shown = true; } + + Block c_block = s as Block; + if (c_block != null) + c_block.unreachable = c_block.unreachable_shown = true; } // @@ -2293,61 +2318,66 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { Block prev_block = ec.CurrentBlock; - ec.CurrentBlock = this; - bool emit_debug_info = SymbolWriter.HasSymbolWriter; - bool is_lexical_block = (this == Explicit) && (Parent != null) && - ((flags & Flags.IsIterator) == 0); + if (scope_initializers != null) + EmitScopeInitializers (ec); - bool omit_debug_info = ec.OmitDebuggingInfo; + ec.Mark (StartLocation); + DoEmit (ec); - if (emit_debug_info) { - if (is_lexical_block) - ec.BeginScope (); - } + if (SymbolWriter.HasSymbolWriter) + EmitSymbolInfo (ec); + + ec.CurrentBlock = prev_block; + } - if ((scope_init != null) || (scope_initializers != null)) - SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); + protected void EmitScopeInitializers (EmitContext ec) + { + SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); - if (scope_init != null) { - ec.OmitDebuggingInfo = true; - scope_init.EmitStatement (ec); - ec.OmitDebuggingInfo = omit_debug_info; - } - if (scope_initializers != null) { - ec.OmitDebuggingInfo = true; - foreach (StatementExpression s in scope_initializers) + using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) { + foreach (Statement s in scope_initializers) s.Emit (ec); - ec.OmitDebuggingInfo = omit_debug_info; } - if ((scope_init != null) || (scope_initializers != null)) - SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); + SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); + } - ec.Mark (StartLocation, true); - DoEmit (ec); + protected virtual void EmitSymbolInfo (EmitContext ec) + { + if (variables != null) { + foreach (LocalInfo vi in variables.Values) { + vi.EmitSymbolInfo (ec); + } + } + } - if (emit_debug_info) { - EmitSymbolInfo (ec); + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + MutateVariables (storey); - if (is_lexical_block) - ec.EndScope (); + if (scope_initializers != null) { + foreach (Statement s in scope_initializers) + s.MutateHoistedGenericType (storey); } - ec.CurrentBlock = prev_block; + foreach (Statement s in statements) + s.MutateHoistedGenericType (storey); } - protected virtual void EmitSymbolInfo (EmitContext ec) + void MutateVariables (AnonymousMethodStorey storey) { if (variables != null) { - foreach (DictionaryEntry de in variables) { - string name = (string) de.Key; - LocalInfo vi = (LocalInfo) de.Value; - - vi.EmitSymbolInfo (ec, name); + 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 () @@ -2394,6 +2424,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) { @@ -2405,12 +2438,6 @@ namespace Mono.CSharp { this.Explicit = this; } - public bool IsIterator { - get { return (flags & Flags.IsIterator) != 0; } - } - - HybridDictionary known_variables; - // // Marks a variable with name @name as being used in this or a child block. // If a variable name has been used in a child block, it's illegal to @@ -2427,30 +2454,149 @@ namespace Mono.CSharp { Parent.Explicit.AddKnownVariable (name, info); } - internal IKnownVariable GetKnownVariable (string name) - { - return known_variables == null ? null : (IKnownVariable) known_variables [name]; + public AnonymousMethodStorey AnonymousMethodStorey { + get { return am_storey; } } - protected override void CloneTo (CloneContext clonectx, Statement t) + // + // Creates anonymous method storey in current block + // + public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec) { - ExplicitBlock target = (ExplicitBlock) t; - target.known_variables = null; - base.CloneTo (clonectx, t); - } - } + // + // When referencing a variable in iterator storey from children anonymous method + // + if (Toplevel.am_storey is IteratorStorey) { + return Toplevel.am_storey; + } - public class ToplevelParameterInfo : IKnownVariable { - public readonly ToplevelBlock Block; - public readonly int Index; - public VariableInfo VariableInfo; + // + // An iterator has only 1 storey block + // + if (ec.CurrentIterator != null) + return ec.CurrentIterator.Storey; - Block IKnownVariable.Block { - get { return Block; } - } - public Parameter Parameter { + if (am_storey == null) { + MemberBase mc = ec.ResolveContext as MemberBase; + GenericMethod gm = mc == null ? null : mc.GenericMethod; + + // + // Creates anonymous method storey for this block + // + am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey"); + } + + return am_storey; + } + + public override void Emit (EmitContext ec) + { + if (am_storey != null) + am_storey.EmitStoreyInstantiation (ec); + + bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey); + if (emit_debug_info) + ec.BeginScope (); + + base.Emit (ec); + + if (emit_debug_info) + ec.EndScope (); + } + + public override void EmitMeta (EmitContext ec) + { + // + // Creates anonymous method storey + // + if (am_storey != null) { + if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) { + // + // Creates parent storey reference when hoisted this is accessible + // + if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) { + ExplicitBlock parent = Toplevel.Parent.Explicit; + + // + // Hoisted this exists in top-level parent storey only + // + while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey) + parent = parent.Parent.Explicit; + + am_storey.AddParentStoreyReference (parent.am_storey); + } + + am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey); + } + + am_storey.DefineType (); + am_storey.ResolveType (); + am_storey.Define (); + am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey); + + ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock; + if (ref_blocks != null) { + foreach (ExplicitBlock ref_block in ref_blocks) { + for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) { + if (b.am_storey != null) { + b.am_storey.AddParentStoreyReference (am_storey); + + // Stop propagation inside same top block + if (b.Toplevel == Toplevel) + break; + + b = b.Toplevel; + } + b.HasCapturedVariable = true; + } + } + } + } + + base.EmitMeta (ec); + } + + internal IKnownVariable GetKnownVariable (string name) + { + return known_variables == null ? null : (IKnownVariable) known_variables [name]; + } + + public bool HasCapturedThis + { + set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; } + get { return (flags & Flags.HasCapturedThis) != 0; } + } + + public bool HasCapturedVariable + { + set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; } + get { return (flags & Flags.HasCapturedVariable) != 0; } + } + + protected override void CloneTo (CloneContext clonectx, Statement t) + { + ExplicitBlock target = (ExplicitBlock) t; + target.known_variables = null; + base.CloneTo (clonectx, t); + } + } + + public class ToplevelParameterInfo : IKnownVariable { + public readonly ToplevelBlock Block; + public readonly int Index; + public VariableInfo VariableInfo; + + Block IKnownVariable.Block { + get { return Block; } + } + public Parameter Parameter { get { return Block.Parameters [Index]; } } + + public Type ParameterType { + get { return Block.Parameters.Types [Index]; } + } + public Location Location { get { return Parameter.Location; } } @@ -2470,44 +2616,72 @@ namespace Mono.CSharp { // In particular, this was introduced when the support for Anonymous // Methods was implemented. // - public class ToplevelBlock : ExplicitBlock { + public class ToplevelBlock : ExplicitBlock + { + // + // Block is converted to an expression + // + sealed class BlockScopeExpression : Expression + { + Expression child; + readonly ToplevelBlock block; + + public BlockScopeExpression (Expression child, ToplevelBlock block) + { + this.child = child; + this.block = block; + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException (); + } + + public override Expression DoResolve (EmitContext ec) + { + if (child == null) + return null; + + block.ResolveMeta (ec, ParametersCompiled.EmptyReadOnlyParameters); + child = child.Resolve (ec); + if (child == null) + return null; + + eclass = child.eclass; + type = child.Type; + return this; + } + + public override void Emit (EmitContext ec) + { + block.EmitMeta (ec); + block.EmitScopeInitializers (ec); + child.Emit (ec); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); + child.MutateHoistedGenericType (storey); + block.MutateHoistedGenericType (storey); + } + } + GenericMethod generic; FlowBranchingToplevel top_level_branching; - AnonymousContainer anonymous_container; - RootScopeInfo root_scope; - Parameters parameters; + protected ParametersCompiled parameters; ToplevelParameterInfo[] parameter_info; + LocalInfo this_variable; + + public HoistedVariable HoistedThisVariable; // // The parameters for the block. // - public Parameters Parameters { + public ParametersCompiled Parameters { 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; } } @@ -2516,49 +2690,45 @@ 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) : + public ToplevelBlock (Block parent, ParametersCompiled parameters, Location start) : this (parent, (Flags) 0, parameters, start) { } - public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) : + public ToplevelBlock (Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) : this (parent, parameters, start) { this.generic = generic; } - public ToplevelBlock (Parameters parameters, Location start) : + public ToplevelBlock (ParametersCompiled parameters, Location start) : this (null, (Flags) 0, parameters, start) { } - public ToplevelBlock (Flags flags, Parameters parameters, Location start) : + ToplevelBlock (Flags flags, ParametersCompiled parameters, Location start) : this (null, flags, parameters, start) { } // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child. // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'. - public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) : + public ToplevelBlock (Block parent, Flags flags, ParametersCompiled parameters, Location start) : base (null, flags, start, Location.Null) { this.Toplevel = this; - this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + this.parameters = parameters; this.Parent = parent; if (parent != null) parent.AddAnonymousChild (this); - if (this.parameters.Count != 0) + if (!this.parameters.IsEmpty) ProcessParameters (); } - public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + public ToplevelBlock (Location loc) + : this (null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc) { } @@ -2590,15 +2760,11 @@ namespace Mono.CSharp { return true; } - public virtual Expression GetTransparentIdentifier (string name) - { - return null; - } - void ProcessParameters () { int n = parameters.Count; parameter_info = new ToplevelParameterInfo [n]; + ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel; for (int i = 0; i < n; ++i) { parameter_info [i] = new ToplevelParameterInfo (this, i); @@ -2607,21 +2773,8 @@ namespace Mono.CSharp { continue; string name = p.Name; - LocalInfo vi = GetLocalInfo (name); - if (vi != null) { - Report.SymbolRelatedToPreviousError (vi.Location, name); - Error_AlreadyDeclared (loc, name, "parent or current"); - continue; - } - - ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name); - if (pi != null) { - Report.SymbolRelatedToPreviousError (pi.Location, name); - Error_AlreadyDeclared (loc, name, "parent or current"); - continue; - } - - AddKnownVariable (name, parameter_info [i]); + if (CheckParentConflictName (top_parent, name, loc)) + AddKnownVariable (name, parameter_info [i]); } // mark this block as "used" so that we create local declarations in a sub-block @@ -2641,46 +2794,36 @@ 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 (statements.Count == 1) { + Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec); + if (scope_initializers != null) + expr = new BlockScopeExpression (expr, this); - if (scope_info != null) - throw new InternalErrorException (); - - scope_info = root_scope; - return root_scope; - } + return expr; + } - public override Expression CreateExpressionTree (EmitContext ec) - { - return ((Statement) statements [0]).CreateExpressionTree (ec); + return base.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); + IsIterator = true; - if (Parent != null || root_scope != null) - throw new InternalErrorException (); + // Creates block with original statements + AddStatement (new IteratorStatement (iterator, new Block (this, source))); - scope_info = root_scope = root; - } + source.statements = new ArrayList (1); + source.AddStatement (new Return (iterator, iterator.Location)); + source.IsIterator = false; - 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 { @@ -2688,44 +2831,26 @@ namespace Mono.CSharp { } // - // 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 + // Returns a parameter reference expression for the given name, + // or null if there is no such parameter // - public ParameterReference GetParameterReference (string name, Location loc) - { - ToplevelParameterInfo p = GetParameterInfo (name); - return p == null ? null : new ParameterReference (this, p, loc); - } - - public ToplevelParameterInfo GetParameterInfo (string name) + public Expression GetParameterReference (string name, Location loc) { - int idx; for (ToplevelBlock t = this; t != null; t = t.Container) { - Parameter par = t.Parameters.GetParameterByName (name, out idx); - if (par != null) - return t.parameter_info [idx]; + Expression expr = t.GetParameterReferenceExpression (name, loc); + if (expr != null) + return expr; } + return null; } - LocalInfo this_variable = null; + protected virtual Expression GetParameterReferenceExpression (string name, Location loc) + { + int idx = parameters.GetParameterIndexByName (name); + return idx < 0 ? + null : new ParameterReference (parameter_info [idx], loc); + } // // Returns the "this" instance variable of this block. @@ -2755,12 +2880,17 @@ namespace Mono.CSharp { return this_variable; } + public bool IsIterator { + get { return (flags & Flags.IsIterator) != 0; } + set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; } + } + public bool IsThisAssigned (EmitContext ec) { return this_variable == null || this_variable.IsThisAssigned (ec); } - public bool ResolveMeta (EmitContext ec, Parameters ip) + public bool ResolveMeta (EmitContext ec, ParametersCompiled ip) { int errors = Report.Errors; int orig_count = parameters.Count; @@ -2778,7 +2908,7 @@ namespace Mono.CSharp { int offset = Parent == null ? 0 : Parent.AssignableSlots; for (int i = 0; i < orig_count; ++i) { - Parameter.Modifier mod = parameters.ParameterModifier (i); + Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags; if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT) continue; @@ -2821,63 +2951,28 @@ namespace Mono.CSharp { public override void EmitMeta (EmitContext ec) { + parameters.ResolveVariable (); + // Avoid declaring an IL variable for this_variable since it is not accessed // from the generated IL if (this_variable != null) Variables.Remove ("this"); base.EmitMeta (ec); - parameters.ResolveVariable (this); } protected override void EmitSymbolInfo (EmitContext ec) { - if ((AnonymousContainer != null) && (AnonymousContainer.Scope != null)) - SymbolWriter.DefineScopeVariable (AnonymousContainer.Scope.ID); + AnonymousExpression ae = ec.CurrentAnonymousMethod; + if ((ae != null) && (ae.Storey != null)) + SymbolWriter.DefineScopeVariable (ae.Storey.ID); base.EmitSymbolInfo (ec); } - public void MakeIterator (Iterator iterator) - { - flags |= Flags.IsIterator; - - Block block = new ExplicitBlock (this, flags, 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) - { - ec.StartFlowBranching (iterator); - bool ok = block.Resolve (ec); - ec.EndFlowBranching (); - return ok; - } - - protected override void DoEmit (EmitContext ec) - { - iterator.EmitMoveNext (ec, block); - } - } - - 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); } } @@ -2908,6 +3003,10 @@ namespace Mono.CSharp { } } + public Location Location { + get { return loc; } + } + public object Converted { get { return converted; @@ -2959,7 +3058,7 @@ namespace Mono.CSharp { return true; } - c = c.ImplicitConversionRequired (required_type, loc); + c = c.ImplicitConversionRequired (ec, required_type, loc); if (c == null) return false; @@ -2974,8 +3073,6 @@ namespace Mono.CSharp { label = "default"; else if (converted == NullStringCase) label = "null"; - else if (TypeManager.IsEnumType (switch_type)) - label = TypeManager.CSharpEnumValue (switch_type, converted); else label = converted.ToString (); @@ -3032,23 +3129,22 @@ namespace Mono.CSharp { Label null_target; Expression new_expr; bool is_constant; + bool has_null_case; SwitchSection constant_section; SwitchSection default_section; -#if GMCS_SOURCE + ExpressionStatement string_dictionary; + FieldExpr switch_cache_field; + static int unique_counter; + // - // Nullable Types support for GMCS. + // Nullable Types support // Nullable.Unwrap unwrap; protected bool HaveUnwrap { get { return unwrap != null; } } -#else - protected bool HaveUnwrap { - get { return false; } - } -#endif // // The types allowed to be implicitly cast from @@ -3110,8 +3206,7 @@ namespace Mono.CSharp { TypeManager.int64_type, TypeManager.uint64_type, TypeManager.char_type, - TypeManager.string_type, - TypeManager.bool_type + TypeManager.string_type }; } @@ -3137,10 +3232,7 @@ namespace Mono.CSharp { continue; if (converted != null){ - Report.ExtraInformation ( - loc, - String.Format ("reason: more than one conversion to an integral type exist for type {0}", - TypeManager.CSharpName (expr.Type))); + Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous "); return null; } @@ -3180,6 +3272,9 @@ namespace Mono.CSharp { } object key = sl.Converted; + if (key == SwitchLabel.NullStringCase) + has_null_case = true; + try { Elements.Add (key, sl); } catch (ArgumentException) { @@ -3280,7 +3375,7 @@ namespace Mono.CSharp { /// /// /// - void TableSwitchEmit (EmitContext ec, LocalBuilder val) + void TableSwitchEmit (EmitContext ec, Expression val) { int element_count = Elements.Count; object [] element_keys = new object [element_count]; @@ -3288,7 +3383,7 @@ namespace Mono.CSharp { Array.Sort (element_keys); // initialize the block list with one element per key - ArrayList key_blocks = new ArrayList (); + ArrayList key_blocks = new ArrayList (element_count); foreach (object key in element_keys) key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key))); @@ -3345,7 +3440,7 @@ namespace Mono.CSharp { // okay now we can start... ILGenerator ig = ec.ig; Label lbl_end = ig.DefineLabel (); // at the end ;-) - Label lbl_default = ig.DefineLabel (); + Label lbl_default = default_target; Type type_keys = null; if (element_keys.Length > 0) @@ -3361,15 +3456,18 @@ namespace Mono.CSharp { for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock) { KeyBlock kb = ((KeyBlock) key_blocks [iBlock]); - lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel (); + lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel (); if (kb.Length <= 2) { - foreach (object key in kb.element_keys) - { - ig.Emit (OpCodes.Ldloc, val); - EmitObjectInteger (ig, key); + foreach (object key in kb.element_keys) { SwitchLabel sl = (SwitchLabel) Elements [key]; - ig.Emit (OpCodes.Beq, sl.GetILLabel (ec)); + if (key is int && (int) key == 0) { + val.EmitBranchable (ec, sl.GetILLabel (ec), false); + } else { + val.Emit (ec); + EmitObjectInteger (ig, key); + ig.Emit (OpCodes.Beq, sl.GetILLabel (ec)); + } } } else @@ -3382,15 +3480,15 @@ namespace Mono.CSharp { // TODO: optimize constant/I4 cases // check block range (could be > 2^31) - ig.Emit (OpCodes.Ldloc, val); + val.Emit (ec); EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); ig.Emit (OpCodes.Blt, lbl_default); - ig.Emit (OpCodes.Ldloc, val); + val.Emit (ec); EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys)); ig.Emit (OpCodes.Bgt, lbl_default); // normalize range - ig.Emit (OpCodes.Ldloc, val); + val.Emit (ec); if (kb.first != 0) { EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys)); @@ -3401,7 +3499,7 @@ namespace Mono.CSharp { else { // normalize range - ig.Emit (OpCodes.Ldloc, val); + val.Emit (ec); int first = (int) kb.first; if (first > 0) { @@ -3445,145 +3543,37 @@ 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, lbl_default); + if (element_keys.Length > 0) + ig.Emit (OpCodes.Br, lbl_default); // now emit the code for the sections bool found_default = false; - bool found_null = false; - foreach (SwitchSection ss in Sections) - { - foreach (SwitchLabel sl in ss.Labels) - if (sl.Converted == SwitchLabel.NullStringCase) - found_null = true; - } - foreach (SwitchSection ss in Sections) - { - foreach (SwitchLabel sl in ss.Labels) - { - ig.MarkLabel (sl.GetILLabel (ec)); - ig.MarkLabel (sl.GetILLabelCode (ec)); - if (sl.Converted == SwitchLabel.NullStringCase) + foreach (SwitchSection ss in Sections) { + foreach (SwitchLabel sl in ss.Labels) { + if (sl.Converted == SwitchLabel.NullStringCase) { ig.MarkLabel (null_target); - else if (sl.Label == null) { + } else if (sl.Label == null) { ig.MarkLabel (lbl_default); found_default = true; - if (!found_null) + if (!has_null_case) ig.MarkLabel (null_target); } + ig.MarkLabel (sl.GetILLabel (ec)); + ig.MarkLabel (sl.GetILLabelCode (ec)); } ss.Block.Emit (ec); } if (!found_default) { ig.MarkLabel (lbl_default); - if (HaveUnwrap && !found_null) { + if (!has_null_case) { ig.MarkLabel (null_target); } } ig.MarkLabel (lbl_end); } - // - // This simple emit switch works, but does not take advantage of the - // `switch' opcode. - // TODO: remove non-string logic from here - // TODO: binary search strings? - // - void SimpleSwitchEmit (EmitContext ec, LocalBuilder val) - { - ILGenerator ig = ec.ig; - Label end_of_switch = ig.DefineLabel (); - Label next_test = ig.DefineLabel (); - bool first_test = true; - bool pending_goto_end = false; - bool null_marked = false; - bool null_found; - int section_count = Sections.Count; - - // TODO: implement switch optimization for string by using Hashtable - //if (SwitchType == TypeManager.string_type && section_count > 7) - // Console.WriteLine ("Switch optimization possible " + loc); - - ig.Emit (OpCodes.Ldloc, val); - - if (Elements.Contains (SwitchLabel.NullStringCase)){ - ig.Emit (OpCodes.Brfalse, null_target); - } else - ig.Emit (OpCodes.Brfalse, default_target); - - ig.Emit (OpCodes.Ldloc, val); - ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string); - ig.Emit (OpCodes.Stloc, val); - - for (int section = 0; section < section_count; section++){ - SwitchSection ss = (SwitchSection) Sections [section]; - - if (ss == default_section) - continue; - - Label sec_begin = ig.DefineLabel (); - - ig.Emit (OpCodes.Nop); - - if (pending_goto_end) - ig.Emit (OpCodes.Br, end_of_switch); - - int label_count = ss.Labels.Count; - null_found = false; - for (int label = 0; label < label_count; label++){ - SwitchLabel sl = (SwitchLabel) ss.Labels [label]; - ig.MarkLabel (sl.GetILLabel (ec)); - - if (!first_test){ - ig.MarkLabel (next_test); - next_test = ig.DefineLabel (); - } - // - // If we are the default target - // - if (sl.Label != null){ - object lit = sl.Converted; - - if (lit == SwitchLabel.NullStringCase){ - null_found = true; - if (label + 1 == label_count) - ig.Emit (OpCodes.Br, next_test); - continue; - } - - ig.Emit (OpCodes.Ldloc, val); - ig.Emit (OpCodes.Ldstr, (string)lit); - if (label_count == 1) - ig.Emit (OpCodes.Bne_Un, next_test); - else { - if (label+1 == label_count) - ig.Emit (OpCodes.Bne_Un, next_test); - else - ig.Emit (OpCodes.Beq, sec_begin); - } - } - } - if (null_found) { - ig.MarkLabel (null_target); - null_marked = true; - } - ig.MarkLabel (sec_begin); - foreach (SwitchLabel sl in ss.Labels) - ig.MarkLabel (sl.GetILLabelCode (ec)); - - ss.Block.Emit (ec); - pending_goto_end = !ss.Block.HasRet; - first_test = false; - } - ig.MarkLabel (next_test); - ig.MarkLabel (default_target); - if (!null_marked) - ig.MarkLabel (null_target); - if (default_section != null) - default_section.Block.Emit (ec); - ig.MarkLabel (end_of_switch); - } SwitchSection FindSection (SwitchLabel label) { @@ -3597,6 +3587,18 @@ namespace Mono.CSharp { return null; } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + foreach (SwitchSection ss in Sections) + ss.Block.MutateHoistedGenericType (storey); + } + + public static void Reset () + { + unique_counter = 0; + allowed_types = null; + } + public override bool Resolve (EmitContext ec) { Expr = Expr.Resolve (ec); @@ -3605,15 +3607,13 @@ namespace Mono.CSharp { new_expr = SwitchGoverningType (ec, Expr); -#if GMCS_SOURCE if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) { - unwrap = Nullable.Unwrap.Create (Expr, ec); + unwrap = Nullable.Unwrap.Create (Expr, false); if (unwrap == null) return false; new_expr = SwitchGoverningType (ec, unwrap); } -#endif if (new_expr == null){ Report.Error (151, loc, "A value of an integral type or string expected for switch"); @@ -3683,35 +3683,152 @@ namespace Mono.CSharp { Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching); - if (TypeManager.string_isinterned_string == null) { - TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type, - "IsInterned", loc, TypeManager.string_type); + if (!ok) + return false; + + if (SwitchType == TypeManager.string_type && !is_constant) { + // TODO: Optimize single case, and single+default case + ResolveStringSwitchMap (ec); } - return ok; + return true; } - - protected override void DoEmit (EmitContext ec) + + void ResolveStringSwitchMap (EmitContext ec) { - ILGenerator ig = ec.ig; + FullNamedExpression string_dictionary_type; + if (TypeManager.generic_ienumerable_type != null) { + MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); - default_target = ig.DefineLabel (); - null_target = ig.DefineLabel (); + string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", + new TypeArguments ( + new TypeExpression (TypeManager.string_type, loc), + new TypeExpression (TypeManager.int32_type, loc)), loc); + } else { + MemberAccess system_collections_generic = new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); - // Store variable for comparission purposes - LocalBuilder value; - if (HaveUnwrap) { - value = ig.DeclareLocal (SwitchType); -#if GMCS_SOURCE - unwrap.EmitCheck (ec); - ig.Emit (OpCodes.Brfalse, null_target); + string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); + } + + Field field = new Field (ec.TypeContainer, string_dictionary_type, + Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, + new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); + if (!field.Define ()) + return; + ec.TypeContainer.PartialContainer.AddField (field); + + ArrayList init = new ArrayList (); + int counter = 0; + Elements.Clear (); + string value = null; + foreach (SwitchSection section in Sections) { + int last_count = init.Count; + foreach (SwitchLabel sl in section.Labels) { + if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) + continue; + + value = (string) sl.Converted; + ArrayList init_args = new ArrayList (2); + init_args.Add (new StringLiteral (value, sl.Location)); + init_args.Add (new IntConstant (counter, loc)); + init.Add (new CollectionElementInitializer (init_args, loc)); + } + + // + // Don't add empty sections + // + if (last_count == init.Count) + continue; + + Elements.Add (counter, section.Labels [0]); + ++counter; + } + + ArrayList args = new ArrayList (1); + args.Add (new Argument (new IntConstant (init.Count, loc))); + Expression initializer = new NewInitialize (string_dictionary_type, args, + new CollectionOrObjectInitializers (init, loc), loc); + + switch_cache_field = new FieldExpr (field.FieldBuilder, loc); + string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec)); + } + + void DoEmitStringSwitch (LocalTemporary value, EmitContext ec) + { + ILGenerator ig = ec.ig; + Label l_initialized = ig.DefineLabel (); + + // + // Skip initialization when value is null + // + value.EmitBranchable (ec, null_target, false); + + // + // Check if string dictionary is initialized and initialize + // + switch_cache_field.EmitBranchable (ec, l_initialized, true); + string_dictionary.EmitStatement (ec); + ig.MarkLabel (l_initialized); + + LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type); + + if (TypeManager.generic_ienumerable_type != null) { + ArrayList get_value_args = new ArrayList (2); + get_value_args.Add (new Argument (value)); + get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); + Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec); + if (get_item == null) + return; + + // + // A value was not found, go to default case + // + get_item.EmitBranchable (ec, default_target, false); + } else { + ArrayList get_value_args = new ArrayList (1); + get_value_args.Add (value); + + Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec); + if (get_item == null) + return; + + LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type); + get_item_object.EmitAssign (ec, get_item, true, false); + ec.ig.Emit (OpCodes.Brfalse, default_target); + + ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, + new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec); + + get_item_int.EmitStatement (ec); + get_item_object.Release (ec); + } + + TableSwitchEmit (ec, string_switch_variable); + string_switch_variable.Release (ec); + } + + protected override void DoEmit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + default_target = ig.DefineLabel (); + null_target = ig.DefineLabel (); + + // Store variable for comparission purposes + // TODO: Don't duplicate non-captured VariableReference + LocalTemporary value; + if (HaveUnwrap) { + value = new LocalTemporary (SwitchType); + unwrap.EmitCheck (ec); + ig.Emit (OpCodes.Brfalse, null_target); new_expr.Emit (ec); - ig.Emit (OpCodes.Stloc, value); -#endif + value.Store (ec); } else if (!is_constant) { - value = ig.DeclareLocal (SwitchType); + value = new LocalTemporary (SwitchType); new_expr.Emit (ec); - ig.Emit (OpCodes.Stloc, value); + value.Store (ec); } else value = null; @@ -3728,10 +3845,14 @@ namespace Mono.CSharp { if (is_constant) { if (constant_section != null) constant_section.Block.Emit (ec); - } else if (SwitchType == TypeManager.string_type) - SimpleSwitchEmit (ec, value); - else + } else if (string_dictionary != null) { + DoEmitStringSwitch (value, ec); + } else { TableSwitchEmit (ec, value); + } + + if (value != null) + value.Release (ec); // Restore context state. ig.MarkLabel (ec.LoopEnd); @@ -3849,7 +3970,7 @@ namespace Mono.CSharp { ArrayList resume_points; int first_resume_pc; - public void AddResumePoint (ResumableStatement stmt, Location loc, int pc) + public void AddResumePoint (ResumableStatement stmt, int pc) { if (resume_points == null) { resume_points = new ArrayList (); @@ -3954,7 +4075,7 @@ namespace Mono.CSharp { if (expr == null) return false; - if (expr.Type.IsValueType){ + if (!TypeManager.IsReferenceType (expr.Type)){ Report.Error (185, loc, "`{0}' is not a reference type as required by the lock statement", TypeManager.CSharpName (expr.Type)); @@ -3991,7 +4112,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - temp.Store (ec, expr); + temp.EmitAssign (ec, expr); temp.Emit (ec); ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object); } @@ -4006,6 +4127,13 @@ namespace Mono.CSharp { 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) { @@ -4037,6 +4165,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; @@ -4066,6 +4199,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; @@ -4094,6 +4232,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; @@ -4139,92 +4283,62 @@ 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; + class StringEmitter : Emitter + { + LocalInfo pinned_string; public StringEmitter (Expression expr, LocalInfo li, Location loc): base (expr, li) { - this.loc = loc; + pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc); + pinned_string.Pinned = true; } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type); - + pinned_string.Resolve (ec); + pinned_string.ResolveVariable (ec); + converted.Emit (ec); - ig.Emit (OpCodes.Stloc, pinned_string); + pinned_string.EmitAssign (ec); - Expression sptr = new StringPtr (pinned_string, loc); - converted = Convert.ImplicitConversionRequired ( - ec, sptr, vi.VariableType, loc); - - if (converted == null) - return; + PropertyInfo p = TypeManager.int_get_offset_to_string_data; + if (p == null) { + // TODO: Move to resolve + p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty ( + TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type); - converted.Emit (ec); - vi.Variable.EmitAssign (ec); + if (p == null) + return; + } + + // TODO: Should use Binary::Add + pinned_string.Emit (ec); + ec.ig.Emit (OpCodes.Conv_I); + + PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location); + //pe.InstanceExpression = pinned_string; + pe.Resolve (ec).Emit (ec); + + ec.ig.Emit (OpCodes.Add); + vi.EmitAssign (ec); } public override void EmitExit (EmitContext ec) { ec.ig.Emit (OpCodes.Ldnull); - ec.ig.Emit (OpCodes.Stloc, pinned_string); + pinned_string.EmitAssign (ec); } } @@ -4287,43 +4401,6 @@ namespace Mono.CSharp { Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); return false; } - - // - // Case 1: & object. - // - if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){ - Expression child = ((Unary) e).Expr; - - if (child is ParameterReference || child is LocalVariableReference){ - Report.Error ( - 213, loc, - "No need to use fixed statement for parameters or " + - "local variable declarations (address is already " + - "fixed)"); - return false; - } - - ec.InFixedInitializer = true; - e = e.Resolve (ec); - ec.InFixedInitializer = false; - if (e == null) - return false; - - child = ((Unary) e).Expr; - - if (!TypeManager.VerifyUnManaged (child.Type, loc)) - return false; - - if (!Convert.ImplicitConversionExists (ec, e, expr_type)) { - e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false); - return false; - } - - data [i] = new ExpressionEmitter (e, vi); - i++; - - continue; - } ec.InFixedInitializer = true; e = e.Resolve (ec); @@ -4360,7 +4437,7 @@ namespace Mono.CSharp { 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, + new NullPointer (loc), converted); converted = converted.Resolve (ec); @@ -4381,24 +4458,26 @@ namespace Mono.CSharp { } // Case 4: fixed buffer - FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr; - if (fixed_buffer_ptr != null) { - data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi); + if (e is FixedBufferPtr) { + data [i++] = new ExpressionEmitter (e, vi); continue; } // - // For other cases, flag a `this is already fixed expression' + // Case 1: & object. // - if (e is LocalVariableReference || e is ParameterReference || - Convert.ImplicitConversionExists (ec, e, vi.VariableType)){ - - Report.Error (245, loc, "right hand expression is already fixed, no need to use fixed statement "); - return false; + Unary u = e as Unary; + if (u != null && u.Oper == Unary.Operator.AddressOf) { + IVariableReference vr = u.Expr as IVariableReference; + if (vr == null || !vr.IsFixed) { + data [i] = new ExpressionEmitter (e, vi); + } } - Report.Error (245, loc, "Fixed statement only allowed on strings, arrays or address-of expressions"); - return false; + if (data [i++] == null) + Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression"); + + e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc); } ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc); @@ -4428,6 +4507,12 @@ 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; @@ -4488,19 +4573,27 @@ 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"); + // TODO: Move to resolve + LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); + lvr.Resolve (ec); + +#if GMCS_SOURCE + // Only to make verifier happy + if (TypeManager.IsGenericParameter (lvr.Type)) + ig.Emit (OpCodes.Unbox_Any, lvr.Type); +#endif - if (vi.Variable.NeedsTemporary) { - LocalBuilder e = ig.DeclareLocal (vi.VariableType); - ig.Emit (OpCodes.Stloc, e); + 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); @@ -4536,6 +4629,15 @@ 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; @@ -4596,6 +4698,12 @@ namespace Mono.CSharp { fini.Emit (ec); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + stmt.MutateHoistedGenericType (storey); + fini.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { TryFinally target = (TryFinally) t; @@ -4661,7 +4769,9 @@ namespace Mono.CSharp { Type resolved_type = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) { - Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName); + Report.Error (160, c.loc, + "A previous catch clause already catches all exceptions of this or a super type `{0}'", + TypeManager.CSharpName (prev_catches [ii])); ok = false; } } @@ -4672,7 +4782,7 @@ namespace Mono.CSharp { if (General != null) { if (CodeGen.Assembly.WrapNonExceptionThrows) { foreach (Catch c in Specific){ - if (c.CatchType == TypeManager.exception_type) { + if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) { Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); } } @@ -4718,6 +4828,18 @@ namespace Mono.CSharp { ig.EndExceptionBlock (); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + Block.MutateHoistedGenericType (storey); + + if (General != null) + General.MutateHoistedGenericType (storey); + if (Specific != null) { + foreach (Catch c in Specific) + c.MutateHoistedGenericType (storey); + } + } + protected override void CloneTo (CloneContext clonectx, Statement t) { TryCatch target = (TryCatch) t; @@ -4733,6 +4855,7 @@ namespace Mono.CSharp { } } + // FIXME: Why is it almost exact copy of Using ?? public class UsingTemporary : ExceptionStatement { TemporaryVariable local_copy; public Statement Statement; @@ -4782,7 +4905,7 @@ namespace Mono.CSharp { protected override void EmitPreTryBody (EmitContext ec) { - local_copy.Store (ec, expr); + local_copy.EmitAssign (ec, expr); } protected override void EmitTryBody (EmitContext ec) @@ -4790,10 +4913,10 @@ namespace Mono.CSharp { Statement.Emit (ec); } - protected override void EmitFinallyBody (EmitContext ec) + protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; - if (!expr_type.IsValueType) { + if (!TypeManager.IsStruct (expr_type)) { Label skip = ig.DefineLabel (); local_copy.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); @@ -4832,6 +4955,13 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, mi); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + expr_type = storey.MutateType (expr_type); + local_copy.MutateHoistedGenericType (storey); + Statement.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { UsingTemporary target = (UsingTemporary) t; @@ -4850,7 +4980,6 @@ namespace Mono.CSharp { Expression var; Expression init; - Expression converted_var; ExpressionStatement assign; public Using (Expression var, Expression init, Statement stmt, Location l) @@ -4861,31 +4990,6 @@ namespace Mono.CSharp { loc = l; } - bool ResolveVariable (EmitContext ec) - { - ExpressionStatement a = new SimpleAssign (var, init, loc); - a = a.ResolveStatement (ec); - if (a == null) - return false; - - assign = a; - - if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) { - converted_var = var; - return true; - } - - Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location); - if (e == null) { - Error_IsNotConvertibleToIDisposable (var); - return false; - } - - converted_var = e; - - return true; - } - static public void Error_IsNotConvertibleToIDisposable (Expression expr) { Report.SymbolRelatedToPreviousError (expr.Type); @@ -4906,42 +5010,25 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { ILGenerator ig = ec.ig; + Label skip = ig.DefineLabel (); - if (!var.Type.IsValueType) { - Label skip = ig.DefineLabel (); + bool emit_null_check = !TypeManager.IsValueType (var.Type); + if (emit_null_check) { var.Emit (ec); ig.Emit (OpCodes.Brfalse, skip); - 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, var.Type, "Dispose", Mono.CSharp.Location.Null); - - 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; - - foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) { - if (TypeManager.GetParameterData (mk).Count == 0) { - mi = mk; - break; - } - } + } - if (mi == null) { - Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); - return; - } + Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, new ArrayList (0), loc); - IMemoryLocation mloc = (IMemoryLocation) var; + if (emit_null_check) + ig.MarkLabel (skip); + } - 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) @@ -4965,6 +5052,27 @@ namespace Mono.CSharp { return ok; } + bool ResolveVariable (EmitContext ec) + { + assign = new SimpleAssign (var, init, loc); + assign = assign.ResolveStatement (ec); + if (assign == null) + return false; + + if (assign.Type == TypeManager.idisposable_type || + TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) { + return true; + } + + Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location); + if (e == null) { + Error_IsNotConvertibleToIDisposable (var); + return false; + } + + throw new NotImplementedException ("covariance?"); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Using target = (Using) t; @@ -4979,153 +5087,80 @@ namespace Mono.CSharp { /// Implementation of the foreach C# statement /// public class Foreach : Statement { - Expression type; - Expression variable; - Expression expr; - Statement statement; - ArrayForeach array; - CollectionForeach collection; - - public Foreach (Expression type, LocalVariableReference var, Expression expr, - Statement stmt, Location l) - { - this.type = type; - this.variable = var; - this.expr = expr; - statement = stmt; - loc = l; - } - - public Statement Statement { - get { return statement; } - } - - public override bool Resolve (EmitContext ec) - { - expr = expr.Resolve (ec); - if (expr == null) - return false; - - if (expr.IsNull) { - Report.Error (186, loc, "Use of null is not valid in this context"); - return false; - } - - if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { - Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", - expr.ExprClassName); - 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); - } - - collection = new CollectionForeach (type, variable, expr, statement, loc); - return collection.Resolve (ec); - } - protected override void DoEmit (EmitContext ec) + sealed class ArrayForeach : Statement { - ILGenerator ig = ec.ig; - - Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd; - ec.LoopBegin = ig.DefineLabel (); - ec.LoopEnd = ig.DefineLabel (); + class ArrayCounter : TemporaryVariable + { + StatementExpression increment; - if (collection != null) - collection.Emit (ec); - else - array.Emit (ec); - - ec.LoopBegin = old_begin; - ec.LoopEnd = old_end; - } + public ArrayCounter (Location loc) + : base (TypeManager.int32_type, loc) + { + } - protected class ArrayCounter : TemporaryVariable - { - public ArrayCounter (Location loc) - : base (TypeManager.int32_type, loc) - { } + public void ResolveIncrement (EmitContext ec) + { + increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this)); + increment.Resolve (ec); + } - public void Initialize (EmitContext ec) - { - EmitThis (ec); - ec.ig.Emit (OpCodes.Ldc_I4_0); - EmitStore (ec); + public void EmitIncrement (EmitContext ec) + { + increment.Emit (ec); + } } - public void Increment (EmitContext ec) - { - EmitThis (ec); - Emit (ec); - ec.ig.Emit (OpCodes.Ldc_I4_1); - ec.ig.Emit (OpCodes.Add); - EmitStore (ec); - } - } + readonly Foreach for_each; + readonly Statement statement; - protected class ArrayForeach : Statement - { - Expression variable, expr, conv; - Statement statement; - Type array_type; - Expression var_type; + Expression conv; TemporaryVariable[] lengths; + Expression [] length_exprs; ArrayCounter[] counter; - int rank; TemporaryVariable copy; Expression access; - Expression[] length_exprs; - public ArrayForeach (Expression var_type, Expression var, - Expression expr, Statement stmt, Location l) + public ArrayForeach (Foreach @foreach, int rank) { - this.var_type = var_type; - this.variable = var; - this.expr = expr; - statement = stmt; - loc = l; + for_each = @foreach; + statement = for_each.statement; + loc = @foreach.loc; + + counter = new ArrayCounter [rank]; + length_exprs = new Expression [rank]; + + // + // Only use temporary length variables when dealing with + // multi-dimensional arrays + // + if (rank > 1) + lengths = new TemporaryVariable [rank]; } - public override bool Resolve (EmitContext ec) + protected override void CloneTo (CloneContext clonectx, Statement target) { - array_type = expr.Type; - rank = array_type.GetArrayRank (); + throw new NotImplementedException (); + } - copy = new TemporaryVariable (array_type, loc); + public override bool Resolve (EmitContext ec) + { + copy = new TemporaryVariable (for_each.expr.Type, loc); copy.Resolve (ec); - counter = new ArrayCounter [rank]; - lengths = new TemporaryVariable [rank]; - length_exprs = new Expression [rank]; - + int rank = length_exprs.Length; ArrayList list = new ArrayList (rank); for (int i = 0; i < rank; i++) { counter [i] = new ArrayCounter (loc); - counter [i].Resolve (ec); - - lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); - lengths [i].Resolve (ec); + counter [i].ResolveIncrement (ec); if (rank == 1) { length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec); } else { + lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); + lengths [i].Resolve (ec); + 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); @@ -5138,6 +5173,7 @@ namespace Mono.CSharp { if (access == null) return false; + Expression var_type = for_each.type; VarExpr ve = var_type as VarExpr; if (ve != null) { // Infer implicitly typed local variable from foreach array type @@ -5157,8 +5193,8 @@ namespace Mono.CSharp { ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); ec.CurrentBranching.CreateSibling (); - variable = variable.ResolveLValue (ec, conv, loc); - if (variable == null) + for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc); + if (for_each.variable == null) ok = false; ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); @@ -5178,8 +5214,9 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - copy.Store (ec, expr); + copy.EmitAssign (ec, for_each.expr); + int rank = length_exprs.Length; Label[] test = new Label [rank]; Label[] loop = new Label [rank]; @@ -5187,37 +5224,115 @@ namespace Mono.CSharp { test [i] = ig.DefineLabel (); loop [i] = ig.DefineLabel (); - lengths [i].Store (ec, length_exprs [i]); + if (lengths != null) + 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]); } - ((IAssignMethod) variable).EmitAssign (ec, conv, false, false); + ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false); statement.Emit (ec); 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); - lengths [i].Emit (ec); + + if (lengths != null) + lengths [i].Emit (ec); + else + length_exprs [i].Emit (ec); + ig.Emit (OpCodes.Blt, loop [i]); } ig.MarkLabel (ec.LoopEnd); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + for_each.expr.MutateHoistedGenericType (storey); + + copy.MutateHoistedGenericType (storey); + conv.MutateHoistedGenericType (storey); + statement.MutateHoistedGenericType (storey); + + for (int i = 0; i < counter.Length; i++) { + counter [i].MutateHoistedGenericType (storey); + if (lengths != null) + lengths [i].MutateHoistedGenericType (storey); + } + } } - protected class CollectionForeach : Statement + sealed class CollectionForeach : Statement { + class CollectionForeachStatement : Statement + { + Type type; + Expression variable, current, conv; + Statement statement; + Assign assign; + + public CollectionForeachStatement (Type type, Expression variable, + Expression current, Statement statement, + Location loc) + { + this.type = type; + this.variable = variable; + this.current = current; + this.statement = statement; + this.loc = loc; + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + throw new NotImplementedException (); + } + + public override bool Resolve (EmitContext ec) + { + current = current.Resolve (ec); + if (current == null) + return false; + + conv = Convert.ExplicitConversion (ec, current, type, loc); + if (conv == null) + return false; + + assign = new SimpleAssign (variable, conv, loc); + if (assign.Resolve (ec) == null) + return false; + + if (!statement.Resolve (ec)) + return false; + + return true; + } + + protected override void DoEmit (EmitContext ec) + { + assign.EmitStatement (ec); + statement.Emit (ec); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + assign.MutateHoistedGenericType (storey); + statement.MutateHoistedGenericType (storey); + } + } + Expression variable, expr; Statement statement; @@ -5243,27 +5358,22 @@ namespace Mono.CSharp { loc = l; } + protected override void CloneTo (CloneContext clonectx, Statement target) + { + throw new NotImplementedException (); + } + bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi) { Type return_type = mi.ReturnType; - if ((return_type == TypeManager.ienumerator_type) && (mi.DeclaringType == TypeManager.string_type)) - // - // Apply the same optimization as MS: skip the GetEnumerator - // returning an IEnumerator, and use the one returning a - // CharEnumerator instead. This allows us to avoid the - // try-finally block and the boxing. - // - return false; - // // Ok, we can access it, now make sure that we can do something // with this `GetEnumerator' // if (return_type == TypeManager.ienumerator_type || - TypeManager.ienumerator_type.IsAssignableFrom (return_type) || - (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) { + TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) { // // If it is not an interface, lets try to find the methods ourselves. // For example, if we have: @@ -5288,11 +5398,10 @@ namespace Mono.CSharp { TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type); } -#if GMCS_SOURCE // // Prefer a generic enumerator over a non-generic one. // - if (return_type.IsInterface && return_type.IsGenericType) { + if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) { enumerator_type = return_type; if (!FetchGetCurrent (ec, return_type)) get_current = new PropertyExpr ( @@ -5301,7 +5410,6 @@ namespace Mono.CSharp { move_next = TypeManager.bool_movenext_void; return true; } -#endif if (return_type.IsInterface || !FetchMoveNext (return_type) || @@ -5335,14 +5443,10 @@ namespace Mono.CSharp { // bool FetchMoveNext (Type t) { - MemberList move_next_list; - - move_next_list = TypeContainer.FindMembers ( - t, MemberTypes.Method, + MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t, + MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, - Type.FilterName, "MoveNext"); - if (move_next_list.Count == 0) - return false; + "MoveNext", null); foreach (MemberInfo m in move_next_list){ MethodInfo mi = (MethodInfo) m; @@ -5372,32 +5476,7 @@ namespace Mono.CSharp { return true; } - // - // Retrieves a `public void Dispose ()' method from the Type `t' - // - static MethodInfo FetchMethodDispose (Type t) - { - MemberList dispose_list; - - dispose_list = TypeContainer.FindMembers ( - t, MemberTypes.Method, - BindingFlags.Public | BindingFlags.Instance, - Type.FilterName, "Dispose"); - if (dispose_list.Count == 0) - return null; - - foreach (MemberInfo m in dispose_list){ - MethodInfo mi = (MethodInfo) m; - - if (TypeManager.GetParameterData (mi).Count == 0){ - if (mi.ReturnType == TypeManager.void_type) - return mi; - } - } - return null; - } - - public void Error_Enumerator () + void Error_Enumerator () { if (enumerator_found) { return; @@ -5539,9 +5618,6 @@ namespace Mono.CSharp { 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 @@ -5576,9 +5652,14 @@ namespace Mono.CSharp { loop = new While (move_next_expr, block, loc); - wrapper = is_disposable ? - (Statement) new DisposableWrapper (this) : - (Statement) new NonDisposableWrapper (this); + + bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type); + if (implements_idisposable || !enumerator_type.IsSealed) { + wrapper = new DisposableWrapper (this, implements_idisposable); + } else { + wrapper = new NonDisposableWrapper (this); + } + return wrapper.Resolve (ec); } @@ -5595,6 +5676,11 @@ namespace Mono.CSharp { this.parent = parent; } + protected override void CloneTo (CloneContext clonectx, Statement target) + { + throw new NotSupportedException (); + } + public override bool Resolve (EmitContext ec) { return parent.ResolveLoop (ec); @@ -5605,14 +5691,27 @@ namespace Mono.CSharp { parent.EmitLoopInit (ec); parent.EmitLoopBody (ec); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + throw new NotSupportedException (); + } } - class DisposableWrapper : ExceptionStatement { + sealed class DisposableWrapper : ExceptionStatement + { CollectionForeach parent; + bool implements_idisposable; - internal DisposableWrapper (CollectionForeach parent) + internal DisposableWrapper (CollectionForeach parent, bool implements) { this.parent = parent; + this.implements_idisposable = implements; + } + + protected override void CloneTo (CloneContext clonectx, Statement target) + { + throw new NotSupportedException (); } public override bool Resolve (EmitContext ec) @@ -5647,7 +5746,35 @@ namespace Mono.CSharp { protected override void EmitFinallyBody (EmitContext ec) { - parent.EmitFinallyBody (ec); + Expression instance = parent.enumerator; + if (!TypeManager.IsValueType (parent.enumerator_type)) { + ILGenerator ig = ec.ig; + + parent.enumerator.Emit (ec); + + Label call_dispose = ig.DefineLabel (); + + if (!implements_idisposable) { + ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); + LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type); + temp.Store (ec); + temp.Emit (ec); + instance = temp; + } + + ig.Emit (OpCodes.Brtrue_S, call_dispose); + + // using 'endfinally' to empty the evaluation stack + ig.Emit (OpCodes.Endfinally); + ig.MarkLabel (call_dispose); + } + + Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, new ArrayList (0), loc); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + throw new NotSupportedException (); } } @@ -5658,7 +5785,7 @@ namespace Mono.CSharp { void EmitLoopInit (EmitContext ec) { - enumerator.Store (ec, init); + enumerator.EmitAssign (ec, init); } void EmitLoopBody (EmitContext ec) @@ -5666,81 +5793,73 @@ namespace Mono.CSharp { loop.Emit (ec); } - void EmitFinallyBody (EmitContext ec) + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { - ILGenerator ig = ec.ig; - - if (enumerator_type.IsValueType) { - MethodInfo mi = FetchMethodDispose (enumerator_type); - if (mi != null) { - enumerator.EmitLoadAddress (ec); - ig.Emit (OpCodes.Call, mi); - } else { - enumerator.Emit (ec); - ig.Emit (OpCodes.Box, enumerator_type); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } - } else { - Label call_dispose = ig.DefineLabel (); + enumerator_type = storey.MutateType (enumerator_type); + init.MutateHoistedGenericType (storey); + loop.MutateHoistedGenericType (storey); + } + } - enumerator.Emit (ec); - ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); - ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Brtrue_S, call_dispose); + Expression type; + Expression variable; + Expression expr; + Statement statement; - // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block - // (Partition III, Section 3.35) - ig.Emit (OpCodes.Endfinally); + public Foreach (Expression type, LocalVariableReference var, Expression expr, + Statement stmt, Location l) + { + this.type = type; + this.variable = var; + this.expr = expr; + statement = stmt; + loc = l; + } - ig.MarkLabel (call_dispose); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } - } + public Statement Statement { + get { return statement; } } - protected class CollectionForeachStatement : Statement + public override bool Resolve (EmitContext ec) { - Type type; - Expression variable, current, conv; - Statement statement; - Assign assign; + expr = expr.Resolve (ec); + if (expr == null) + return false; - public CollectionForeachStatement (Type type, Expression variable, - Expression current, Statement statement, - Location loc) - { - this.type = type; - this.variable = variable; - this.current = current; - this.statement = statement; - this.loc = loc; + if (expr.IsNull) { + Report.Error (186, loc, "Use of null is not valid in this context"); + return false; } - public override bool Resolve (EmitContext ec) - { - current = current.Resolve (ec); - if (current == null) + if (expr.Type == TypeManager.string_type) { + statement = new ArrayForeach (this, 1); + } else if (expr.Type.IsArray) { + statement = new ArrayForeach (this, expr.Type.GetArrayRank ()); + } else { + if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) { + Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'", + expr.ExprClassName); return false; + } - conv = Convert.ExplicitConversion (ec, current, type, loc); - if (conv == null) - return false; + statement = new CollectionForeach (type, variable, expr, statement, loc); + } - assign = new SimpleAssign (variable, conv, loc); - if (assign.Resolve (ec) == null) - return false; + return statement.Resolve (ec); + } - if (!statement.Resolve (ec)) - return false; + protected override void DoEmit (EmitContext ec) + { + ILGenerator ig = ec.ig; - return true; - } + Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd; + ec.LoopBegin = ig.DefineLabel (); + ec.LoopEnd = ig.DefineLabel (); - protected override void DoEmit (EmitContext ec) - { - assign.EmitStatement (ec); - statement.Emit (ec); - } + statement.Emit (ec); + + ec.LoopBegin = old_begin; + ec.LoopEnd = old_end; } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -5752,5 +5871,10 @@ namespace Mono.CSharp { target.expr = expr.Clone (clonectx); target.statement = statement.Clone (clonectx); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + statement.MutateHoistedGenericType (storey); + } } }