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;
public void Error (int error, string s)
{
- if (!Location.IsNull (loc))
+ if (!loc.IsNull)
Report.Error (error, loc, s);
else
Report.Error (error, s);
Expression Test;
readonly Statement InitStatement;
readonly Statement Increment;
- readonly Statement Statement;
+ public readonly Statement Statement;
bool infinite, empty;
public For (Statement initStatement,
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)
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;
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);
}
public class LabeledStatement : Statement {
- public readonly Location Location;
bool defined;
bool referenced;
Label label;
public LabeledStatement (string label_name, Location l)
{
- this.Location = l;
+ this.loc = l;
}
public Label LabelTarget (EmitContext ec)
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);
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);
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;
}
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;
}
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;
}
}
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;
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 (
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);
}
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;
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; }
}
//
}
public int ID {
+ get { return this_id; }
+ }
+
+ protected Hashtable Variables {
get {
- return this_id;
+ if (variables == null)
+ variables = new Hashtable ();
+ return variables;
}
}
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;
}
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;
}
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;
}
return null;
}
- LocalInfo this_variable = null;
-
- // <summary>
- // Returns the "this" instance variable of this block.
- // See AddThisVariable() for more information.
- // </summary>
- 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;
// <summary>
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;
}
- // <summary>
- // 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.
- // </summary>
- 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;
}
Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
if (p != null) {
Report.SymbolRelatedToPreviousError (p.Location, name);
- Report.Error (136, l, "'{0}' hides a method parameter", 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);
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)
return li;
}
- public Hashtable Variables {
- get {
- return variables;
- }
- }
-
public LocalInfo GetLocalInfo (string name)
{
for (Block b = this; b != null; b = b.Parent) {
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)
/// </summary>
public bool IsConstant (string name)
{
- Expression e = null;
-
- e = GetConstantExpression (name);
-
+ Expression e = GetConstantExpression (name);
return e != null;
}
- /// <returns>
- /// A list of labels that were not used within this block
- /// </returns>
- public string [] GetUnreferenced ()
- {
- // FIXME: Implement me
- return null;
- }
-
public void AddStatement (Statement s)
{
statements.Add (s);
}
public bool Used {
- get {
- return (flags & Flags.BlockUsed) != 0;
- }
+ get { return (flags & Flags.BlockUsed) != 0; }
}
public void Use ()
}
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 ()
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);
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);
}
}
}
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;
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)
// 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");
}
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)
}
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)
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)
}
public CaptureContext CaptureContext {
- get {
- return capture_context;
- }
+ get { return capture_context; }
}
public FlowBranching TopLevelBranching {
- get {
- return top_level_branching;
- }
+ get { return top_level_branching; }
}
//
return false;
}
+ LocalInfo this_variable = null;
+
+ // <summary>
+ // Returns the "this" instance variable of this block.
+ // See AddThisVariable() for more information.
+ // </summary>
+ public LocalInfo ThisVariable {
+ get { return this_variable; }
+ }
+
+
+ // <summary>
+ // 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.
+ // </summary>
+ 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;
if (top_level_branching != null)
return true;
+ if (ip != null)
+ parameters = ip.Parameters;
+
ResolveMeta (this, ec, ip);
top_level_branching = ec.StartFlowBranching (this);
public class SwitchLabel {
Expression label;
object converted;
- public Location loc;
+ Location loc;
Label il_label;
bool il_label_set;
// 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 {
/// <summary>
/// Maps constants whose type type SwitchType to their SwitchLabels.
/// </summary>
- public Hashtable Elements;
+ public IDictionary Elements;
/// <summary>
/// The governing switch type
//
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
};
}
// 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).
//
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)
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 {
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;
}
public class Lock : ExceptionStatement {
Expression expr;
- Statement Statement;
+ public Statement Statement;
LocalBuilder temp;
public Lock (Expression expr, Statement stmt, Location l)
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;
}
loc = l;
}
+ public Statement Statement {
+ get { return statement; }
+ }
+
public override bool Resolve (EmitContext ec)
{
if (!ec.InUnsafe){
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;
}
//
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;
}
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;
}
}
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);
public class Using : ExceptionStatement {
object expression_or_block;
- Statement Statement;
+ public Statement Statement;
ArrayList var_list;
Expression expr;
Type expr_type;
{
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;
}
statement = stmt;
loc = l;
}
-
+
+ public Statement Statement {
+ get { return statement; }
+ }
+
public override bool Resolve (EmitContext ec)
{
expr = expr.Resolve (ec);
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;
}
//
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;
}
list.Add (counter [i]);
}
- access = new ElementAccess (copy, list, loc).Resolve (ec);
+ access = new ElementAccess (copy, list).Resolve (ec);
if (access == null)
return false;
// 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);
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;
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;
}
//
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)
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) {
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;
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;