X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fstatement.cs;h=bb4a8007f7a1b358bf618457d993b7dae3669d38;hb=67dae6e4154448e87f29b3b4b13f8cc364b7ef83;hp=15f8ca49b19619d4a3b9de6cc8aa15e0893d6a41;hpb=58a175b868892577cd95bd7c6bcaec743f4d4d6d;p=mono.git diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 15f8ca49b19..bb4a8007f7a 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -27,7 +27,7 @@ namespace Mono.CSharp { /// Resolves the statement, true means that all sub-statements /// did resolve ok. // - public virtual bool Resolve (EmitContext ec) + public virtual bool Resolve (BlockContext ec) { return true; } @@ -36,7 +36,7 @@ namespace Mono.CSharp { /// We already know that the statement is unreachable, but we still /// need to resolve it to catch errors. /// - public virtual bool ResolveUnreachable (EmitContext ec, bool warn) + public virtual bool ResolveUnreachable (BlockContext ec, bool warn) { // // This conflicts with csc's way of doing this, but IMHO it's @@ -48,7 +48,7 @@ namespace Mono.CSharp { // if (warn) - Report.Warning (162, 2, loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); bool ok = Resolve (ec); @@ -62,25 +62,6 @@ namespace Mono.CSharp { /// protected abstract void DoEmit (EmitContext ec); - /// - /// Utility wrapper routine for Error, just to beautify the code - /// - public void Error (int error, string format, params object[] args) - { - Error (error, String.Format (format, args)); - } - - public void Error (int error, string s) - { - if (!loc.IsNull) - Report.Error (error, loc, s); - else - Report.Error (error, s); - } - - /// - /// Return value indicates whether all code paths emitted return. - /// public virtual void Emit (EmitContext ec) { ec.Mark (loc); @@ -100,9 +81,9 @@ namespace Mono.CSharp { return s; } - public virtual Expression CreateExpressionTree (EmitContext ec) + public virtual Expression CreateExpressionTree (ResolveContext ec) { - Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); + ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree"); return null; } @@ -116,82 +97,18 @@ namespace Mono.CSharp { public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey); } - // - // This class is used during the Statement.Clone operation - // to remap objects that have been cloned. - // - // Since blocks are cloned by Block.Clone, we need a way for - // expressions that must reference the block to be cloned - // pointing to the new cloned block. - // - public class CloneContext { - Hashtable block_map = new Hashtable (); - Hashtable variable_map; - - public void AddBlockMap (Block from, Block to) - { - if (block_map.Contains (from)) - return; - block_map [from] = to; - } - - public Block LookupBlock (Block from) - { - Block result = (Block) block_map [from]; - - if (result == null){ - result = (Block) from.Clone (this); - block_map [from] = result; - } - - return result; - } - - /// - /// Remaps block to cloned copy if one exists. - /// - public Block RemapBlockCopy (Block from) - { - Block mapped_to = (Block)block_map[from]; - if (mapped_to == null) - return from; - - return mapped_to; - } - - public void AddVariableMap (LocalInfo from, LocalInfo to) - { - if (variable_map == null) - variable_map = new Hashtable (); - - if (variable_map.Contains (from)) - return; - variable_map [from] = to; - } - - public LocalInfo LookupVariable (LocalInfo from) - { - LocalInfo result = (LocalInfo) variable_map [from]; - - if (result == null) - throw new Exception ("LookupVariable: looking up a variable that has not been registered yet"); - - return result; - } - } - public sealed class EmptyStatement : Statement { private EmptyStatement () {} public static readonly EmptyStatement Value = new EmptyStatement (); - - public override bool Resolve (EmitContext ec) + + public override bool Resolve (BlockContext ec) { return true; } - public override bool ResolveUnreachable (EmitContext ec, bool warn) + public override bool ResolveUnreachable (BlockContext ec, bool warn) { return true; } @@ -216,20 +133,18 @@ namespace Mono.CSharp { public Statement FalseStatement; bool is_true_ret; - - public If (Expression expr, Statement true_statement, Location l) + + public If (Expression bool_expr, Statement true_statement, Location l) + : this (bool_expr, true_statement, null, l) { - this.expr = expr; - TrueStatement = true_statement; - loc = l; } - public If (Expression expr, + public If (Expression bool_expr, Statement true_statement, Statement false_statement, Location l) { - this.expr = expr; + this.expr = bool_expr; TrueStatement = true_statement; FalseStatement = false_statement; loc = l; @@ -243,50 +158,44 @@ namespace Mono.CSharp { FalseStatement.MutateHoistedGenericType (storey); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; Report.Debug (1, "START IF BLOCK", loc); - expr = Expression.ResolveBoolean (ec, expr, loc); - if (expr == null){ + expr = expr.Resolve (ec); + if (expr == null) { ok = false; - goto skip; - } - - Assign ass = expr as Assign; - if (ass != null && ass.Source is Constant) { - Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?"); - } + } else { + // + // Dead code elimination + // + if (expr is Constant) { + bool take = !((Constant) expr).IsDefaultValue; - // - // Dead code elimination - // - if (expr is Constant){ - bool take = !((Constant) expr).IsDefaultValue; + if (take) { + if (!TrueStatement.Resolve (ec)) + return false; - if (take){ - if (!TrueStatement.Resolve (ec)) - return false; + if ((FalseStatement != null) && + !FalseStatement.ResolveUnreachable (ec, true)) + return false; + FalseStatement = null; + } else { + if (!TrueStatement.ResolveUnreachable (ec, true)) + return false; + TrueStatement = null; - if ((FalseStatement != null) && - !FalseStatement.ResolveUnreachable (ec, true)) - return false; - FalseStatement = null; - } else { - if (!TrueStatement.ResolveUnreachable (ec, true)) - return false; - TrueStatement = null; + if ((FalseStatement != null) && + !FalseStatement.Resolve (ec)) + return false; + } - if ((FalseStatement != null) && - !FalseStatement.Resolve (ec)) - return false; + return true; } - - return true; } - skip: + ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc); ok &= TrueStatement.Resolve (ec); @@ -364,15 +273,15 @@ namespace Mono.CSharp { public class Do : Statement { public Expression expr; public Statement EmbeddedStatement; - - public Do (Statement statement, Expression bool_expr, Location l) + + public Do (Statement statement, BooleanExpression bool_expr, Location l) { expr = bool_expr; EmbeddedStatement = statement; loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -386,9 +295,9 @@ namespace Mono.CSharp { ec.EndFlowBranching (); if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable) - Report.Warning (162, 2, expr.Location, "Unreachable code detected"); + ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected"); - expr = Expression.ResolveBoolean (ec, expr, loc); + expr = expr.Resolve (ec); if (expr == null) ok = false; else if (expr is Constant){ @@ -453,21 +362,21 @@ namespace Mono.CSharp { public Expression expr; public Statement Statement; bool infinite, empty; - - public While (Expression bool_expr, Statement statement, Location l) + + public While (BooleanExpression bool_expr, Statement statement, Location l) { this.expr = bool_expr; Statement = statement; loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; - expr = Expression.ResolveBoolean (ec, expr, loc); + expr = expr.Resolve (ec); if (expr == null) - return false; + ok = false; // // Inform whether we are infinite or not @@ -578,7 +487,7 @@ namespace Mono.CSharp { bool infinite, empty; public For (Statement init_statement, - Expression test, + BooleanExpression test, Statement increment, Statement statement, Location l) @@ -590,7 +499,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -600,7 +509,7 @@ namespace Mono.CSharp { } if (Test != null){ - Test = Expression.ResolveBoolean (ec, Test, loc); + Test = Test.Resolve (ec); if (Test == null) ok = false; else if (Test is Constant){ @@ -737,9 +646,9 @@ namespace Mono.CSharp { loc = expr.Location; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - if (expr != null) + if (expr != null && expr.eclass == ExprClass.Invalid) expr = expr.ResolveStatement (ec); return expr != null; } @@ -771,14 +680,14 @@ namespace Mono.CSharp { public abstract class ExitStatement : Statement { protected bool unwind_protect; - protected abstract bool DoResolve (EmitContext ec); + protected abstract bool DoResolve (BlockContext ec); - public virtual void Error_FinallyClause () + public virtual void Error_FinallyClause (Report Report) { Report.Error (157, loc, "Control cannot leave the body of a finally clause"); } - public sealed override bool Resolve (EmitContext ec) + public sealed override bool Resolve (BlockContext ec) { if (!DoResolve (ec)) return false; @@ -802,55 +711,48 @@ namespace Mono.CSharp { loc = l; } - protected override bool DoResolve (EmitContext ec) + protected override bool DoResolve (BlockContext ec) { if (Expr == null) { if (ec.ReturnType == TypeManager.void_type) return true; - Error (126, "An object of a type convertible to `{0}' is required " + - "for the return statement", - TypeManager.CSharpName (ec.ReturnType)); + ec.Report.Error (126, loc, + "An object of a type convertible to `{0}' is required for the return statement", + TypeManager.CSharpName (ec.ReturnType)); return false; } if (ec.CurrentBlock.Toplevel.IsIterator) { - Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + + ec.Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " + "statement to return a value, or yield break to end the iteration"); } AnonymousExpression am = ec.CurrentAnonymousMethod; if (am == null && ec.ReturnType == TypeManager.void_type) { - MemberCore mc = ec.ResolveContext as MemberCore; - Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void", - mc.GetSignatureForError ()); + ec.Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void", + ec.GetSignatureForError ()); } Expr = Expr.Resolve (ec); if (Expr == null) return false; + if (ec.HasSet (ResolveContext.Options.InferReturnType)) { + ec.ReturnTypeInference.AddCommonTypeBound (Expr.Type); + return true; + } + if (Expr.Type != ec.ReturnType) { - if (ec.InferReturnType) { - // - // void cannot be used in contextual return - // - if (Expr.Type == TypeManager.void_type) - return false; + Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc); - ec.ReturnType = Expr.Type; - } else { - Expr = Convert.ImplicitConversionRequired ( - ec, Expr, ec.ReturnType, loc); - - if (Expr == null) { - if (am != null) { - Report.Error (1662, loc, - "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type", - am.ContainerType, am.GetSignatureForError ()); - } - return false; + if (Expr == null) { + if (am != null) { + ec.Report.Error (1662, loc, + "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type", + am.ContainerType, am.GetSignatureForError ()); } + return false; } } @@ -891,13 +793,12 @@ namespace Mono.CSharp { string target; LabeledStatement label; bool unwind_protect; - - public override bool Resolve (EmitContext ec) + + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } public Goto (string label, Location l) @@ -988,7 +889,7 @@ namespace Mono.CSharp { // nothing to clone } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { // this flow-branching will be terminated when the surrounding block ends ec.StartFlowBranching (this); @@ -1029,23 +930,25 @@ namespace Mono.CSharp { // nothing to clone } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { ec.CurrentBranching.CurrentUsageVector.Goto (); + + if (ec.Switch == null) { + ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement"); + return false; + } + + if (!ec.Switch.GotDefault) { + FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report); + return false; + } + return true; } protected override void DoEmit (EmitContext ec) { - if (ec.Switch == null){ - Report.Error (153, loc, "A goto case is only valid inside a switch statement"); - return; - } - - if (!ec.Switch.GotDefault){ - FlowBranchingBlock.Error_UnknownLabel (loc, "default"); - return; - } ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); } @@ -1067,39 +970,38 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (ec.Switch == null){ - Report.Error (153, loc, "A goto case is only valid inside a switch statement"); + ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement"); return false; } + ec.CurrentBranching.CurrentUsageVector.Goto (); + expr = expr.Resolve (ec); if (expr == null) return false; Constant c = expr as Constant; if (c == null) { - Error (150, "A constant value is expected"); + ec.Report.Error (150, expr.Location, "A constant value is expected"); return false; } Type type = ec.Switch.SwitchType; - 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)) + ec.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; @@ -1107,11 +1009,10 @@ namespace Mono.CSharp { if (sl == null){ FlowBranchingBlock.Error_UnknownLabel (loc, "case " + - (c.GetValue () == null ? "null" : val.ToString ())); + (c.GetValue () == null ? "null" : val.ToString ()), ec.Report); return false; } - ec.CurrentBranching.CurrentUsageVector.Goto (); return true; } @@ -1142,35 +1043,24 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (expr == null) { ec.CurrentBranching.CurrentUsageVector.Goto (); return ec.CurrentBranching.CheckRethrow (loc); } - expr = expr.Resolve (ec); + expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue); ec.CurrentBranching.CurrentUsageVector.Goto (); if (expr == null) return false; - ExprClass eclass = expr.eclass; - - if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || - eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { - expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc); - return false; - } - - Type t = expr.Type; + if (Convert.ImplicitConversionExists (ec, expr, TypeManager.exception_type)) + expr = Convert.ImplicitConversion (ec, expr, TypeManager.exception_type, loc); + else + ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception"); - if ((t != TypeManager.exception_type) && - !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && - !(expr is NullLiteral)) { - Error (155, "The type caught or thrown must be derived from System.Exception"); - return false; - } return true; } @@ -1209,12 +1099,11 @@ namespace Mono.CSharp { bool unwind_protect; - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } protected override void DoEmit (EmitContext ec) @@ -1241,12 +1130,11 @@ namespace Mono.CSharp { bool unwind_protect; - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - int errors = Report.Errors; unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc); ec.CurrentBranching.CurrentUsageVector.Goto (); - return errors == Report.Errors; + return true; } protected override void DoEmit (EmitContext ec) @@ -1280,7 +1168,7 @@ namespace Mono.CSharp { // The information about a user-perceived local variable // public class LocalInfo : IKnownVariable, ILocalVariable { - public readonly Expression Type; + public readonly FullNamedExpression Type; public Type VariableType; public readonly string Name; @@ -1310,8 +1198,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; @@ -1339,7 +1227,7 @@ namespace Mono.CSharp { // builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType); else - builder = ec.ig.DeclareLocal (VariableType); + builder = ec.ig.DeclareLocal (TypeManager.TypeToReflectionType (VariableType)); } } @@ -1364,7 +1252,7 @@ namespace Mono.CSharp { ec.DefineLocalVariable (Name, builder); } - public bool IsThisAssigned (EmitContext ec) + public bool IsThisAssigned (BlockContext ec, Block block) { if (VariableInfo == null) throw new Exception (); @@ -1372,10 +1260,10 @@ namespace Mono.CSharp { if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo)) return true; - return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc); + return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation); } - public bool IsAssigned (EmitContext ec) + public bool IsAssigned (BlockContext ec) { if (VariableInfo == null) throw new Exception (); @@ -1383,7 +1271,7 @@ namespace Mono.CSharp { return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo); } - public bool Resolve (EmitContext ec) + public bool Resolve (ResolveContext ec) { if (VariableType != null) return true; @@ -1397,18 +1285,13 @@ namespace Mono.CSharp { 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); + FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType, ec.Report); return false; } - if (VariableType.IsPointer && !ec.InUnsafe) - Expression.UnsafeError (Location); + if (VariableType.IsPointer && !ec.IsUnsafe) + Expression.UnsafeError (ec, Location); return true; } @@ -1455,12 +1338,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 (); } @@ -1493,7 +1376,7 @@ namespace Mono.CSharp { // 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 @@ -1520,7 +1403,7 @@ 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; @@ -1532,16 +1415,16 @@ namespace Mono.CSharp { BlockUsed = 2, VariablesInitialized = 4, HasRet = 8, - IsDestructor = 16, - Unsafe = 32, - IsIterator = 64, - HasStoreyAccess = 128 + 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 { @@ -1572,7 +1455,6 @@ namespace Mono.CSharp { // Keeps track of (name, type) pairs // IDictionary variables; - protected IDictionary range_variables; // // Keeps track of constants @@ -1588,7 +1470,7 @@ namespace Mono.CSharp { // Block switch_block; - ArrayList scope_initializers; + protected ArrayList scope_initializers; ArrayList anonymous_children; @@ -1612,6 +1494,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) { @@ -1664,9 +1560,9 @@ namespace Mono.CSharp { EndLocation = loc; } - protected static void Error_158 (string name, Location loc) + protected void Error_158 (string name, Location loc) { - Report.Error (158, loc, "The label `{0}' shadows another label " + + Toplevel.Report.Error (158, loc, "The label `{0}' shadows another label " + "by the same name in a contained scope", name); } @@ -1690,8 +1586,8 @@ namespace Mono.CSharp { while (cur != null) { LabeledStatement s = cur.DoLookupLabel (name); if (s != null) { - Report.SymbolRelatedToPreviousError (s.loc, s.Name); - Report.Error (140, target.loc, "The label `{0}' is a duplicate", name); + Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name); + Toplevel.Report.Error (140, target.loc, "The label `{0}' is a duplicate", name); return false; } @@ -1713,7 +1609,7 @@ namespace Mono.CSharp { if (s == null) continue; - Report.SymbolRelatedToPreviousError (s.loc, s.Name); + Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name); Error_158 (name, target.loc); return false; } @@ -1785,8 +1681,8 @@ namespace Mono.CSharp { // block, we violate the invariant meaning in a block. // if (b == this) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); + Toplevel.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); return false; } @@ -1810,8 +1706,8 @@ namespace Mono.CSharp { return true; if (this is ToplevelBlock) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - e.Error_VariableIsUsedBeforeItIsDeclared (name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); + e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name); return false; } @@ -1819,40 +1715,50 @@ namespace Mono.CSharp { // Even though we detected the error when the name is used, we // treat it as if the variable declaration was in error. // - Report.SymbolRelatedToPreviousError (loc, name); + Toplevel.Report.SymbolRelatedToPreviousError (loc, name); Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; } - 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); + block.Report.SymbolRelatedToPreviousError (vi.Location, name); if (Explicit == vi.Block.Explicit) { - if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type) - Error_AlreadyDeclared (l, name); - else - Error_AlreadyDeclared (l, name, null); + Error_AlreadyDeclared (l, name, null); } else { - Error_AlreadyDeclared (l, name, "parent"); + Error_AlreadyDeclared (l, name, this is ToplevelBlock ? + "parent or current" : "parent"); } - return null; + 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); + Toplevel.Report.SymbolRelatedToPreviousError (tp); + Error_AlreadyDeclaredTypeParameter (Toplevel.Report, loc, name, "local variable"); return null; } } @@ -1860,12 +1766,12 @@ namespace Mono.CSharp { IKnownVariable kvi = Explicit.GetKnownVariable (name); if (kvi != null) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); + Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name); Error_AlreadyDeclared (l, name, "child"); return null; } - vi = new LocalInfo (type, name, this, l); + LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l); AddVariable (vi); if ((flags & Flags.VariablesInitialized) != 0) @@ -1887,7 +1793,7 @@ namespace Mono.CSharp { return; } - Report.Error (136, loc, "A local variable named `{0}' cannot be declared " + + Toplevel.Report.Error (136, loc, "A local variable named `{0}' cannot be declared " + "in this scope because it would give a different meaning " + "to `{0}', which is already used in a `{1}' scope " + "to denote something else", var, reason); @@ -1895,14 +1801,15 @@ namespace Mono.CSharp { protected virtual void Error_AlreadyDeclared (Location loc, string name) { - Report.Error (128, loc, + Toplevel.Report.Error (128, loc, "A local variable named `{0}' is already defined in this scope", name); } - protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name) + public virtual void Error_AlreadyDeclaredTypeParameter (Report r, Location loc, string name, string conflict) { - GenericMethod.Error_ParameterNameCollision (loc, name, "local variable"); - } + r.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) { @@ -1946,12 +1853,6 @@ namespace Mono.CSharp { if (ret != null) return ret; } - - if (b.range_variables != null) { - ret = (LocalInfo) b.range_variables [name]; - if (ret != null) - return ret; - } } return null; @@ -1979,7 +1880,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 (); @@ -2006,15 +1907,6 @@ 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 { // TODO: Re-enable @@ -2036,7 +1928,7 @@ namespace Mono.CSharp { anonymous_children.Add (b); } - void DoResolveConstants (EmitContext ec) + void DoResolveConstants (BlockContext ec) { if (constants == null) return; @@ -2051,7 +1943,7 @@ namespace Mono.CSharp { if (variable_type == null) { if (vi.Type is VarExpr) - Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); + ec.Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant"); continue; } @@ -2066,13 +1958,13 @@ namespace Mono.CSharp { constants.Remove (name); if (!Const.IsConstantTypeValid (variable_type)) { - Const.Error_InvalidConstantType (variable_type, loc); + Const.Error_InvalidConstantType (variable_type, loc, ec.Report); continue; } ec.CurrentBlock = this; Expression e; - using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) { + using (ec.With (ResolveContext.Options.ConstantCheckState, (flags & Flags.Unchecked) == 0)) { e = cv.Resolve (ec); } if (e == null) @@ -2080,16 +1972,16 @@ namespace Mono.CSharp { Constant ce = e as Constant; if (ce == null) { - Const.Error_ExpressionMustBeConstant (vi.Location, name); + Const.Error_ExpressionMustBeConstant (vi.Location, name, ec.Report); continue; } 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, ec.Report); else - ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false); + ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false); continue; } @@ -2098,13 +1990,13 @@ namespace Mono.CSharp { } } - protected void ResolveMeta (EmitContext ec, int offset) + protected void ResolveMeta (BlockContext ec, int offset) { Report.Debug (64, "BLOCK RESOLVE META", this, Parent); // If some parent block was unsafe, we remain unsafe even if this block // isn't explicitly marked as such. - using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) { + using (ec.With (ResolveContext.Options.UnsafeScope, ec.IsUnsafe | Unsafe)) { flags |= Flags.VariablesInitialized; if (variables != null) { @@ -2147,9 +2039,9 @@ namespace Mono.CSharp { } } - void UsageWarning () + void UsageWarning (BlockContext ec) { - if (variables == null || Report.WarningLevel < 3) + if (variables == null || ec.Report.WarningLevel < 3) return; foreach (DictionaryEntry de in variables) { @@ -2160,14 +2052,14 @@ namespace Mono.CSharp { // vi.VariableInfo can be null for 'catch' variables if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned) - Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name); + ec.Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name); else - Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name); + ec.Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name); } } } - static void CheckPossibleMistakenEmptyStatement (Statement s) + static void CheckPossibleMistakenEmptyStatement (BlockContext ec, Statement s) { Statement body; @@ -2196,21 +2088,29 @@ namespace Mono.CSharp { return; if (body == null || body is EmptyStatement) - Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); + ec.Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { Block prev_block = ec.CurrentBlock; bool ok = true; - int errors = Report.Errors; + int errors = ec.Report.Errors; ec.CurrentBlock = this; ec.StartFlowBranching (this); Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching); + // + // Compiler generated scope statements + // + if (scope_initializers != null) { + foreach (Statement s in scope_initializers) + s.Resolve (ec); + } + // // This flag is used to notate nested statements as unreachable from the beginning of this block. // For the purposes of this resolution, it doesn't matter that the whole block is unreachable @@ -2221,10 +2121,9 @@ namespace Mono.CSharp { for (int ix = 0; ix < statement_count; ix++){ Statement s = (Statement) statements [ix]; // Check possible empty statement (CS0642) - if (Report.WarningLevel >= 3 && - ix + 1 < statement_count && - statements [ix + 1] is Block) - CheckPossibleMistakenEmptyStatement (s); + if (ix + 1 < statement_count && ec.Report.WarningLevel >= 3 && + statements [ix + 1] is ExplicitBlock) + CheckPossibleMistakenEmptyStatement (ec, s); // // Warn if we detect unreachable code. @@ -2234,7 +2133,7 @@ namespace Mono.CSharp { continue; if (!unreachable_shown && !(s is LabeledStatement)) { - Report.Warning (162, 2, s.loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, s.loc, "Unreachable code detected"); unreachable_shown = true; } @@ -2286,25 +2185,25 @@ namespace Mono.CSharp { if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable) ok = false; - if ((labels != null) && (Report.WarningLevel >= 2)) { + if ((labels != null) && (ec.Report.WarningLevel >= 2)) { foreach (LabeledStatement label in labels.Values) if (!label.HasBeenReferenced) - Report.Warning (164, 2, label.loc, "This label has not been referenced"); + ec.Report.Warning (164, 2, label.loc, "This label has not been referenced"); } - if (ok && errors == Report.Errors) - UsageWarning (); + if (ok && errors == ec.Report.Errors) + UsageWarning (ec); return ok; } - public override bool ResolveUnreachable (EmitContext ec, bool warn) + public override bool ResolveUnreachable (BlockContext ec, bool warn) { unreachable_shown = true; unreachable = true; if (warn) - Report.Warning (162, 2, loc, "Unreachable code detected"); + ec.Report.Warning (162, 2, loc, "Unreachable code detected"); ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc); bool ok = Resolve (ec); @@ -2323,28 +2222,26 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - Block prev_block = ec.CurrentBlock; - ec.CurrentBlock = this; - - if (scope_initializers != null) { - SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); - - bool omit_debug_info = ec.OmitDebuggingInfo; - ec.OmitDebuggingInfo = true; - foreach (StatementExpression s in scope_initializers) - s.Emit (ec); - ec.OmitDebuggingInfo = omit_debug_info; - - SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); - } + if (scope_initializers != null) + EmitScopeInitializers (ec); ec.Mark (StartLocation); DoEmit (ec); if (SymbolWriter.HasSymbolWriter) EmitSymbolInfo (ec); + } - ec.CurrentBlock = prev_block; + protected void EmitScopeInitializers (EmitContext ec) + { + SymbolWriter.OpenCompilerGeneratedBlock (ec.ig); + + using (ec.With (EmitContext.Options.OmitDebugInfo, true)) { + foreach (Statement s in scope_initializers) + s.Emit (ec); + } + + SymbolWriter.CloseCompilerGeneratedBlock (ec.ig); } protected virtual void EmitSymbolInfo (EmitContext ec) @@ -2360,6 +2257,11 @@ namespace Mono.CSharp { { MutateVariables (storey); + if (scope_initializers != null) { + foreach (Statement s in scope_initializers) + s.MutateHoistedGenericType (storey); + } + foreach (Statement s in statements) s.MutateHoistedGenericType (storey); } @@ -2459,13 +2361,12 @@ namespace Mono.CSharp { // // Creates anonymous method storey in current block // - public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec) + public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec) { // // When referencing a variable in iterator storey from children anonymous method // if (Toplevel.am_storey is IteratorStorey) { - ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey); return Toplevel.am_storey; } @@ -2476,30 +2377,22 @@ namespace Mono.CSharp { return ec.CurrentIterator.Storey; if (am_storey == null) { - MemberBase mc = ec.ResolveContext as MemberBase; + MemberBase mc = ec.MemberContext as MemberBase; GenericMethod gm = mc == null ? null : mc.GenericMethod; // - // Create anonymous method storey for this block + // Creates anonymous method storey for this block // - am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey"); + am_storey = new AnonymousMethodStorey (this, ec.CurrentTypeDefinition, mc, gm, "AnonStorey"); } - // - // Creates a link between this block and the anonymous method - // - // An anonymous method can reference variables from any outer block, but they are - // hoisted in their own ExplicitBlock. When more than one block is referenced we - // need to create another link between those variable storeys - // - ec.CurrentAnonymousMethod.AddStoreyReference (am_storey); return am_storey; } public override void Emit (EmitContext ec) { if (am_storey != null) - am_storey.EmitHoistedVariables (ec); + am_storey.EmitStoreyInstantiation (ec); bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey); if (emit_debug_info) @@ -2518,24 +2411,49 @@ namespace Mono.CSharp { // 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.DefineMembers (); + am_storey.ResolveType (); + am_storey.Define (); am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey); - } - base.EmitMeta (ec); - } + 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); - protected override void EmitSymbolInfo (EmitContext ec) - { - if (am_storey != null) - SymbolWriter.DefineScopeVariable (am_storey.ID); + // Stop propagation inside same top block + if (b.Toplevel == Toplevel) + break; - base.EmitSymbolInfo (ec); + b = b.Toplevel; + } + b.HasCapturedVariable = true; + } + } + } + } + + base.EmitMeta (ec); } internal IKnownVariable GetKnownVariable (string name) @@ -2543,29 +2461,16 @@ namespace Mono.CSharp { return known_variables == null ? null : (IKnownVariable) known_variables [name]; } - public void PropagateStoreyReference (AnonymousMethodStorey s) + public bool HasCapturedThis { - if (Parent != null && am_storey != s) { - if (am_storey != null) - am_storey.AddParentStoreyReference (s); - - Parent.Explicit.PropagateStoreyReference (s); - } + set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; } + get { return (flags & Flags.HasCapturedThis) != 0; } } - public override bool Resolve (EmitContext ec) + public bool HasCapturedVariable { - bool ok = base.Resolve (ec); - - // - // Discard an anonymous method storey when this block has no hoisted variables - // - if (am_storey != null && !am_storey.HasHoistedVariables) { - am_storey.Undo (); - am_storey = null; - } - - return ok; + set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; } + get { return (flags & Flags.HasCapturedVariable) != 0; } } protected override void CloneTo (CloneContext clonectx, Statement t) @@ -2587,6 +2492,11 @@ namespace Mono.CSharp { public Parameter Parameter { get { return Block.Parameters [Index]; } } + + public Type ParameterType { + get { return Block.Parameters.Types [Index]; } + } + public Location Location { get { return Parameter.Location; } } @@ -2606,73 +2516,131 @@ 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 (ResolveContext ec) + { + throw new NotSupportedException (); + } + + public override Expression DoResolve (ResolveContext ec) + { + if (child == null) + return null; + + 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; - Parameters parameters; + protected ParametersCompiled parameters; ToplevelParameterInfo[] parameter_info; LocalInfo this_variable; + bool resolved; + bool unreachable; + CompilerContext compiler; public HoistedVariable HoistedThisVariable; + public bool Resolved { + get { + return resolved; + } + } + // // The parameters for the block. // - public Parameters Parameters { + public ParametersCompiled Parameters { get { return parameters; } } - public GenericMethod GenericMethod { - get { return generic; } + public Report Report { + get { return compiler.Report; } } - public bool HasStoreyAccess { - set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; } - get { return (flags & Flags.HasStoreyAccess) != 0; } + public GenericMethod GenericMethod { + get { return generic; } } public ToplevelBlock Container { get { return Parent == null ? null : Parent.Toplevel; } } - public ToplevelBlock (Block parent, Parameters parameters, Location start) : - this (parent, (Flags) 0, parameters, start) + public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, Location start) : + this (ctx, parent, (Flags) 0, parameters, start) { } - public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) : - this (parent, parameters, start) + public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) : + this (ctx, parent, parameters, start) { this.generic = generic; } - - public ToplevelBlock (Parameters parameters, Location start) : - this (null, (Flags) 0, parameters, start) + + public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) : + this (ctx, null, (Flags) 0, parameters, start) { } - ToplevelBlock (Flags flags, Parameters parameters, Location start) : - this (null, flags, parameters, start) + ToplevelBlock (CompilerContext ctx, Flags flags, ParametersCompiled parameters, Location start) : + this (ctx, null, flags, parameters, start) { } // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child. // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'. - public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) : + public ToplevelBlock (CompilerContext ctx, Block parent, Flags flags, ParametersCompiled parameters, Location start) : base (null, flags, start, Location.Null) { + this.compiler = ctx; this.Toplevel = this; - this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + this.parameters = parameters; this.Parent = parent; if (parent != null) parent.AddAnonymousChild (this); - if (!this.parameters.Empty) + if (!this.parameters.IsEmpty) ProcessParameters (); } - public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc) + public ToplevelBlock (CompilerContext ctx, Location loc) + : this (ctx, null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc) { } @@ -2704,15 +2672,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); @@ -2721,21 +2685,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 @@ -2755,9 +2706,17 @@ namespace Mono.CSharp { return true; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { - return ((Statement) statements [0]).CreateExpressionTree (ec); + if (statements.Count == 1) { + Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec); + if (scope_initializers != null) + expr = new BlockScopeExpression (expr, this); + + return expr; + } + + return base.CreateExpressionTree (ec); } // @@ -2765,16 +2724,10 @@ namespace Mono.CSharp { // public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source) { - // Create block with original statements - ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation); IsIterator = true; - // TODO: Change to iter_block.statements = statements; - foreach (Statement stmt in source.statements) - iter_block.AddStatement (stmt); - labels = source.labels; - - AddStatement (new IteratorStatement (iterator, iter_block)); + // Creates block with original statements + AddStatement (new IteratorStatement (iterator, new Block (this, source))); source.statements = new ArrayList (1); source.AddStatement (new Return (iterator, iterator.Location)); @@ -2785,31 +2738,28 @@ namespace Mono.CSharp { return iterator_storey; } - public FlowBranchingToplevel TopLevelBranching { - get { return top_level_branching; } - } - // - // 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) + public Expression GetParameterReference (string name, Location loc) { - ToplevelParameterInfo p = GetParameterInfo (name); - return p == null ? null : new ParameterReference (this, p, loc); - } - - public ToplevelParameterInfo GetParameterInfo (string name) - { - 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; } + 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. // See AddThisVariable() for more information. @@ -2843,19 +2793,60 @@ namespace Mono.CSharp { set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; } } - public bool IsThisAssigned (EmitContext ec) + public bool IsThisAssigned (BlockContext ec) { - return this_variable == null || this_variable.IsThisAssigned (ec); + return this_variable == null || this_variable.IsThisAssigned (ec, this); } - public bool ResolveMeta (EmitContext ec, Parameters ip) + public bool Resolve (FlowBranching parent, BlockContext rc, ParametersCompiled ip, IMethodData md) { - int errors = Report.Errors; - int orig_count = parameters.Count; - - if (top_level_branching != null) + if (resolved) return true; + resolved = true; + + try { + if (!ResolveMeta (rc, ip)) + return false; + + using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) { + FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent); + + if (!Resolve (rc)) + return false; + + unreachable = top_level.End (); + } + } catch (Exception) { +#if PRODUCTION + if (rc.CurrentBlock != null) { + ec.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: Phase Resolve"); + } else { + ec.Report.Error (587, "Internal compiler error: Phase Resolve"); + } +#endif + throw; + } + + if (rc.ReturnType != TypeManager.void_type && !unreachable) { + if (rc.CurrentAnonymousMethod == null) { + rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ()); + return false; + } else if (!rc.CurrentAnonymousMethod.IsIterator) { + rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'", + rc.CurrentAnonymousMethod.GetSignatureForError ()); + return false; + } + } + + return true; + } + + bool ResolveMeta (BlockContext ec, ParametersCompiled ip) + { + int errors = ec.Report.Errors; + int orig_count = parameters.Count; + if (ip != null) parameters = ip; @@ -2866,7 +2857,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; @@ -2878,9 +2869,7 @@ namespace Mono.CSharp { ResolveMeta (ec, offset); - top_level_branching = ec.StartFlowBranching (this); - - return Report.Errors == errors; + return ec.Report.Errors == errors; } // @@ -2907,6 +2896,61 @@ namespace Mono.CSharp { } } + public override void Emit (EmitContext ec) + { + if (Report.Errors > 0) + return; + +#if PRODUCTION + try { +#endif + EmitMeta (ec); + + if (ec.HasReturnLabel) + ec.ReturnLabel = ec.ig.DefineLabel (); + + base.Emit (ec); + + ec.Mark (EndLocation); + + if (ec.HasReturnLabel) + ec.ig.MarkLabel (ec.ReturnLabel); + + if (ec.return_value != null) { + ec.ig.Emit (OpCodes.Ldloc, ec.return_value); + ec.ig.Emit (OpCodes.Ret); + } else { + // + // If `HasReturnLabel' is set, then we already emitted a + // jump to the end of the method, so we must emit a `ret' + // there. + // + // Unfortunately, System.Reflection.Emit automatically emits + // a leave to the end of a finally block. This is a problem + // if no code is following the try/finally block since we may + // jump to a point after the end of the method. + // As a workaround, we're always creating a return label in + // this case. + // + + if (ec.HasReturnLabel || !unreachable) { + if (ec.ReturnType != TypeManager.void_type) + ec.ig.Emit (OpCodes.Ldloc, ec.TemporaryReturn ()); + ec.ig.Emit (OpCodes.Ret); + } + } + +#if PRODUCTION + } catch (Exception e){ + Console.WriteLine ("Exception caught by the compiler while emitting:"); + Console.WriteLine (" Block that caused the problem begin at: " + block.loc); + + Console.WriteLine (e.GetType ().FullName + ": " + e.Message); + throw; + } +#endif + } + public override void EmitMeta (EmitContext ec) { parameters.ResolveVariable (); @@ -2918,10 +2962,13 @@ namespace Mono.CSharp { base.EmitMeta (ec); } - public override void Emit (EmitContext ec) + protected override void EmitSymbolInfo (EmitContext ec) { - base.Emit (ec); - ec.Mark (EndLocation); + AnonymousExpression ae = ec.CurrentAnonymousMethod; + if ((ae != null) && (ae.Storey != null)) + SymbolWriter.DefineScopeVariable (ae.Storey.ID); + + base.EmitSymbolInfo (ec); } } @@ -2984,7 +3031,7 @@ namespace Mono.CSharp { // Resolves the expression, reduces it to a literal if possible // and then converts it to the requested type. // - public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable) + public bool ResolveAndReduce (ResolveContext ec, Type required_type, bool allow_nullable) { Expression e = label.Resolve (ec); @@ -2993,7 +3040,7 @@ namespace Mono.CSharp { Constant c = e as Constant; if (c == null){ - Report.Error (150, loc, "A constant value is expected"); + ec.Report.Error (150, loc, "A constant value is expected"); return false; } @@ -3007,7 +3054,7 @@ namespace Mono.CSharp { return true; } - c = c.ImplicitConversionRequired (required_type, loc); + c = c.ImplicitConversionRequired (ec, required_type, loc); if (c == null) return false; @@ -3015,20 +3062,18 @@ namespace Mono.CSharp { return true; } - public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with) + public void Error_AlreadyOccurs (ResolveContext ec, Type switch_type, SwitchLabel collision_with) { string label; if (converted == null) label = "default"; else if (converted == NullStringCase) label = "null"; - else if (TypeManager.IsEnumType (switch_type)) - label = TypeManager.CSharpEnumValue (switch_type, converted); else label = converted.ToString (); - Report.SymbolRelatedToPreviousError (collision_with.loc, null); - Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); + ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null); + ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); } public SwitchLabel Clone (CloneContext clonectx) @@ -3088,20 +3133,14 @@ namespace Mono.CSharp { FieldExpr switch_cache_field; static int unique_counter; -#if GMCS_SOURCE // - // Nullable Types support for GMCS. + // Nullable Types support // Nullable.Unwrap unwrap; protected bool HaveUnwrap { get { return unwrap != null; } } -#else - protected bool HaveUnwrap { - get { return false; } - } -#endif // // The types allowed to be implicitly cast from @@ -3134,7 +3173,7 @@ namespace Mono.CSharp { // expression that includes any potential conversions to the // integral types or to string. // - Expression SwitchGoverningType (EmitContext ec, Expression expr) + Expression SwitchGoverningType (ResolveContext ec, Expression expr) { Type t = expr.Type; @@ -3189,7 +3228,7 @@ namespace Mono.CSharp { continue; if (converted != null){ - Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous "); + ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous "); return null; } @@ -3205,7 +3244,7 @@ namespace Mono.CSharp { // It also returns a hashtable with the keys that we will later // use to compute the switch tables // - bool CheckSwitch (EmitContext ec) + bool CheckSwitch (ResolveContext ec) { bool error = false; Elements = Sections.Count > 10 ? @@ -3216,7 +3255,7 @@ namespace Mono.CSharp { foreach (SwitchLabel sl in ss.Labels){ if (sl.Label == null){ if (default_section != null){ - sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]); + sl.Error_AlreadyOccurs (ec, SwitchType, (SwitchLabel)default_section.Labels [0]); error = true; } default_section = ss; @@ -3235,7 +3274,7 @@ namespace Mono.CSharp { try { Elements.Add (key, sl); } catch (ArgumentException) { - sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]); + sl.Error_AlreadyOccurs (ec, SwitchType, (SwitchLabel)Elements [key]); error = true; } } @@ -3553,9 +3592,10 @@ namespace Mono.CSharp { public static void Reset () { unique_counter = 0; + allowed_types = null; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { Expr = Expr.Resolve (ec); if (Expr == null) @@ -3563,18 +3603,18 @@ 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"); + ec.Report.Error (151, loc, + "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type", + TypeManager.CSharpName (Expr.Type)); return false; } @@ -3582,7 +3622,7 @@ namespace Mono.CSharp { SwitchType = new_expr.Type; if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) { - Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); + ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type"); return false; } @@ -3652,40 +3692,40 @@ namespace Mono.CSharp { return true; } - void ResolveStringSwitchMap (EmitContext ec) + void ResolveStringSwitchMap (ResolveContext ec) { FullNamedExpression string_dictionary_type; -#if GMCS_SOURCE - MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", - new TypeArguments (loc, - new TypeExpression (TypeManager.string_type, loc), - new TypeExpression (TypeManager.int32_type, loc)), loc); -#else - MemberAccess system_collections_generic = new MemberAccess ( - new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); - - string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); -#endif - Field field = new Field (ec.TypeContainer, string_dictionary_type, + if (TypeManager.generic_ienumerable_type != null) { + MemberAccess system_collections_generic = new MemberAccess (new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary", + new TypeArguments ( + new TypeExpression (TypeManager.string_type, loc), + new TypeExpression (TypeManager.int32_type, loc)), loc); + } else { + MemberAccess system_collections_generic = new MemberAccess ( + new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc); + + string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc); + } + + Field field = new Field (ec.CurrentTypeDefinition, string_dictionary_type, Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, - CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), null, loc); + new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null); if (!field.Define ()) return; - ec.TypeContainer.PartialContainer.AddField (field); + ec.CurrentTypeDefinition.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) { - value = null; + if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) continue; - } value = (string) sl.Converted; ArrayList init_args = new ArrayList (2); @@ -3694,15 +3734,18 @@ namespace Mono.CSharp { init.Add (new CollectionElementInitializer (init_args, loc)); } - if (value == null) + // + // Don't add empty sections + // + if (last_count == init.Count) continue; Elements.Add (counter, section.Labels [0]); ++counter; } - ArrayList args = new ArrayList (1); - args.Add (new Argument (new IntConstant (Sections.Count, loc))); + Arguments args = new Arguments (1); + args.Add (new Argument (new IntConstant (init.Count, loc))); Expression initializer = new NewInitialize (string_dictionary_type, args, new CollectionOrObjectInitializers (init, loc), loc); @@ -3729,36 +3772,39 @@ namespace Mono.CSharp { LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type); -#if GMCS_SOURCE - ArrayList get_value_args = new ArrayList (2); - get_value_args.Add (new Argument (value)); - get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); - Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec); - if (get_item == null) - return; + ResolveContext rc = new ResolveContext (ec.MemberContext); - // - // A value was not found, go to default case - // - get_item.EmitBranchable (ec, default_target, false); -#else - ArrayList get_value_args = new ArrayList (1); - get_value_args.Add (value); + if (TypeManager.generic_ienumerable_type != null) { + Arguments get_value_args = new Arguments (2); + get_value_args.Add (new Argument (value)); + get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out)); + Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc); + if (get_item == null) + return; - Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec); - if (get_item == null) - return; + // + // A value was not found, go to default case + // + get_item.EmitBranchable (ec, default_target, false); + } else { + Arguments get_value_args = new Arguments (1); + get_value_args.Add (new Argument (value)); + + Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (rc); + 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); + 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); + ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable, + new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc); + + get_item_int.EmitStatement (ec); + get_item_object.Release (ec); + } - get_item_int.EmitStatement (ec); - get_item_object.Release (ec); -#endif TableSwitchEmit (ec, string_switch_variable); string_switch_variable.Release (ec); } @@ -3775,12 +3821,10 @@ namespace Mono.CSharp { LocalTemporary value; if (HaveUnwrap) { value = new LocalTemporary (SwitchType); -#if GMCS_SOURCE unwrap.EmitCheck (ec); ig.Emit (OpCodes.Brfalse, null_target); new_expr.Emit (ec); value.Store (ec); -#endif } else if (!is_constant) { value = new LocalTemporary (SwitchType); new_expr.Emit (ec); @@ -3860,6 +3904,7 @@ namespace Mono.CSharp { public abstract class ExceptionStatement : ResumableStatement { bool code_follows; + Iterator iter; protected abstract void EmitPreTryBody (EmitContext ec); protected abstract void EmitTryBody (EmitContext ec); @@ -3873,7 +3918,7 @@ namespace Mono.CSharp { if (resume_points != null) { IntConstant.EmitInt (ig, (int) Iterator.State.Running); - ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC); + ig.Emit (OpCodes.Stloc, iter.CurrentPC); } ig.BeginExceptionBlock (); @@ -3883,7 +3928,7 @@ namespace Mono.CSharp { // For normal control flow, we want to fall-through the Switch // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above - ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC); + ig.Emit (OpCodes.Ldloc, iter.CurrentPC); IntConstant.EmitInt (ig, first_resume_pc); ig.Emit (OpCodes.Sub); @@ -3899,7 +3944,7 @@ namespace Mono.CSharp { Label start_finally = ec.ig.DefineLabel (); if (resume_points != null) { - ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally); + ig.Emit (OpCodes.Ldloc, iter.SkipFinally); ig.Emit (OpCodes.Brfalse_S, start_finally); ig.Emit (OpCodes.Endfinally); } @@ -3915,13 +3960,15 @@ namespace Mono.CSharp { code_follows = true; } - protected void ResolveReachability (EmitContext ec) + public override bool Resolve (BlockContext ec) { // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause // So, ensure there's some IL code after this statement. if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable) ec.NeedReturnLabel (); + iter = ec.CurrentIterator; + return true; } ArrayList resume_points; @@ -4025,14 +4072,14 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) return false; - if (expr.Type.IsValueType){ - Report.Error (185, loc, + if (!TypeManager.IsReferenceType (expr.Type)){ + ec.Report.Error (185, loc, "`{0}' is not a reference type as required by the lock statement", TypeManager.CSharpName (expr.Type)); return false; @@ -4042,7 +4089,7 @@ namespace Mono.CSharp { bool ok = Statement.Resolve (ec); ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); // Avoid creating libraries that reference the internal // mcs NullType: @@ -4054,7 +4101,7 @@ namespace Mono.CSharp { temp.Resolve (ec); if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) { - Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true); + Type monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", Kind.Class, true); TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod ( monitor_type, "Enter", loc, TypeManager.object_type); TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod ( @@ -4109,15 +4156,15 @@ namespace Mono.CSharp { b.Unchecked = true; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + using (ec.With (ResolveContext.Options.AllCheckStateFlags, false)) return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + using (ec.With (EmitContext.Options.AllCheckStateFlags, false)) Block.Emit (ec); } @@ -4143,15 +4190,15 @@ namespace Mono.CSharp { b.Unchecked = false; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) - return Block.Resolve (ec); + using (ec.With (ResolveContext.Options.AllCheckStateFlags, true)) + return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + using (ec.With (EmitContext.Options.AllCheckStateFlags, true)) Block.Emit (ec); } @@ -4175,18 +4222,21 @@ namespace Mono.CSharp { { Block = b; Block.Unsafe = true; + loc = b.StartLocation; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.InUnsafe, true)) + if (ec.CurrentIterator != null) + ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators"); + + using (ec.Set (ResolveContext.Options.UnsafeScope)) return Block.Resolve (ec); } protected override void DoEmit (EmitContext ec) { - using (ec.With (EmitContext.Flags.InUnsafe, true)) - Block.Emit (ec); + Block.Emit (ec); } public override void MutateHoistedGenericType (AnonymousMethodStorey storey) @@ -4250,81 +4300,52 @@ namespace Mono.CSharp { } } - 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; - } + class StringEmitter : Emitter + { + LocalInfo pinned_string; - 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); - } + public StringEmitter (Expression expr, LocalInfo li, Location loc): + base (expr, li) + { + pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc); + pinned_string.Pinned = true; + } - ILGenerator ig = ec.ig; + public StringEmitter Resolve (ResolveContext rc) + { + pinned_string.Resolve (rc); - 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); + if (TypeManager.int_get_offset_to_string_data == null) { + TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty ( + TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type); } - } - - LocalBuilder pinned_string; - Location loc; - public StringEmitter (Expression expr, LocalInfo li, Location loc): - base (expr, li) - { - this.loc = loc; + return this; } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type); - + 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; + // TODO: Should use Binary::Add + pinned_string.Emit (ec); + ec.ig.Emit (OpCodes.Conv_I); - converted.Emit (ec); + PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, TypeManager.int_get_offset_to_string_data, pinned_string.Location); + //pe.InstanceExpression = pinned_string; + pe.Resolve (new ResolveContext (ec.MemberContext)).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); } } @@ -4340,17 +4361,17 @@ namespace Mono.CSharp { get { return statement; } } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - if (!ec.InUnsafe){ - Expression.UnsafeError (loc); + if (!ec.IsUnsafe){ + Expression.UnsafeError (ec, loc); return false; } TypeExpr texpr = type.ResolveAsContextualType (ec, false); if (texpr == null) { if (type is VarExpr) - Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable"); + ec.Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable"); return false; } @@ -4360,7 +4381,7 @@ namespace Mono.CSharp { data = new Emitter [declarators.Count]; if (!expr_type.IsPointer){ - Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type"); + ec.Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type"); return false; } @@ -4384,50 +4405,14 @@ namespace Mono.CSharp { // if (e is Cast){ - Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); + ec.Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); return false; } - - // - // 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; + using (ec.Set (ResolveContext.Options.FixedInitializerScope)) { 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); - ec.InFixedInitializer = false; if (e == null) return false; @@ -4457,10 +4442,10 @@ namespace Mono.CSharp { // // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0]) // - converted = new Conditional (new Binary (Binary.Operator.LogicalOr, + converted = new Conditional (new BooleanExpression (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 Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc)))), + new NullPointer (loc), converted); converted = converted.Resolve (ec); @@ -4475,30 +4460,32 @@ namespace Mono.CSharp { // Case 3: string // if (e.Type == TypeManager.string_type){ - data [i] = new StringEmitter (e, vi, loc); + data [i] = new StringEmitter (e, vi, loc).Resolve (ec); i++; continue; } // 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) + ec.Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression"); + + e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc); } ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc); @@ -4596,7 +4583,11 @@ namespace Mono.CSharp { if (Name != null) { // TODO: Move to resolve LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc); - lvr.Resolve (ec); + lvr.Resolve (new ResolveContext (ec.MemberContext)); + + // Only to make verifier happy + if (TypeManager.IsGenericParameter (lvr.Type)) + ig.Emit (OpCodes.Unbox_Any, lvr.Type); Expression source; if (lvr.IsHoisted) { @@ -4615,9 +4606,9 @@ namespace Mono.CSharp { Block.Emit (ec); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - using (ec.With (EmitContext.Flags.InCatch, true)) { + using (ec.With (ResolveContext.Options.CatchScope, true)) { if (type_expr != null) { TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false); if (te == null) @@ -4626,7 +4617,7 @@ namespace Mono.CSharp { type = te.Type; if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){ - Error (155, "The type caught or thrown must be derived from System.Exception"); + ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception"); return false; } } else @@ -4676,7 +4667,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -4687,14 +4678,14 @@ namespace Mono.CSharp { if (ok) ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally); - using (ec.With (EmitContext.Flags.InFinally, true)) { + using (ec.With (ResolveContext.Options.FinallyScope, true)) { if (!fini.Resolve (ec)) ok = false; } ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); return ok; } @@ -4739,24 +4730,18 @@ namespace Mono.CSharp { { this.Block = block; this.Specific = catch_clauses; - this.General = null; this.inside_try_finally = inside_try_finally; - for (int i = 0; i < catch_clauses.Count; ++i) { - Catch c = (Catch) catch_clauses [i]; - if (c.IsGeneral) { - if (i != catch_clauses.Count - 1) - Report.Error (1017, c.loc, "Try statement already has an empty catch block"); - this.General = c; - catch_clauses.RemoveAt (i); - i--; - } + Catch c = (Catch) catch_clauses [0]; + if (c.IsGeneral) { + this.General = c; + catch_clauses.RemoveAt (0); } loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -4778,13 +4763,17 @@ namespace Mono.CSharp { vi.VariableInfo = null; } - if (!c.Resolve (ec)) + if (!c.Resolve (ec)) { ok = false; + continue; + } 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); + ec.Report.Error (160, c.loc, + "A previous catch clause already catches all exceptions of this or a super type `{0}'", + TypeManager.CSharpName (prev_catches [ii])); ok = false; } } @@ -4795,8 +4784,8 @@ namespace Mono.CSharp { if (General != null) { if (CodeGen.Assembly.WrapNonExceptionThrows) { foreach (Catch c in Specific){ - if (c.CatchType == TypeManager.exception_type) { - Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); + if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) { + ec.Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'"); } } } @@ -4868,6 +4857,7 @@ namespace Mono.CSharp { } } + // FIXME: Why is it almost exact copy of Using ?? public class UsingTemporary : ExceptionStatement { TemporaryVariable local_copy; public Statement Statement; @@ -4881,7 +4871,7 @@ namespace Mono.CSharp { loc = l; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { expr = expr.Resolve (ec); if (expr == null) @@ -4891,7 +4881,7 @@ namespace Mono.CSharp { if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) { if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { - Using.Error_IsNotConvertibleToIDisposable (expr); + Using.Error_IsNotConvertibleToIDisposable (ec, expr); return false; } } @@ -4905,7 +4895,7 @@ namespace Mono.CSharp { ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); if (TypeManager.void_dispose_void == null) { TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( @@ -4928,7 +4918,7 @@ namespace Mono.CSharp { 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); @@ -4938,8 +4928,8 @@ namespace Mono.CSharp { return; } - Expression ml = Expression.MemberLookup ( - ec.ContainerType, TypeManager.idisposable_type, expr_type, + Expression ml = Expression.MemberLookup (RootContext.ToplevelTypes.Compiler, + ec.CurrentType, TypeManager.idisposable_type, expr_type, "Dispose", Location.Null); if (!(ml is MethodGroupExpr)) { @@ -4959,7 +4949,7 @@ namespace Mono.CSharp { } if (mi == null) { - Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); + RootContext.ToplevelTypes.Compiler.Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters."); return; } @@ -4992,7 +4982,6 @@ namespace Mono.CSharp { Expression var; Expression init; - Expression converted_var; ExpressionStatement assign; public Using (Expression var, Expression init, Statement stmt, Location l) @@ -5003,36 +4992,11 @@ 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) + static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, Expression expr) { - Report.SymbolRelatedToPreviousError (expr.Type); - Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", - expr.GetSignatureForError ()); + ec.Report.SymbolRelatedToPreviousError (expr.Type); + ec.Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'", + TypeManager.CSharpName (expr.Type)); } protected override void EmitPreTryBody (EmitContext ec) @@ -5048,42 +5012,18 @@ 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; - } + } - IMemoryLocation mloc = (IMemoryLocation) var; + Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc); - mloc.AddressOf (ec, AddressOp.Load); - ig.Emit (OpCodes.Call, mi); - } - } + if (emit_null_check) + ig.MarkLabel (skip); } public override void MutateHoistedGenericType (AnonymousMethodStorey storey) @@ -5093,7 +5033,7 @@ namespace Mono.CSharp { stmt.MutateHoistedGenericType (storey); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { if (!ResolveVariable (ec)) return false; @@ -5104,7 +5044,7 @@ namespace Mono.CSharp { ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); if (TypeManager.void_dispose_void == null) { TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( @@ -5114,6 +5054,27 @@ namespace Mono.CSharp { return ok; } + bool ResolveVariable (BlockContext ec) + { + assign = new SimpleAssign (var, init, loc); + assign = assign.ResolveStatement (ec); + if (assign == null) + return false; + + if (assign.Type == TypeManager.idisposable_type || + TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) { + return true; + } + + Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location); + if (e == null) { + Error_IsNotConvertibleToIDisposable (ec, var); + return false; + } + + throw new NotImplementedException ("covariance?"); + } + protected override void CloneTo (CloneContext clonectx, Statement t) { Using target = (Using) t; @@ -5128,108 +5089,56 @@ namespace Mono.CSharp { /// Implementation of the foreach C# statement /// public class Foreach : Statement { - Expression type; - Expression variable; - Expression expr; - Statement statement; - - 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; - } - - if (expr.Type.IsArray) { - statement = new ArrayForeach (type, variable, expr, statement, loc); - } else { - statement = new CollectionForeach (type, variable, expr, statement, loc); - } - - return statement.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 (); - - statement.Emit (ec); - - ec.LoopBegin = old_begin; - ec.LoopEnd = old_end; - } + class ArrayCounter : TemporaryVariable + { + StatementExpression increment; - protected class ArrayCounter : TemporaryVariable - { - StatementExpression increment; + public ArrayCounter (Location loc) + : base (TypeManager.int32_type, loc) + { + } - public ArrayCounter (Location loc) - : base (TypeManager.int32_type, loc) - { - } + public void ResolveIncrement (BlockContext ec) + { + increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this)); + increment.Resolve (ec); + } - public void ResolveIncrement (EmitContext ec) - { - increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc)); - increment.Resolve (ec); + public void EmitIncrement (EmitContext ec) + { + increment.Emit (ec); + } } - public void EmitIncrement (EmitContext ec) - { - increment.Emit (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]; } protected override void CloneTo (CloneContext clonectx, Statement target) @@ -5237,41 +5146,36 @@ namespace Mono.CSharp { throw new NotImplementedException (); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { - array_type = expr.Type; - rank = array_type.GetArrayRank (); - - copy = new TemporaryVariable (array_type, loc); + copy = new TemporaryVariable (for_each.expr.Type, loc); copy.Resolve (ec); - counter = new ArrayCounter [rank]; - lengths = new TemporaryVariable [rank]; - length_exprs = new Expression [rank]; - - ArrayList list = new ArrayList (rank); + int rank = length_exprs.Length; + Arguments list = new Arguments (rank); for (int i = 0; i < rank; i++) { counter [i] = new ArrayCounter (loc); counter [i].ResolveIncrement (ec); - lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); - lengths [i].Resolve (ec); - if (rank == 1) { length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec); } else { - ArrayList args = new ArrayList (1); + lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc); + lengths [i].Resolve (ec); + + Arguments args = new Arguments (1); args.Add (new Argument (new IntConstant (i, loc))); length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec); } - list.Add (counter [i]); + list.Add (new Argument (counter [i])); } access = new ElementAccess (copy, list).Resolve (ec); 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 @@ -5291,8 +5195,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); + if (for_each.variable == null) ok = false; ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc); @@ -5312,8 +5216,9 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - copy.EmitAssign (ec, expr); + copy.EmitAssign (ec, for_each.expr); + int rank = length_exprs.Length; Label[] test = new Label [rank]; Label[] loop = new Label [rank]; @@ -5321,7 +5226,8 @@ namespace Mono.CSharp { test [i] = ig.DefineLabel (); loop [i] = ig.DefineLabel (); - lengths [i].EmitAssign (ec, length_exprs [i]); + if (lengths != null) + lengths [i].EmitAssign (ec, length_exprs [i]); } IntConstant zero = new IntConstant (0, loc); @@ -5332,7 +5238,7 @@ namespace Mono.CSharp { ig.MarkLabel (loop [i]); } - ((IAssignMethod) variable).EmitAssign (ec, conv, false, false); + ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false); statement.Emit (ec); @@ -5343,7 +5249,12 @@ namespace Mono.CSharp { 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]); } @@ -5352,20 +5263,78 @@ namespace Mono.CSharp { public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { + for_each.expr.MutateHoistedGenericType (storey); + copy.MutateHoistedGenericType (storey); conv.MutateHoistedGenericType (storey); - variable.MutateHoistedGenericType (storey); statement.MutateHoistedGenericType (storey); - for (int i = 0; i < rank; i++) { + for (int i = 0; i < counter.Length; i++) { counter [i].MutateHoistedGenericType (storey); - lengths [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 (BlockContext 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; @@ -5396,27 +5365,17 @@ namespace Mono.CSharp { throw new NotImplementedException (); } - bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi) + bool GetEnumeratorFilter (ResolveContext 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: @@ -5441,20 +5400,18 @@ 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 ( - ec.ContainerType, TypeManager.ienumerator_getcurrent, loc); + ec.CurrentType, TypeManager.ienumerator_getcurrent, loc); if (!FetchMoveNext (return_type)) move_next = TypeManager.bool_movenext_void; return true; } -#endif if (return_type.IsInterface || !FetchMoveNext (return_type) || @@ -5462,7 +5419,7 @@ namespace Mono.CSharp { enumerator_type = return_type; move_next = TypeManager.bool_movenext_void; get_current = new PropertyExpr ( - ec.ContainerType, TypeManager.ienumerator_getcurrent, loc); + ec.CurrentType, TypeManager.ienumerator_getcurrent, loc); return true; } } else { @@ -5472,7 +5429,7 @@ namespace Mono.CSharp { // if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) { - Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property", + ec.Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property", TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi)); return false; } @@ -5488,13 +5445,12 @@ 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) + "MoveNext", null); + + if (move_next_list == null) return false; foreach (MemberInfo m in move_next_list){ @@ -5513,10 +5469,10 @@ namespace Mono.CSharp { // // Retrieves a `public T get_Current ()' method from the Type `t' // - bool FetchGetCurrent (EmitContext ec, Type t) + bool FetchGetCurrent (ResolveContext ec, Type t) { - PropertyExpr pe = Expression.MemberLookup ( - ec.ContainerType, t, "Current", MemberTypes.Property, + PropertyExpr pe = Expression.MemberLookup (ec.Compiler, + ec.CurrentType, t, "Current", MemberTypes.Property, Expression.AllBindingFlags, loc) as PropertyExpr; if (pe == null) return false; @@ -5525,38 +5481,13 @@ 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; - } - - void Error_Enumerator () + void Error_Enumerator (BlockContext ec) { if (enumerator_found) { return; } - Report.Error (1579, loc, + ec.Report.Error (1579, loc, "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible", TypeManager.CSharpName (expr.Type)); } @@ -5574,10 +5505,10 @@ namespace Mono.CSharp { return base_method != m; } - bool TryType (EmitContext ec, Type t) + bool TryType (ResolveContext ec, Type t) { - MethodGroupExpr mg = Expression.MemberLookup ( - ec.ContainerType, t, "GetEnumerator", MemberTypes.Method, + MethodGroupExpr mg = Expression.MemberLookup (ec.Compiler, + ec.CurrentType, t, "GetEnumerator", MemberTypes.Method, Expression.AllBindingFlags, loc) as MethodGroupExpr; if (mg == null) return false; @@ -5608,8 +5539,8 @@ namespace Mono.CSharp { continue; MethodBase mb = TypeManager.DropGenericMethodArguments (mi); - Report.SymbolRelatedToPreviousError (t); - Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " + + ec.Report.SymbolRelatedToPreviousError (t); + ec.Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " + "because it contains multiple implementation of `{1}'. Try casting to a specific implementation", TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb)); return false; @@ -5621,9 +5552,9 @@ namespace Mono.CSharp { TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType)) continue; - Report.SymbolRelatedToPreviousError (result); - Report.SymbolRelatedToPreviousError (mi); - Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'", + ec.Report.SymbolRelatedToPreviousError (result); + ec.Report.SymbolRelatedToPreviousError (mi); + ec.Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'", TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi)); return false; } @@ -5657,18 +5588,18 @@ namespace Mono.CSharp { } return false; - } + } - bool ProbeCollectionType (EmitContext ec, Type t) + bool ProbeCollectionType (ResolveContext ec, Type t) { - int errors = Report.Errors; + int errors = ec.Report.Errors; for (Type tt = t; tt != null && tt != TypeManager.object_type;){ if (TryType (ec, tt)) return true; tt = tt.BaseType; } - if (Report.Errors > errors) + if (ec.Report.Errors > errors) return false; // @@ -5683,18 +5614,15 @@ namespace Mono.CSharp { return false; } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { enumerator_type = TypeManager.ienumerator_type; if (!ProbeCollectionType (ec, expr.Type)) { - Error_Enumerator (); + Error_Enumerator (ec); 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 @@ -5727,11 +5655,16 @@ namespace Mono.CSharp { Statement block = new CollectionForeachStatement ( var_type.Type, variable, get_current, statement, loc); - loop = new While (move_next_expr, block, loc); + loop = new While (new BooleanExpression (move_next_expr), block, loc); + + + 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); + } - wrapper = is_disposable ? - (Statement) new DisposableWrapper (this) : - (Statement) new NonDisposableWrapper (this); return wrapper.Resolve (ec); } @@ -5753,7 +5686,7 @@ namespace Mono.CSharp { throw new NotSupportedException (); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { return parent.ResolveLoop (ec); } @@ -5770,12 +5703,15 @@ namespace Mono.CSharp { } } - 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) @@ -5783,7 +5719,7 @@ namespace Mono.CSharp { throw new NotSupportedException (); } - public override bool Resolve (EmitContext ec) + public override bool Resolve (BlockContext ec) { bool ok = true; @@ -5794,7 +5730,7 @@ namespace Mono.CSharp { ec.EndFlowBranching (); - ResolveReachability (ec); + ok &= base.Resolve (ec); if (TypeManager.void_dispose_void == null) { TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod ( @@ -5815,7 +5751,30 @@ 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, null, loc); } public override void MutateHoistedGenericType (AnonymousMethodStorey storey) @@ -5824,7 +5783,7 @@ namespace Mono.CSharp { } } - bool ResolveLoop (EmitContext ec) + bool ResolveLoop (BlockContext ec) { return loop.Resolve (ec); } @@ -5839,37 +5798,6 @@ namespace Mono.CSharp { loop.Emit (ec); } - void EmitFinallyBody (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (enumerator_type.IsValueType) { - MethodInfo mi = FetchMethodDispose (enumerator_type); - if (mi != null) { - enumerator.AddressOf (ec, AddressOp.Load); - 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.Emit (ec); - ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type); - ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Brtrue_S, call_dispose); - - // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block - // (Partition III, Section 3.35) - ig.Emit (OpCodes.Endfinally); - - ig.MarkLabel (call_dispose); - ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void); - } - } - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { enumerator_type = storey.MutateType (enumerator_type); @@ -5878,60 +5806,65 @@ namespace Mono.CSharp { } } - protected class CollectionForeachStatement : Statement + Expression type; + Expression variable; + Expression expr; + Statement statement; + + public Foreach (Expression type, LocalVariableReference var, Expression expr, + Statement stmt, Location l) { - Type type; - Expression variable, current, conv; - Statement statement; - Assign assign; + this.type = type; + this.variable = var; + this.expr = expr; + statement = stmt; + loc = l; + } - 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; - } + public Statement Statement { + get { return statement; } + } - protected override void CloneTo (CloneContext clonectx, Statement target) - { - throw new NotImplementedException (); + public override bool Resolve (BlockContext ec) + { + expr = expr.Resolve (ec); + if (expr == null) + return false; + + if (expr.IsNull) { + ec.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) { + ec.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); - public override void MutateHoistedGenericType (AnonymousMethodStorey storey) - { - assign.MutateHoistedGenericType (storey); - statement.MutateHoistedGenericType (storey); - } + ec.LoopBegin = old_begin; + ec.LoopEnd = old_end; } protected override void CloneTo (CloneContext clonectx, Statement t)