X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fstatement.cs;h=5fe7e02470cb4aaf593ddac59a3412f867db8158;hb=bd316288ae3fa0cb6f03b367716d04d5244c5d04;hp=dde59346b9b6e973b46ae3cc156debdac5abd431;hpb=569026428aa0d2db5167f63f51abc2819d78d631;p=mono.git diff --git a/mcs/gmcs/statement.cs b/mcs/gmcs/statement.cs index dde59346b9b..5fe7e02470c 100644 --- a/mcs/gmcs/statement.cs +++ b/mcs/gmcs/statement.cs @@ -14,10 +14,10 @@ using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Diagnostics; +using System.Collections; +using System.Collections.Specialized; namespace Mono.CSharp { - - using System.Collections; public abstract class Statement { public Location loc; @@ -80,7 +80,7 @@ namespace Mono.CSharp { public void Error (int error, string s) { - if (!Location.IsNull (loc)) + if (!loc.IsNull) Report.Error (error, loc, s); else Report.Error (error, s); @@ -410,7 +410,7 @@ namespace Mono.CSharp { Expression Test; readonly Statement InitStatement; readonly Statement Increment; - readonly Statement Statement; + public readonly Statement Statement; bool infinite, empty; public For (Statement initStatement, @@ -527,10 +527,10 @@ namespace Mono.CSharp { public class StatementExpression : Statement { ExpressionStatement expr; - public StatementExpression (ExpressionStatement expr, Location l) + public StatementExpression (ExpressionStatement expr) { this.expr = expr; - loc = l; + loc = expr.Location; } public override bool Resolve (EmitContext ec) @@ -577,16 +577,16 @@ namespace Mono.CSharp { if (ec.ReturnType == null){ if (Expr != null){ if (ec.CurrentAnonymousMethod != null){ - Report.Error (1662, loc, String.Format ( - "Anonymous method could not be converted to delegate " + - "since the return value does not match the delegate value")); + Report.Error (1662, loc, + "Cannot convert anonymous method block to delegate type `{0}' because some of the return types in the block are not implicitly convertible to the delegate return type", + ec.CurrentAnonymousMethod.GetSignatureForError ()); } - Error (127, "Return with a value not allowed here"); + Error (127, "A return keyword must not be followed by any expression when method returns void"); return false; } } else { if (Expr == null){ - Error (126, "An object of type `{0}' is expected " + + Error (126, "An object of a type convertible to `{0}' is required " + "for the return statement", TypeManager.CSharpName (ec.ReturnType)); return false; @@ -610,7 +610,7 @@ namespace Mono.CSharp { ec.CurrentBranching.AddFinallyVector (vector); in_exc = true; } else if (ec.InFinally) { - Error (157, "Control can not leave the body of the finally block"); + Error (157, "Control cannot leave the body of a finally clause"); return false; } else vector.CheckOutParameters (ec.CurrentBranching); @@ -678,7 +678,6 @@ namespace Mono.CSharp { } public class LabeledStatement : Statement { - public readonly Location Location; bool defined; bool referenced; Label label; @@ -688,7 +687,7 @@ namespace Mono.CSharp { public LabeledStatement (string label_name, Location l) { - this.Location = l; + this.loc = l; } public Label LabelTarget (EmitContext ec) @@ -731,7 +730,8 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { if (ig != null && ig != ec.ig) { - Report.Error (1632, "Control cannot leave body of anonymous method"); + // TODO: location is wrong + Report.Error (1632, loc, "Control cannot leave the body of an anonymous method"); return; } LabelTarget (ec); @@ -764,12 +764,12 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { if (ec.Switch == null){ - Report.Error (153, loc, "goto default is only valid in a switch statement"); + Report.Error (153, loc, "A goto case is only valid inside a switch statement"); return; } if (!ec.Switch.GotDefault){ - Report.Error (159, loc, "No default target on switch statement"); + Report.Error (159, loc, "No such label `default:' within the scope of the goto statement"); return; } ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget); @@ -792,7 +792,7 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { if (ec.Switch == null){ - Report.Error (153, loc, "goto case is only valid in a switch statement"); + Report.Error (153, loc, "A goto case is only valid inside a switch statement"); return false; } @@ -800,23 +800,24 @@ namespace Mono.CSharp { if (expr == null) return false; - if (!(expr is Constant)){ - Report.Error (159, loc, "Target expression for goto case is not constant"); + Constant c = expr as Constant; + if (c == null) { + Error (150, "A constant value is expected"); return false; } - object val = Expression.ConvertIntLiteral ( - (Constant) expr, ec.Switch.SwitchType, loc); + c = c.ToType (ec.Switch.SwitchType, loc); + if (c == null) + return false; + object val = c.GetValue (); if (val == null) - return false; + val = c; sl = (SwitchLabel) ec.Switch.Elements [val]; if (sl == null){ - Report.Error ( - 159, loc, - "No such label 'case " + val + "': for the goto case"); + Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val); return false; } @@ -852,15 +853,15 @@ namespace Mono.CSharp { if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess || eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) { - expr.Error_UnexpectedKind ("value, variable, property or indexer access ", loc); + expr.Error_UnexpectedKind (ec, "value, variable, property or indexer access ", loc); return false; } Type t = expr.Type; - + if ((t != TypeManager.exception_type) && - !t.IsSubclassOf (TypeManager.exception_type) && - !(expr is NullLiteral)) { + !TypeManager.IsSubclassOf (t, TypeManager.exception_type) && + !(expr is NullLiteral)) { Error (155, "The type caught or thrown must be derived " + "from System.Exception"); @@ -875,7 +876,7 @@ namespace Mono.CSharp { } if (ec.InFinally) { - Error (724, "A throw statement with no argument is only allowed in a catch clause nested inside of the innermost catch clause"); + Error (724, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause"); return false; } return true; @@ -905,10 +906,10 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ - Error (139, "No enclosing loop or switch to continue to"); + Error (139, "No enclosing loop out of which to break or continue"); return false; } else if (ec.InFinally && ec.CurrentBranching.BreakCrossesTryCatchBoundary()) { - Error (157, "Control can not leave the body of the finally block"); + Error (157, "Control cannot leave the body of a finally clause"); return false; } else if (ec.CurrentBranching.InTryOrCatch (false)) ec.CurrentBranching.AddFinallyVector ( @@ -949,11 +950,11 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ - Error (139, "No enclosing loop to continue to"); + if (!ec.CurrentBranching.InLoop ()){ + Error (139, "No enclosing loop out of which to break or continue"); return false; } else if (ec.InFinally) { - Error (157, "Control can not leave the body of the finally block"); + Error (157, "Control cannot leave the body of a finally clause"); return false; } else if (ec.CurrentBranching.InTryOrCatch (false)) ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector); @@ -1069,28 +1070,16 @@ namespace Mono.CSharp { } if (VariableType.IsAbstract && VariableType.IsSealed) { - Report.Error (723, Location, "Cannot declare variable of static type '{0}'", TypeManager.CSharpName (VariableType)); + Report.Error (723, Location, "Cannot declare variable of static type `{0}'", TypeManager.CSharpName (VariableType)); return false; } -// TODO: breaks the build -// if (VariableType.IsPointer && !ec.InUnsafe) -// Expression.UnsafeError (Location); + + if (VariableType.IsPointer && !ec.InUnsafe) + Expression.UnsafeError (Location); return true; } - // - // Whether the variable is Fixed (because its Pinned or its a value type) - // - public bool IsFixed { - get { - if (((flags & Flags.Pinned) != 0) || TypeManager.IsValueType (VariableType)) - return true; - - return false; - } - } - public bool IsCaptured { get { return (flags & Flags.Captured) != 0; @@ -1209,53 +1198,31 @@ namespace Mono.CSharp { public readonly ToplevelBlock Toplevel; [Flags] - public enum Flags { + public enum Flags : ushort { Implicit = 1, Unchecked = 2, BlockUsed = 4, VariablesInitialized = 8, HasRet = 16, IsDestructor = 32, - HasVarargs = 64, - IsToplevel = 128, - Unsafe = 256 + IsToplevel = 64, + Unsafe = 128, + HasVarargs = 256 // Used in ToplevelBlock } - Flags flags; + protected Flags flags; public bool Implicit { - get { - return (flags & Flags.Implicit) != 0; - } + get { return (flags & Flags.Implicit) != 0; } } public bool Unchecked { - get { - return (flags & Flags.Unchecked) != 0; - } - set { - flags |= Flags.Unchecked; - } + get { return (flags & Flags.Unchecked) != 0; } + set { flags |= Flags.Unchecked; } } public bool Unsafe { - get { - return (flags & Flags.Unsafe) != 0; - } - set { - flags |= Flags.Unsafe; - } - } - - public bool HasVarargs { - get { - if (Parent != null) - return Parent.HasVarargs; - else - return (flags & Flags.HasVarargs) != 0; - } - set { - flags |= Flags.HasVarargs; - } + get { return (flags & Flags.Unsafe) != 0; } + set { flags |= Flags.Unsafe; } } // @@ -1348,8 +1315,14 @@ namespace Mono.CSharp { } public int ID { + get { return this_id; } + } + + protected Hashtable Variables { get { - return this_id; + if (variables == null) + variables = new Hashtable (); + return variables; } } @@ -1384,7 +1357,7 @@ namespace Mono.CSharp { while (cur != null) { if (cur.DoLookupLabel (name) != null) { Report.Error ( - 140, loc, "The label '{0}' is a duplicate", + 140, loc, "The label `{0}' is a duplicate", name); return false; } @@ -1399,8 +1372,8 @@ namespace Mono.CSharp { if (cur.DoLookupLabel (name) != null) { Report.Error ( 158, loc, - "The label '{0}' shadows another label " + - "by the same name in a containing scope.", + "The label `{0}' shadows another label " + + "by the same name in a contained scope.", name); return false; } @@ -1412,10 +1385,10 @@ namespace Mono.CSharp { continue; Report.Error ( - 158, s.Location, - "The label '{0}' shadows another " + + 158, s.loc, + "The label `{0}' shadows another " + "label by the same name in a " + - "containing scope.", + "contained scope.", name); return false; } @@ -1465,23 +1438,6 @@ namespace Mono.CSharp { return null; } - LocalInfo this_variable = null; - - // - // Returns the "this" instance variable of this block. - // See AddThisVariable() for more information. - // - public LocalInfo ThisVariable { - get { - for (Block b = this; b != null; b = b.Parent) { - if (b.this_variable != null) - return b.this_variable; - } - - return null; - } - } - Hashtable known_variables; // @@ -1506,94 +1462,91 @@ namespace Mono.CSharp { public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { - LocalInfo kvi = GetKnownVariableInfo (name); - if (kvi == null || kvi.Block == this) + Block b = this; + LocalInfo kvi = b.GetKnownVariableInfo (name); + while (kvi == null) { + while (b.Implicit) + b = b.Parent; + b = b.Parent; + if (b == null) + return true; + kvi = b.GetKnownVariableInfo (name); + } + + if (kvi.Block == b) return true; - if (known_variables != kvi.Block.known_variables) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Report.Error (135, loc, "'{0}' has a different meaning in a child block", name); - return false; + // Is kvi.Block nested inside 'b' + if (b.known_variables != kvi.Block.known_variables) { + // + // If a variable by the same name it defined in a nested block of this + // 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); + return false; + } + + // + // It's ok if the definition is in a nested subblock of b, but not + // nested inside this block -- a definition in a sibling block + // should not affect us. + // + return true; } // - // this block and kvi.Block are the same textual block. + // Block 'b' and kvi.Block are the same textual block. // However, different variables are extant. // // Check if the variable is in scope in both blocks. We use // an indirect check that depends on AddVariable doing its // part in maintaining the invariant-meaning-in-block property. // - if (e is LocalVariableReference || (e is Constant && GetLocalInfo (name) != null)) + if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Report.Error (136, loc, "'{0}' has a different meaning later in the block", name); + // + // 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); + Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; } - // - // This is used by non-static `struct' constructors which do not have an - // initializer - in this case, the constructor must initialize all of the - // struct's fields. To do this, we add a "this" variable and use the flow - // analysis code to ensure that it's been fully initialized before control - // leaves the constructor. - // - public LocalInfo AddThisVariable (TypeContainer tc, Location l) - { - if (this_variable != null) - return this_variable; - - if (variables == null) - variables = new Hashtable (); - - this_variable = new LocalInfo (tc, this, l); - this_variable.Used = true; - this_variable.IsThis = true; - - variables.Add ("this", this_variable); - - return this_variable; - } - public LocalInfo AddVariable (Expression type, string name, Location l) { - if (variables == null) - variables = new Hashtable (); - LocalInfo vi = GetLocalInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); if (known_variables == vi.Block.known_variables) Report.Error (128, l, - "A local variable '{0}' is already declared in this scope", name); + "A local variable named `{0}' is already defined in this scope", name); else - Report.Error (136, l, - "'{0}' hides the declaration of local variable '{0}' in a parent scope", name); + Error_AlreadyDeclared (l, name, "parent"); return null; } vi = GetKnownVariableInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); - Report.Error (136, l, - "A child block already has a declaration of local variable '{0}':" + - " allowing this declaration would violate 'invariant meaning in a block'", - name); + Error_AlreadyDeclared (l, name, "child"); return null; } int idx; Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx); if (p != null) { - Report.SymbolRelatedToPreviousError (Toplevel.Parameters.Location, name); - Report.Error (136, l, "'{0}' hides a method parameter", name); + Report.SymbolRelatedToPreviousError (p.Location, name); + Error_AlreadyDeclared (l, name, "method argument"); return null; } vi = new LocalInfo (type, name, this, l); - variables.Add (name, vi); + Variables.Add (name, vi); for (Block b = this; b != null; b = b.Parent) b.AddKnownVariable (name, vi); @@ -1601,10 +1554,15 @@ namespace Mono.CSharp { if ((flags & Flags.VariablesInitialized) != 0) throw new Exception (); - // Console.WriteLine ("Adding {0} to {1}", name, ID); return vi; } + void Error_AlreadyDeclared (Location loc, string var, string reason) + { + 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", var, reason); + } + public bool AddConstant (Expression type, string name, Expression value, Location l) { if (AddVariable (type, name, l) == null) @@ -1633,12 +1591,6 @@ namespace Mono.CSharp { return li; } - public Hashtable Variables { - get { - return variables; - } - } - public LocalInfo GetLocalInfo (string name) { for (Block b = this; b != null; b = b.Parent) { @@ -1654,11 +1606,7 @@ namespace Mono.CSharp { public Expression GetVariableType (string name) { LocalInfo vi = GetLocalInfo (name); - - if (vi != null) - return vi.Type; - - return null; + return vi == null ? null : vi.Type; } public Expression GetConstantExpression (string name) @@ -1678,22 +1626,10 @@ namespace Mono.CSharp { /// public bool IsConstant (string name) { - Expression e = null; - - e = GetConstantExpression (name); - + Expression e = GetConstantExpression (name); return e != null; } - /// - /// A list of labels that were not used within this block - /// - public string [] GetUnreferenced () - { - // FIXME: Implement me - return null; - } - public void AddStatement (Statement s) { statements.Add (s); @@ -1701,9 +1637,7 @@ namespace Mono.CSharp { } public bool Used { - get { - return (flags & Flags.BlockUsed) != 0; - } + get { return (flags & Flags.BlockUsed) != 0; } } public void Use () @@ -1712,15 +1646,11 @@ namespace Mono.CSharp { } public bool HasRet { - get { - return (flags & Flags.HasRet) != 0; - } + get { return (flags & Flags.HasRet) != 0; } } public bool IsDestructor { - get { - return (flags & Flags.IsDestructor) != 0; - } + get { return (flags & Flags.IsDestructor) != 0; } } public void SetDestructor () @@ -1827,16 +1757,13 @@ namespace Mono.CSharp { Constant ce = e as Constant; if (ce == null){ - Report.Error (133, vi.Location, - "The expression being assigned to '{0}' must be constant", name); + Const.Error_ExpressionMustBeConstant (vi.Location, name); continue; } - if (e.Type != variable_type){ - e = Const.ChangeType (vi.Location, ce, variable_type); - if (e == null) - continue; - } + e = ce.ToType (variable_type, vi.Location); + if (e == null) + continue; constants.Remove (name); constants.Add (name, e); @@ -1919,9 +1846,9 @@ namespace Mono.CSharp { name = (string) de.Key; if (vector.IsAssigned (vi.VariableInfo)){ - Report.Warning (219, vi.Location, "The variable '{0}' is assigned but its value is never used", name); + Report.Warning (219, vi.Location, "The variable `{0}' is assigned but its value is never used", name); } else { - Report.Warning (168, vi.Location, "The variable '{0}' is declared but never used", name); + Report.Warning (168, vi.Location, "The variable `{0}' is declared but never used", name); } } } @@ -1930,6 +1857,36 @@ namespace Mono.CSharp { bool unreachable_shown; bool unreachable; + private void CheckPossibleMistakenEmptyStatement (Statement s) + { + Statement body; + + // Some statements are wrapped by a Block. Since + // others' internal could be changed, here I treat + // them as possibly wrapped by Block equally. + Block b = s as Block; + if (b != null && b.statements.Count == 1) + s = (Statement) b.statements [0]; + + if (s is Lock) + body = ((Lock) s).Statement; + else if (s is For) + body = ((For) s).Statement; + else if (s is Foreach) + body = ((Foreach) s).Statement; + else if (s is While) + body = ((While) s).Statement; + else if (s is Using) + body = ((Using) s).Statement; + else if (s is Fixed) + body = ((Fixed) s).Statement; + else + return; + + if (body == null || body is EmptyStatement) + Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); + } + public override bool Resolve (EmitContext ec) { Block prev_block = ec.CurrentBlock; @@ -1951,6 +1908,11 @@ namespace Mono.CSharp { int statement_count = statements.Count; for (int ix = 0; ix < statement_count; ix++){ Statement s = (Statement) statements [ix]; + // Check possible empty statement (CS0642) + if (RootContext.WarningLevel >= 3 && + ix + 1 < statement_count && + statements [ix + 1] is Block) + CheckPossibleMistakenEmptyStatement (s); if (unreachable) { if (s is Block) @@ -1988,15 +1950,15 @@ namespace Mono.CSharp { // If we're a non-static `struct' constructor which doesn't have an // initializer, then we must initialize all of the struct's fields. - if ((this_variable != null) && - (vector.Reachability.Throws != FlowBranching.FlowReturns.Always) && - !this_variable.IsThisAssigned (ec, loc)) + if ((flags & Flags.IsToplevel) != 0 && + !Toplevel.IsThisAssigned (ec) && + vector.Reachability.Throws != FlowBranching.FlowReturns.Always) ok = false; if ((labels != null) && (RootContext.WarningLevel >= 2)) { foreach (LabeledStatement label in labels.Values) if (!label.HasBeenReferenced) - Report.Warning (164, label.Location, + Report.Warning (164, label.loc, "This label has not been referenced"); } @@ -2124,11 +2086,19 @@ namespace Mono.CSharp { Hashtable capture_contexts; ArrayList children; + public bool HasVarargs { + get { return (flags & Flags.HasVarargs) != 0; } + set { flags |= Flags.HasVarargs; } + } + // // The parameters for the block. // - public readonly Parameters Parameters; - + Parameters parameters; + public Parameters Parameters { + get { return parameters; } + } + public void RegisterCaptureContext (CaptureContext cc) { if (capture_contexts == null) @@ -2147,15 +2117,11 @@ namespace Mono.CSharp { } public CaptureContext ToplevelBlockCaptureContext { - get { - return capture_context; - } + get { return capture_context; } } public ToplevelBlock Container { - get { - return container; - } + get { return container; } } protected void AddChild (ToplevelBlock block) @@ -2188,7 +2154,7 @@ namespace Mono.CSharp { public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) : base (null, flags | Flags.IsToplevel, start, Location.Null) { - Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; + this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters; this.container = container; if (container != null) @@ -2206,15 +2172,11 @@ namespace Mono.CSharp { } public CaptureContext CaptureContext { - get { - return capture_context; - } + get { return capture_context; } } public FlowBranching TopLevelBranching { - get { - return top_level_branching; - } + get { return top_level_branching; } } // @@ -2276,6 +2238,42 @@ namespace Mono.CSharp { return false; } + LocalInfo this_variable = null; + + // + // Returns the "this" instance variable of this block. + // See AddThisVariable() for more information. + // + public LocalInfo ThisVariable { + get { return this_variable; } + } + + + // + // This is used by non-static `struct' constructors which do not have an + // initializer - in this case, the constructor must initialize all of the + // struct's fields. To do this, we add a "this" variable and use the flow + // analysis code to ensure that it's been fully initialized before control + // leaves the constructor. + // + public LocalInfo AddThisVariable (TypeContainer tc, Location l) + { + if (this_variable == null) { + this_variable = new LocalInfo (tc, this, l); + this_variable.Used = true; + this_variable.IsThis = true; + + Variables.Add ("this", this_variable); + } + + return this_variable; + } + + public bool IsThisAssigned (EmitContext ec) + { + return this_variable == null || this_variable.IsThisAssigned (ec, loc); + } + public bool ResolveMeta (EmitContext ec, InternalParameters ip) { int errors = Report.Errors; @@ -2283,6 +2281,9 @@ namespace Mono.CSharp { if (top_level_branching != null) return true; + if (ip != null) + parameters = ip.Parameters; + ResolveMeta (this, ec, ip); top_level_branching = ec.StartFlowBranching (this); @@ -2294,7 +2295,7 @@ namespace Mono.CSharp { public class SwitchLabel { Expression label; object converted; - public Location loc; + Location loc; Label il_label; bool il_label_set; @@ -2345,33 +2346,43 @@ namespace Mono.CSharp { // and then converts it to the requested type. // public bool ResolveAndReduce (EmitContext ec, Type required_type) - { - if (label == null) - return true; - + { Expression e = label.Resolve (ec); if (e == null) return false; - if (!(e is Constant)){ - Report.Error (150, loc, "A constant value is expected, got: " + e); + Constant c = e as Constant; + if (c == null){ + Report.Error (150, loc, "A constant value is expected"); return false; } - if (e is StringConstant || e is NullLiteral){ - if (required_type == TypeManager.string_type){ - converted = e; - return true; - } + if (required_type == TypeManager.string_type && e is NullLiteral) { + converted = e; + return true; } - converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc); - if (converted == null) + c = c.ToType (required_type, loc); + if (c == null) return false; + converted = c.GetValue (); return true; } + + public void Erorr_AlreadyOccurs () + { + string label; + if (converted == null) + label = "default"; + else if (converted is NullLiteral) + label = "null"; + else + label = converted.ToString (); + + Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); + } } public class SwitchSection { @@ -2393,7 +2404,7 @@ namespace Mono.CSharp { /// /// Maps constants whose type type SwitchType to their SwitchLabels. /// - public Hashtable Elements; + public IDictionary Elements; /// /// The governing switch type @@ -2442,33 +2453,33 @@ namespace Mono.CSharp { // Expression SwitchGoverningType (EmitContext ec, Type t) { - if (t == TypeManager.int32_type || - t == TypeManager.uint32_type || - t == TypeManager.char_type || - t == TypeManager.byte_type || + if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.ushort_type || t == TypeManager.short_type || + t == TypeManager.uint32_type || + t == TypeManager.int32_type || t == TypeManager.uint64_type || t == TypeManager.int64_type || + t == TypeManager.char_type || t == TypeManager.string_type || - t == TypeManager.bool_type || - t.IsSubclassOf (TypeManager.enum_type)) + t == TypeManager.bool_type || + t.IsSubclassOf (TypeManager.enum_type)) return Expr; if (allowed_types == null){ allowed_types = new Type [] { - TypeManager.int32_type, - TypeManager.uint32_type, TypeManager.sbyte_type, TypeManager.byte_type, TypeManager.short_type, TypeManager.ushort_type, + TypeManager.int32_type, + TypeManager.uint32_type, TypeManager.int64_type, TypeManager.uint64_type, TypeManager.char_type, - TypeManager.bool_type, - TypeManager.string_type + TypeManager.string_type, + TypeManager.bool_type }; } @@ -2490,32 +2501,22 @@ namespace Mono.CSharp { // Ignore over-worked ImplicitUserConversions that do // an implicit conversion in addition to the user conversion. // - if (e is UserCast){ - UserCast ue = e as UserCast; + if (!(e is UserCast)) + continue; - if (ue.Source != Expr) - e = null; - } - if (converted != null){ Report.ExtraInformation ( loc, String.Format ("reason: more than one conversion to an integral type exist for type {0}", TypeManager.CSharpName (Expr.Type))); return null; - } else { - converted = e; } + + converted = e; } return converted; } - static string Error152 { - get { - return "The label '{0}:' already occurs in this switch statement"; - } - } - // // Performs the basic sanity checks on the switch statement // (looks for duplicate keys and non-constant expressions). @@ -2525,141 +2526,38 @@ namespace Mono.CSharp { // bool CheckSwitch (EmitContext ec) { - Type compare_type; bool error = false; - Elements = new Hashtable (); + Elements = Sections.Count > 10 ? + (IDictionary)new Hashtable () : + (IDictionary)new ListDictionary (); - if (TypeManager.IsEnumType (SwitchType)){ - compare_type = TypeManager.EnumToUnderlying (SwitchType); - } else - compare_type = SwitchType; - foreach (SwitchSection ss in Sections){ foreach (SwitchLabel sl in ss.Labels){ - if (!sl.ResolveAndReduce (ec, SwitchType)){ - error = true; - continue; - } - if (sl.Label == null){ if (default_section != null){ - Report.Error (152, sl.loc, Error152, "default"); + sl.Erorr_AlreadyOccurs (); error = true; } default_section = ss; continue; } - - object key = sl.Converted; - - if (key is Constant) - key = ((Constant) key).GetValue (); - - if (key == null) - key = NullLiteral.Null; - - string lname = null; - if (compare_type == TypeManager.uint64_type){ - ulong v = (ulong) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.int64_type){ - long v = (long) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.uint32_type){ - uint v = (uint) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.char_type){ - char v = (char) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.byte_type){ - byte v = (byte) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.sbyte_type){ - sbyte v = (sbyte) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.short_type){ - short v = (short) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.ushort_type){ - ushort v = (ushort) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.string_type){ - if (key is NullLiteral){ - if (Elements.Contains (NullLiteral.Null)) - lname = "null"; - else - Elements.Add (NullLiteral.Null, null); - } else { - string s = (string) key; - - if (Elements.Contains (s)) - lname = s; - else - Elements.Add (s, sl); - } - } else if (compare_type == TypeManager.int32_type) { - int v = (int) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.bool_type) { - bool v = (bool) key; - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } - else - { - throw new Exception ("Unknown switch type!" + - SwitchType + " " + compare_type); - } - - if (lname != null){ - Report.Error (152, sl.loc, Error152, "case " + lname); + if (!sl.ResolveAndReduce (ec, SwitchType)){ error = true; + continue; } + + object key = sl.Converted; + try { + Elements.Add (key, sl); + } + catch (ArgumentException) { + sl.Erorr_AlreadyOccurs (); + error = true; + } } } - if (error) - return false; - - return true; + return !error; } void EmitObjectInteger (ILGenerator ig, object k) @@ -3003,12 +2901,10 @@ namespace Mono.CSharp { if (label_count == 1) ig.Emit (OpCodes.Br, next_test); continue; - } - StringConstant str = (StringConstant) lit; ig.Emit (OpCodes.Ldloc, val); - ig.Emit (OpCodes.Ldstr, str.Value); + ig.Emit (OpCodes.Ldstr, (string)lit); if (label_count == 1) ig.Emit (OpCodes.Bne_Un, next_test); else { @@ -3060,7 +2956,7 @@ namespace Mono.CSharp { new_expr = SwitchGoverningType (ec, Expr.Type); if (new_expr == null){ - Report.Error (151, loc, "An integer type or string was expected for switch"); + Report.Error (151, loc, "A value of an integral type or string expected for switch"); return false; } @@ -3191,7 +3087,7 @@ namespace Mono.CSharp { public class Lock : ExceptionStatement { Expression expr; - Statement Statement; + public Statement Statement; LocalBuilder temp; public Lock (Expression expr, Statement stmt, Location l) @@ -3208,9 +3104,9 @@ namespace Mono.CSharp { return false; if (expr.Type.IsValueType){ - Error (185, "lock statement requires the expression to be " + - " a reference type (type is: `{0}'", - TypeManager.CSharpName (expr.Type)); + Report.Error (185, loc, + "`{0}' is not a reference type as required by the lock statement", + TypeManager.CSharpName (expr.Type)); return false; } @@ -3462,6 +3358,10 @@ namespace Mono.CSharp { loc = l; } + public Statement Statement { + get { return statement; } + } + public override bool Resolve (EmitContext ec) { if (!ec.InUnsafe){ @@ -3480,7 +3380,7 @@ namespace Mono.CSharp { data = new Emitter [declarators.Count]; if (!expr_type.IsPointer){ - Report.Error (209, loc, "Variables in a fixed statement must be pointers"); + Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type"); return false; } @@ -3504,7 +3404,7 @@ namespace Mono.CSharp { // if (e is Cast){ - Report.Error (254, loc, "Cast expression not allowed as right hand expression in fixed statement"); + Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression"); return false; } @@ -3772,7 +3672,7 @@ namespace Mono.CSharp { Type resolvedType = c.CatchType; for (int ii = 0; ii < last_index; ++ii) { if (resolvedType == prevCatches [ii] || resolvedType.IsSubclassOf (prevCatches [ii])) { - Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type '{0}'", prevCatches [ii].FullName); + Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prevCatches [ii].FullName); return false; } } @@ -3856,6 +3756,11 @@ namespace Mono.CSharp { throw new Exception ("Variable does not exist in this block"); ig.Emit (OpCodes.Stloc, vi.LocalBuilder); + if (vi.IsCaptured){ + ec.EmitCapturedVariableInstance (vi); + ig.Emit (OpCodes.Ldloc, vi.LocalBuilder); + ig.Emit (OpCodes.Stfld, vi.FieldBuilder); + } } else ig.Emit (OpCodes.Pop); @@ -3889,7 +3794,7 @@ namespace Mono.CSharp { public class Using : ExceptionStatement { object expression_or_block; - Statement Statement; + public Statement Statement; ArrayList var_list; Expression expr; Type expr_type; @@ -3933,7 +3838,7 @@ namespace Mono.CSharp { foreach (DictionaryEntry e in var_list){ Expression var = (Expression) e.Key; - var = var.ResolveLValue (ec, new EmptyExpression ()); + var = var.ResolveLValue (ec, new EmptyExpression (), loc); if (var == null) return false; @@ -3977,7 +3882,7 @@ namespace Mono.CSharp { { if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){ if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) { - Report.Error (1674, loc, "'{0}': type used in a using statement must be implicitly convertible to 'System.IDisposable'", + Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to 'System.IDisposable'", TypeManager.CSharpName (expr_type)); return false; } @@ -4205,7 +4110,11 @@ namespace Mono.CSharp { statement = stmt; loc = l; } - + + public Statement Statement { + get { return statement; } + } + public override bool Resolve (EmitContext ec) { expr = expr.Resolve (ec); @@ -4213,7 +4122,7 @@ namespace Mono.CSharp { return false; if (expr is NullLiteral) { - Report.Error (186, expr.Location, "Use of null is not valid in this context"); + Report.Error (186, loc, "Use of null is not valid in this context"); return false; } @@ -4232,7 +4141,7 @@ namespace Mono.CSharp { // if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value || expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){ - CollectionForeach.error1579 (expr.Type, loc); + collection.error1579 (); return false; } @@ -4417,7 +4326,7 @@ namespace Mono.CSharp { list.Add (counter [i]); } - access = new ElementAccess (copy, list, loc).Resolve (ec); + access = new ElementAccess (copy, list).Resolve (ec); if (access == null) return false; @@ -4430,7 +4339,7 @@ namespace Mono.CSharp { ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc); ec.CurrentBranching.CreateSibling (); - variable = variable.ResolveLValue (ec, conv); + variable = variable.ResolveLValue (ec, conv, loc); if (variable == null) ok = false; @@ -4558,9 +4467,20 @@ namespace Mono.CSharp { // way I could do this without a goto // + if (return_type.IsInterface && return_type.IsGenericType) { + enumerator_type = return_type; + if (!FetchGetCurrent (ec, return_type)) + get_current = new PropertyExpr ( + ec, TypeManager.ienumerator_getcurrent, loc); + if (!FetchMoveNext (ec, return_type)) + move_next = TypeManager.bool_movenext_void; + return true; + } + if (return_type.IsInterface || !FetchMoveNext (ec, return_type) || !FetchGetCurrent (ec, return_type)) { + enumerator_type = return_type; move_next = TypeManager.bool_movenext_void; get_current = new PropertyExpr ( ec, TypeManager.ienumerator_getcurrent, loc); @@ -4596,11 +4516,12 @@ namespace Mono.CSharp { move_next_list = TypeContainer.FindMembers ( t, MemberTypes.Method, - BindingFlags.Public | BindingFlags.Instance, + Expression.AllBindingFlags, Type.FilterName, "MoveNext"); if (move_next_list.Count == 0) return false; + bool found = false; foreach (MemberInfo m in move_next_list){ MethodInfo mi = (MethodInfo) m; Type [] args; @@ -4609,11 +4530,13 @@ namespace Mono.CSharp { if ((args != null) && (args.Length == 0) && TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) { move_next = mi; - return true; + if (mi.IsPublic) + return true; + found = true; } } - return false; + return found; } // @@ -4658,12 +4581,11 @@ namespace Mono.CSharp { return null; } - static public void error1579 (Type t, Location loc) + public void error1579 () { - Report.Error (1579, loc, "foreach statement cannot operate on " + - "variables of type `{0}' because that class does " + - "not provide a GetEnumerator method or it is " + - "inaccessible", t.FullName); + 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)); } bool TryType (EmitContext ec, Type t) @@ -4674,11 +4596,28 @@ namespace Mono.CSharp { if (mg == null) return false; - foreach (MethodBase mb in mg.Methods) { - if (!GetEnumeratorFilter (ec, (MethodInfo) mb)) + MethodBase result = null; + MethodInfo tmp_move_next = null; + PropertyExpr tmp_get_cur = null; + Type tmp_enumerator_type = enumerator_type; + foreach (MethodInfo mi in mg.Methods) { + if (!GetEnumeratorFilter (ec, mi)) { continue; + } + + result = mi; + tmp_move_next = move_next; + tmp_get_cur = get_current; + tmp_enumerator_type = enumerator_type; + if (mi.DeclaringType == t) + break; + } - MethodInfo[] mi = new MethodInfo[] { (MethodInfo) mb }; + if (result != null) { + move_next = tmp_move_next; + get_current = tmp_get_cur; + enumerator_type = tmp_enumerator_type; + MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result }; get_enumerator = new MethodGroupExpr (mi, loc); if (t != expr.Type) { @@ -4737,14 +4676,14 @@ namespace Mono.CSharp { is_disposable = true; if (!ProbeCollectionType (ec, expr.Type)) { - error1579 (expr.Type, loc); + error1579 (); return false; } enumerator = new TemporaryVariable (enumerator_type, loc); enumerator.Resolve (ec); - init = new Invocation (get_enumerator, new ArrayList (), loc); + init = new Invocation (get_enumerator, new ArrayList ()); init = init.Resolve (ec); if (init == null) return false; @@ -4755,7 +4694,7 @@ namespace Mono.CSharp { MethodGroupExpr mg = new MethodGroupExpr (mi, loc); mg.InstanceExpression = enumerator; - move_next_expr = new Invocation (mg, new ArrayList (), loc); + move_next_expr = new Invocation (mg, new ArrayList ()); } get_current.InstanceExpression = enumerator;