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 (expr == null)
return false;
- if (!(expr is 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 {0}:' within the scope of the goto statement", val);
+ Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val);
return false;
}
public override bool Resolve (EmitContext ec)
{
- if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+ if (!ec.CurrentBranching.InLoop ()){
Error (139, "No enclosing loop out of which to break or continue");
return false;
} else if (ec.InFinally) {
public readonly ToplevelBlock Toplevel;
[Flags]
- public enum Flags {
+ public enum Flags : ushort {
Implicit = 1,
Unchecked = 2,
BlockUsed = 4,
HasRet = 16,
IsDestructor = 32,
IsToplevel = 64,
- Unsafe = 128
+ Unsafe = 128,
+ HasVarargs = 256 // Used in ToplevelBlock
}
- Flags flags;
+ protected Flags flags;
public bool Implicit {
get { return (flags & Flags.Implicit) != 0; }
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}' conflicts with a declaration 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);
- Error_AlreadyDeclared (loc, name, "parent or current");
+ //
+ // 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;
}
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);
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)
Hashtable capture_contexts;
ArrayList children;
- public bool HasVarargs = false;
+ public bool HasVarargs {
+ get { return (flags & Flags.HasVarargs) != 0; }
+ set { flags |= Flags.HasVarargs; }
+ }
//
// The parameters for the block.
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
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 {
public class Lock : ExceptionStatement {
Expression expr;
- Statement Statement;
+ public Statement Statement;
LocalBuilder temp;
public Lock (Expression expr, Statement stmt, Location l)
loc = l;
}
+ public Statement Statement {
+ get { return statement; }
+ }
+
public override bool Resolve (EmitContext ec)
{
if (!ec.InUnsafe){
public class Using : ExceptionStatement {
object expression_or_block;
- Statement Statement;
+ public Statement Statement;
ArrayList var_list;
Expression expr;
Type expr_type;
statement = stmt;
loc = l;
}
-
+
+ public Statement Statement {
+ get { return statement; }
+ }
+
public override bool Resolve (EmitContext ec)
{
expr = expr.Resolve (ec);
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;
}
//
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) {
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;