// Author:
// Miguel de Icaza (miguel@ximian.com)
// Martin Baulig (martin@ximian.com)
+// Marek Safar (marek.safar@seznam.cz)
//
// (C) 2001, 2002, 2003 Ximian, Inc.
// (C) 2003, 2004 Novell, Inc.
{
ec.Mark (loc, true);
DoEmit (ec);
- }
+ }
+
+ //
+ // This routine must be overrided in derived classes and make copies
+ // of all the data that might be modified if resolved
+ //
+ protected virtual void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new Exception (String.Format ("Statement.CloneTo not implemented for {0}", this.GetType ()));
+ }
+
+ public Statement Clone (CloneContext clonectx)
+ {
+ Statement s = (Statement) this.MemberwiseClone ();
+ if (s is Block)
+ clonectx.AddBlockMap ((Block) this, (Block) s);
+
+ CloneTo (clonectx, s);
+ return s;
+ }
+
+ public Statement PerformClone ()
+ {
+ CloneContext clonectx = new CloneContext ();
+
+ return Clone (clonectx);
+ }
+
}
+ //
+ // 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;
+ }
+
+ 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 () {}
{
return true;
}
-
+
+ public override bool ResolveUnreachable (EmitContext ec, bool warn)
+ {
+ return true;
+ }
+
protected override void DoEmit (EmitContext ec)
{
}
ig.MarkLabel (false_target);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ If target = (If) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.TrueStatement = TrueStatement.Clone (clonectx);
+ target.FalseStatement = FalseStatement.Clone (clonectx);
+ }
}
public class Do : Statement {
public Expression expr;
- public readonly Statement EmbeddedStatement;
+ public Statement EmbeddedStatement;
bool infinite;
public Do (Statement statement, Expression boolExpr, Location l)
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+ bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
if (!EmbeddedStatement.Resolve (ec))
ok = false;
+ ec.EndFlowBranching ();
+
+ if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable && !was_unreachable)
+ Report.Warning (162, 2, expr.Location, "Unreachable code detected");
expr = Expression.ResolveBoolean (ec, expr, loc);
if (expr == null)
if (res)
infinite = true;
}
+ if (infinite)
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
- ec.CurrentBranching.Infinite = infinite;
ec.EndFlowBranching ();
return ok;
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Do target = (Do) t;
+
+ target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
+ target.expr = expr.Clone (clonectx);
+ }
}
public class While : Statement {
public Expression expr;
- public readonly Statement Statement;
+ public Statement Statement;
bool infinite, empty;
public While (Expression boolExpr, Statement statement, Location l)
if (!infinite)
ec.CurrentBranching.CreateSibling ();
+ ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
if (!Statement.Resolve (ec))
ok = false;
+ ec.EndFlowBranching ();
+
+ // There's no direct control flow from the end of the embedded statement to the end of the loop
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
- ec.CurrentBranching.Infinite = infinite;
ec.EndFlowBranching ();
return ok;
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ While target = (While) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class For : Statement {
Expression Test;
- readonly Statement InitStatement;
- readonly Statement Increment;
- public readonly Statement Statement;
+ Statement InitStatement;
+ Statement Increment;
+ public Statement Statement;
bool infinite, empty;
public For (Statement initStatement,
if (!infinite)
ec.CurrentBranching.CreateSibling ();
+ bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
if (!Statement.Resolve (ec))
ok = false;
+ ec.EndFlowBranching ();
if (Increment != null){
- if (!Increment.Resolve (ec))
- ok = false;
+ if (ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable) {
+ if (!Increment.ResolveUnreachable (ec, !was_unreachable))
+ ok = false;
+ } else {
+ if (!Increment.Resolve (ec))
+ ok = false;
+ }
}
- ec.CurrentBranching.Infinite = infinite;
+ // There's no direct control flow from the end of the embedded statement to the end of the loop
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
+
ec.EndFlowBranching ();
return ok;
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ For target = (For) t;
+
+ if (InitStatement != null)
+ target.InitStatement = InitStatement.Clone (clonectx);
+ if (Test != null)
+ target.Test = Test.Clone (clonectx);
+ if (Increment != null)
+ target.Increment = Increment.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class StatementExpression : Statement {
{
return "StatementExpression (" + expr + ")";
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ StatementExpression target = (StatementExpression) t;
+
+ target.expr = (ExpressionStatement) expr.Clone (clonectx);
+ }
}
/// <summary>
loc = l;
}
- bool in_exc;
+ bool unwind_protect;
public override bool Resolve (EmitContext ec)
{
}
}
- FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
-
- if (ec.CurrentBranching.InTryOrCatch (true)) {
- ec.CurrentBranching.AddFinallyVector (vector);
- in_exc = true;
- } else if (ec.InFinally) {
- Error (157, "Control cannot leave the body of a finally clause");
- return false;
- } else
- vector.CheckOutParameters (ec.CurrentBranching);
-
- if (in_exc)
+ int errors = Report.Errors;
+ unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+ if (unwind_protect)
ec.NeedReturnLabel ();
-
- ec.CurrentBranching.CurrentUsageVector.Return ();
- return true;
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
+ return errors == Report.Errors;
}
protected override void DoEmit (EmitContext ec)
if (Expr != null) {
Expr.Emit (ec);
- if (in_exc)
+ if (unwind_protect)
ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
}
- if (in_exc)
+ if (unwind_protect)
ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
else
ec.ig.Emit (OpCodes.Ret);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Return target = (Return) t;
+
+ target.Expr = Expr.Clone (clonectx);
+ }
}
public class Goto : Statement {
string target;
LabeledStatement label;
+ bool unwind_protect;
public override bool Resolve (EmitContext ec)
{
- label = ec.CurrentBranching.LookupLabel (target, loc);
- if (label == null)
- return false;
-
- // If this is a forward goto.
- if (!label.IsDefined)
- label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
-
+ int errors = Report.Errors;
+ unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- label.AddReference ();
-
- return true;
+ return errors == Report.Errors;
}
public Goto (string label, Location l)
}
public string Target {
- get {
- return target;
- }
+ get { return target; }
+ }
+
+ public void SetResolvedTarget (LabeledStatement label)
+ {
+ this.label = label;
+ label.AddReference ();
}
protected override void DoEmit (EmitContext ec)
{
+ if (label == null)
+ throw new InternalErrorException ("goto emitted before target resolved");
Label l = label.LabelTarget (ec);
- ec.ig.Emit (OpCodes.Br, l);
+ ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
}
}
public class LabeledStatement : Statement {
+ string name;
bool defined;
bool referenced;
Label label;
FlowBranching.UsageVector vectors;
- public LabeledStatement (string label_name, Location l)
+ public LabeledStatement (string name, Location l)
{
+ this.name = name;
this.loc = l;
}
return label;
}
+ public string Name {
+ get { return name; }
+ }
+
public bool IsDefined {
- get {
- return defined;
- }
+ get { return defined; }
}
public bool HasBeenReferenced {
- get {
- return referenced;
- }
+ get { return referenced; }
+ }
+
+ public FlowBranching.UsageVector JumpOrigins {
+ get { return vectors; }
}
public void AddUsageVector (FlowBranching.UsageVector vector)
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.Label (vectors);
-
+ // this flow-branching will be terminated when the surrounding block ends
+ ec.StartFlowBranching (this);
return true;
}
protected override void DoEmit (EmitContext ec)
{
- if (ig != null && ig != ec.ig) {
- // TODO: location is wrong
- Report.Error (1632, loc, "Control cannot leave the body of an anonymous method");
- return;
- }
+ if (ig != null && ig != ec.ig)
+ throw new InternalErrorException ("cannot happen");
LabelTarget (ec);
ec.ig.MarkLabel (label);
}
return false;
}
- c = c.ToType (ec.Switch.SwitchType, loc);
- if (c == null)
- 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));
+ return false;
+ }
+
if (val == null)
val = SwitchLabel.NullStringCase;
{
ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ GotoCase target = (GotoCase) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.sl = sl.Clone (clonectx);
+ }
}
public class Throw : Statement {
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Throw ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
if (expr != null){
expr = expr.Resolve (ec);
if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
- expr.Error_UnexpectedKind (ec, "value, variable, property or indexer access ", loc);
+ expr.Error_UnexpectedKind (ec.DeclContainer, "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");
ec.ig.Emit (OpCodes.Throw);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Throw target = (Throw) t;
+
+ target.expr = expr.Clone (clonectx);
+ }
}
public class Break : Statement {
loc = l;
}
- bool crossing_exc;
+ bool unwind_protect;
public override bool Resolve (EmitContext ec)
{
- if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
- Error (139, "No enclosing loop out of which to break or continue");
- return false;
- } else if (ec.InFinally && ec.CurrentBranching.BreakCrossesTryCatchBoundary()) {
- 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);
- else if (ec.CurrentBranching.InLoop () || ec.CurrentBranching.InSwitch ())
- ec.CurrentBranching.AddBreakVector (
- ec.CurrentBranching.CurrentUsageVector);
-
- crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
-
- if (!crossing_exc)
- ec.NeedReturnLabel ();
-
- ec.CurrentBranching.CurrentUsageVector.Break ();
- return true;
+ int errors = Report.Errors;
+ unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
+ return errors == Report.Errors;
}
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
- if (crossing_exc)
- ig.Emit (OpCodes.Leave, ec.LoopEnd);
- else {
- ig.Emit (OpCodes.Br, ec.LoopEnd);
- }
+ ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
}
}
loc = l;
}
- bool crossing_exc;
+ bool unwind_protect;
public override bool Resolve (EmitContext ec)
{
- 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 cannot leave the body of a finally clause");
- return false;
- } else if (ec.CurrentBranching.InTryOrCatch (false))
- ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector);
-
- crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
-
+ int errors = Report.Errors;
+ unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
+ return errors == Report.Errors;
}
protected override void DoEmit (EmitContext ec)
{
- Label begin = ec.LoopBegin;
-
- if (crossing_exc)
- ec.ig.Emit (OpCodes.Leave, begin);
- else
- ec.ig.Emit (OpCodes.Br, begin);
+ ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
+ }
+ }
+
+ public abstract class Variable
+ {
+ public abstract Type Type {
+ get;
+ }
+
+ public abstract bool HasInstance {
+ get;
+ }
+
+ public abstract bool NeedsTemporary {
+ get;
}
+
+ public abstract void EmitInstance (EmitContext ec);
+
+ public abstract void Emit (EmitContext ec);
+
+ public abstract void EmitAssign (EmitContext ec);
+
+ public abstract void EmitAddressOf (EmitContext ec);
}
//
public class LocalInfo {
public Expression Type;
- //
- // Most of the time a variable will be stored in a LocalBuilder
- //
- // But sometimes, it will be stored in a field (variables that have been
- // hoisted by iterators or by anonymous methods). The context of the field will
- // be stored in the EmitContext
- //
- //
- public LocalBuilder LocalBuilder;
- public FieldBuilder FieldBuilder;
-
public Type VariableType;
public readonly string Name;
public readonly Location Location;
public VariableInfo VariableInfo;
+ Variable var;
+ public Variable Variable {
+ get { return var; }
+ }
+
+ [Flags]
enum Flags : byte {
Used = 1,
ReadOnly = 2,
IsThis = 8,
Captured = 16,
AddressTaken = 32,
- CompilerGenerated = 64
+ CompilerGenerated = 64,
+ IsConstant = 128
}
public enum ReadOnlyContext: byte {
Flags flags;
ReadOnlyContext ro_context;
+ LocalBuilder builder;
public LocalInfo (Expression type, string name, Block block, Location l)
{
Location = l;
}
- public LocalInfo (TypeContainer tc, Block block, Location l)
+ public LocalInfo (DeclSpace ds, Block block, Location l)
{
- VariableType = tc.TypeBuilder;
+ VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
Block = block;
Location = l;
}
- public bool IsThisAssigned (EmitContext ec, Location loc)
+ public void ResolveVariable (EmitContext ec)
+ {
+ Block theblock = Block;
+ if (theblock.ScopeInfo != null)
+ var = theblock.ScopeInfo.GetCapturedVariable (this);
+
+ if (var == null) {
+ if (Pinned)
+ //
+ // This is needed to compile on both .NET 1.x and .NET 2.x
+ // the later introduced `DeclareLocal (Type t, bool pinned)'
+ //
+ builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
+ else
+ builder = ec.ig.DeclareLocal (VariableType);
+
+ var = new LocalVariable (this, builder);
+ }
+ }
+
+ public void EmitSymbolInfo (EmitContext ec, string name)
+ {
+ if (builder != null)
+ ec.DefineLocalVariable (name, builder);
+ }
+
+ public bool IsThisAssigned (EmitContext ec)
{
if (VariableInfo == null)
throw new Exception ();
if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
return true;
- return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, loc);
+ return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc);
}
public bool IsAssigned (EmitContext ec)
if (texpr == null)
return false;
- VariableType = texpr.ResolveType (ec);
+ VariableType = texpr.Type;
}
if (VariableType == TypeManager.void_type) {
- Report.Error (1547, Location,
- "Keyword 'void' cannot be used in this context");
+ Expression.Error_VoidInvalidInTheContext (Location);
return false;
}
if (VariableType.IsAbstract && VariableType.IsSealed) {
- Report.Error (723, Location, "Cannot declare variable of static type `{0}'", TypeManager.CSharpName (VariableType));
+ FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
return false;
}
}
}
+ public bool IsConstant {
+ get {
+ return (flags & Flags.IsConstant) != 0;
+ }
+ set {
+ flags |= Flags.IsConstant;
+ }
+ }
+
public bool AddressTaken {
get {
return (flags & Flags.AddressTaken) != 0;
flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
}
}
+
+ protected class LocalVariable : Variable
+ {
+ public readonly LocalInfo LocalInfo;
+ LocalBuilder builder;
+
+ public LocalVariable (LocalInfo local, LocalBuilder builder)
+ {
+ this.LocalInfo = local;
+ this.builder = builder;
+ }
+
+ public override Type Type {
+ get { return LocalInfo.VariableType; }
+ }
+
+ public override bool HasInstance {
+ get { return false; }
+ }
+
+ public override bool NeedsTemporary {
+ get { return false; }
+ }
+
+ public override void EmitInstance (EmitContext ec)
+ {
+ // Do nothing.
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloc, builder);
+ }
+
+ public override void EmitAssign (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Stloc, builder);
+ }
+
+ public override void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloca, builder);
+ }
+ }
+
+ public LocalInfo Clone (CloneContext clonectx)
+ {
+ // Only this kind is created by the parser.
+ return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+ }
}
-
+
/// <summary>
/// Block represents a C# block.
/// </summary>
IsDestructor = 32,
IsToplevel = 64,
Unsafe = 128,
- HasVarargs = 256 // Used in ToplevelBlock
+ HasVarargs = 256, // Used in ToplevelBlock
+ IsIterator = 512
+
}
protected Flags flags;
//
// The statements in this block
//
- ArrayList statements;
+ protected ArrayList statements;
int num_statements;
//
//
Block switch_block;
+ ExpressionStatement scope_init;
+
+ ArrayList anonymous_children;
+
protected static int id;
int this_id;
// share with parent
known_variables = parent.known_variables;
}
-
}
public Block CreateSwitchBlock (Location start)
get { return this_id; }
}
- protected IDictionary Variables {
+ public IDictionary Variables {
get {
if (variables == null)
variables = new ListDictionary ();
EndLocation = loc;
}
+ protected static void Error_158 (string name, Location loc)
+ {
+ Report.Error (158, loc, "The label `{0}' shadows another label " +
+ "by the same name in a contained scope.", name);
+ }
+
/// <summary>
/// Adds a label to the current block.
/// </summary>
/// otherwise.
/// </returns>
///
- public bool AddLabel (string name, LabeledStatement target, Location loc)
+ public bool AddLabel (LabeledStatement target)
{
if (switch_block != null)
- return switch_block.AddLabel (name, target, loc);
+ return switch_block.AddLabel (target);
+
+ string name = target.Name;
Block cur = this;
while (cur != null) {
if (cur.DoLookupLabel (name) != null) {
- Report.Error (
- 140, loc, "The label `{0}' is a duplicate",
- name);
+ Report.Error (140, target.loc,
+ "The label `{0}' is a duplicate", name);
return false;
}
while (cur != null) {
if (cur.DoLookupLabel (name) != null) {
- Report.Error (
- 158, loc,
- "The label `{0}' shadows another label " +
- "by the same name in a contained scope.",
- name);
+ Error_158 (name, target.loc);
return false;
}
if (s == null)
continue;
- Report.Error (
- 158, s.loc,
- "The label `{0}' shadows another " +
- "label by the same name in a " +
- "contained scope.",
- name);
+ Error_158 (name, target.loc);
return false;
}
}
-
cur = cur.Parent;
}
+ Toplevel.CheckError158 (name, target.loc);
+
if (labels == null)
labels = new Hashtable ();
known_variables [name] = info;
}
- LocalInfo GetKnownVariableInfo (string name)
+ LocalInfo GetKnownVariableInfo (string name, bool recurse)
{
- if (known_variables == null)
+ if (known_variables != null) {
+ LocalInfo vi = (LocalInfo) known_variables [name];
+ if (vi != null)
+ return vi;
+ }
+
+ if (!recurse || (children == null))
return null;
- return (LocalInfo) known_variables [name];
+
+ foreach (Block block in children) {
+ LocalInfo vi = block.GetKnownVariableInfo (name, true);
+ if (vi != null)
+ return vi;
+ }
+
+ return null;
}
public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
{
Block b = this;
- LocalInfo kvi = b.GetKnownVariableInfo (name);
+ LocalInfo kvi = b.GetKnownVariableInfo (name, true);
while (kvi == null) {
while (b.Implicit)
b = b.Parent;
b = b.Parent;
if (b == null)
return true;
- kvi = b.GetKnownVariableInfo (name);
+ kvi = b.GetKnownVariableInfo (name, false);
}
if (kvi.Block == b)
return false;
}
+ public bool CheckError136_InParents (string name, Location loc)
+ {
+ for (Block b = Parent; b != null; b = b.Parent) {
+ if (!b.DoCheckError136 (name, "parent or current", loc))
+ return false;
+ }
+
+ for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) {
+ if (!b.CheckError136_InParents (name, loc))
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool CheckError136_InChildren (string name, Location loc)
+ {
+ if (!DoCheckError136_InChildren (name, loc))
+ return false;
+
+ Block b = this;
+ while (b.Implicit) {
+ if (!b.Parent.DoCheckError136_InChildren (name, loc))
+ return false;
+ b = b.Parent;
+ }
+
+ return true;
+ }
+
+ protected bool DoCheckError136_InChildren (string name, Location loc)
+ {
+ if (!DoCheckError136 (name, "child", loc))
+ return false;
+
+ if (AnonymousChildren != null) {
+ foreach (ToplevelBlock child in AnonymousChildren) {
+ if (!child.DoCheckError136_InChildren (name, loc))
+ return false;
+ }
+ }
+
+ if (children != null) {
+ foreach (Block child in children) {
+ if (!child.DoCheckError136_InChildren (name, loc))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public bool CheckError136 (string name, string scope, bool check_parents,
+ bool check_children, Location loc)
+ {
+ if (!DoCheckError136 (name, scope, loc))
+ return false;
+
+ if (check_parents) {
+ if (!CheckError136_InParents (name, loc))
+ return false;
+ }
+
+ if (check_children) {
+ if (!CheckError136_InChildren (name, loc))
+ return false;
+ }
+
+ for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) {
+ if (!c.DoCheckError136 (name, "parent or current", loc))
+ return false;
+ }
+
+ return true;
+ }
+
+ protected bool DoCheckError136 (string name, string scope, Location loc)
+ {
+ LocalInfo vi = GetKnownVariableInfo (name, false);
+ if (vi != null) {
+ Report.SymbolRelatedToPreviousError (vi.Location, name);
+ Error_AlreadyDeclared (loc, name, scope != null ? scope : "child");
+ return false;
+ }
+
+ int idx;
+ Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
+ if (p != null) {
+ Report.SymbolRelatedToPreviousError (p.Location, name);
+ Error_AlreadyDeclared (
+ loc, name, scope != null ? scope : "method argument");
+ return false;
+ }
+
+ return true;
+ }
+
public LocalInfo AddVariable (Expression type, string name, Location l)
{
LocalInfo vi = GetLocalInfo (name);
return null;
}
- vi = GetKnownVariableInfo (name);
- if (vi != null) {
- Report.SymbolRelatedToPreviousError (vi.Location, name);
- Error_AlreadyDeclared (l, name, "child");
- return null;
- }
-
- int idx;
- Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
- if (p != null) {
- Report.SymbolRelatedToPreviousError (p.Location, name);
- Error_AlreadyDeclared (l, name, "method argument");
+ if (!CheckError136 (name, null, true, true, l))
return null;
- }
vi = new LocalInfo (type, name, this, l);
-
Variables.Add (name, vi);
-
- for (Block b = this; b != null; b = b.Parent)
- b.AddKnownVariable (name, vi);
+ AddKnownVariable (name, vi);
if ((flags & Flags.VariablesInitialized) != 0)
throw new Exception ();
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);
+ 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);
}
public bool AddConstant (Expression type, string name, Expression value, Location l)
public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
{
+ Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
+
if (temporary_variables == null)
temporary_variables = new ArrayList ();
public VariableMap ParameterMap {
get {
- if ((flags & Flags.VariablesInitialized) == 0)
+ if ((flags & Flags.VariablesInitialized) == 0){
throw new Exception ("Variables have not been initialized yet");
+ }
return param_map;
}
}
}
+ public ScopeInfo ScopeInfo;
+
+ public ScopeInfo CreateScopeInfo ()
+ {
+ if (ScopeInfo == null)
+ ScopeInfo = ScopeInfo.CreateScope (this);
+
+ return ScopeInfo;
+ }
+
+ public ArrayList AnonymousChildren {
+ get { return anonymous_children; }
+ }
+
+ public void AddAnonymousChild (ToplevelBlock b)
+ {
+ if (anonymous_children == null)
+ anonymous_children = new ArrayList ();
+
+ anonymous_children.Add (b);
+ }
+
/// <summary>
/// Emits the variable declarations and labels.
/// </summary>
/// </remarks>
public void ResolveMeta (ToplevelBlock toplevel, EmitContext ec, Parameters ip)
{
- bool old_unsafe = ec.InUnsafe;
+ Report.Debug (64, "BLOCK RESOLVE META", this, Parent, toplevel);
// If some parent block was unsafe, we remain unsafe even if this block
// isn't explicitly marked as such.
- ec.InUnsafe |= Unsafe;
+ using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
+ //
+ // Compute the VariableMap's.
+ //
+ // Unfortunately, we don't know the type when adding variables with
+ // AddVariable(), so we need to compute this info here.
+ //
- //
- // Compute the VariableMap's.
- //
- // Unfortunately, we don't know the type when adding variables with
- // AddVariable(), so we need to compute this info here.
- //
+ LocalInfo[] locals;
+ if (variables != null) {
+ foreach (LocalInfo li in variables.Values)
+ li.Resolve (ec);
- LocalInfo[] locals;
- if (variables != null) {
- foreach (LocalInfo li in variables.Values)
- li.Resolve (ec);
+ locals = new LocalInfo [variables.Count];
+ variables.Values.CopyTo (locals, 0);
+ } else
+ locals = new LocalInfo [0];
- locals = new LocalInfo [variables.Count];
- variables.Values.CopyTo (locals, 0);
- } else
- locals = new LocalInfo [0];
+ if (Parent != null)
+ local_map = new VariableMap (Parent.LocalMap, locals);
+ else
+ local_map = new VariableMap (locals);
- if (Parent != null)
- local_map = new VariableMap (Parent.LocalMap, locals);
- else
- local_map = new VariableMap (locals);
+ param_map = new VariableMap (ip);
+ flags |= Flags.VariablesInitialized;
- param_map = new VariableMap (ip);
- flags |= Flags.VariablesInitialized;
+ //
+ // Process this block variables
+ //
+ if (variables != null) {
+ foreach (DictionaryEntry de in variables) {
+ string name = (string) de.Key;
+ LocalInfo vi = (LocalInfo) de.Value;
+ Type variable_type = vi.VariableType;
- bool old_check_state = ec.ConstantCheckState;
- ec.ConstantCheckState = (flags & Flags.Unchecked) == 0;
-
- //
- // Process this block variables
- //
- if (variables != null){
- foreach (DictionaryEntry de in variables){
- string name = (string) de.Key;
- LocalInfo vi = (LocalInfo) de.Value;
-
- if (vi.VariableType == null)
- continue;
+ if (variable_type == null)
+ continue;
- Type variable_type = vi.VariableType;
+ if (variable_type.IsPointer) {
+ //
+ // Am not really convinced that this test is required (Microsoft does it)
+ // but the fact is that you would not be able to use the pointer variable
+ // *anyways*
+ //
+ if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type),
+ vi.Location))
+ continue;
+ }
- if (variable_type.IsPointer){
- //
- // Am not really convinced that this test is required (Microsoft does it)
- // but the fact is that you would not be able to use the pointer variable
- // *anyways*
- //
- if (!TypeManager.VerifyUnManaged (TypeManager.GetElementType (variable_type),
- vi.Location))
+ if (constants == null)
continue;
- }
- if (constants == null)
- continue;
+ Expression cv = (Expression) constants [name];
+ if (cv == null)
+ continue;
- Expression cv = (Expression) constants [name];
- if (cv == null)
- continue;
+ // Don't let 'const int Foo = Foo;' succeed.
+ // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
+ // which in turn causes the 'must be constant' error to be triggered.
+ constants.Remove (name);
- // Don't let 'const int Foo = Foo;' succeed.
- // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
- // which in turn causes the 'must be constant' error to be triggered.
- constants.Remove (name);
+ if (!Const.IsConstantTypeValid (variable_type)) {
+ Const.Error_InvalidConstantType (variable_type, loc);
+ continue;
+ }
- ec.CurrentBlock = this;
- Expression e = cv.Resolve (ec);
- if (e == null)
- continue;
+ using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
+ ec.CurrentBlock = this;
+ Expression e = cv.Resolve (ec);
+ if (e == null)
+ continue;
- Constant ce = e as Constant;
- if (ce == null){
- Const.Error_ExpressionMustBeConstant (vi.Location, name);
- continue;
- }
+ Constant ce = e as Constant;
+ if (ce == null) {
+ Const.Error_ExpressionMustBeConstant (vi.Location, name);
+ continue;
+ }
- e = ce.ToType (variable_type, vi.Location);
- if (e == null)
- 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);
+ else
+ ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false);
+ continue;
+ }
- constants.Add (name, e);
+ constants.Add (name, e);
+ vi.IsConstant = true;
+ }
+ }
}
- }
- ec.ConstantCheckState = old_check_state;
- //
- // Now, handle the children
- //
- if (children != null){
- foreach (Block b in children)
- b.ResolveMeta (toplevel, ec, ip);
+ //
+ // Now, handle the children
+ //
+ if (children != null) {
+ foreach (Block b in children)
+ b.ResolveMeta (toplevel, ec, ip);
+ }
}
- ec.InUnsafe = old_unsafe;
}
//
// Emits the local variable declarations for a block
//
- public void EmitMeta (EmitContext ec)
+ public virtual void EmitMeta (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
- if (variables != null){
- bool have_captured_vars = ec.HaveCapturedVariables ();
-
- foreach (DictionaryEntry de in variables){
- LocalInfo vi = (LocalInfo) de.Value;
-
- if (have_captured_vars && ec.IsCaptured (vi))
- continue;
+ Report.Debug (64, "BLOCK EMIT META", this, Parent, Toplevel, ScopeInfo, ec);
+ if (ScopeInfo != null) {
+ scope_init = ScopeInfo.GetScopeInitializer (ec);
+ Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo,
+ ec, scope_init);
+ }
- if (vi.Pinned)
- //
- // This is needed to compile on both .NET 1.x and .NET 2.x
- // the later introduced `DeclareLocal (Type t, bool pinned)'
- //
- vi.LocalBuilder = TypeManager.DeclareLocalPinned (ig, vi.VariableType);
- else if (!vi.IsThis)
- vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
- }
+ if (variables != null){
+ foreach (LocalInfo vi in variables.Values)
+ vi.ResolveVariable (ec);
}
if (temporary_variables != null) {
- AnonymousContainer am = ec.CurrentAnonymousMethod;
- TypeBuilder scope = null;
- if ((am != null) && am.IsIterator) {
- scope = am.Scope.ScopeTypeBuilder;
- if (scope == null)
- throw new InternalErrorException ();
- }
- foreach (LocalInfo vi in temporary_variables) {
- if (scope != null) {
- if (vi.FieldBuilder == null)
- vi.FieldBuilder = scope.DefineField (
- vi.Name, vi.VariableType, FieldAttributes.Assembly);
- } else
- vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
- }
+ foreach (LocalInfo vi in temporary_variables)
+ vi.ResolveVariable (ec);
}
if (children != null){
if ((variables != null) && (RootContext.WarningLevel >= 3)) {
foreach (DictionaryEntry de in variables){
LocalInfo vi = (LocalInfo) de.Value;
-
+
if (vi.Used)
continue;
-
+
name = (string) de.Key;
- if (vector.IsAssigned (vi.VariableInfo)){
+ // vi.VariableInfo can be null for 'catch' variables
+ if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){
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);
Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+ //
+ // 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
+ // from the beginning of the function. The outer Resolve() that detected the unreachability is
+ // responsible for handling the situation.
+ //
int statement_count = statements.Count;
for (int ix = 0; ix < statement_count; ix++){
Statement s = (Statement) statements [ix];
if (s is Block)
((Block) s).unreachable = true;
- if (!unreachable_shown) {
+ if (!unreachable_shown && !(s is LabeledStatement)) {
Report.Warning (162, 2, s.loc, "Unreachable code detected");
unreachable_shown = true;
}
statements [ix] = EmptyStatement.Value;
num_statements = ix + 1;
- if (s is LabeledStatement)
- unreachable = false;
- else
- unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+
+ unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
+ if (unreachable && s is LabeledStatement)
+ throw new InternalErrorException ("should not happen");
}
Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
ec.CurrentBranching, statement_count, num_statements);
+ if (!ok)
+ return false;
+
+ while (ec.CurrentBranching is FlowBranchingLabeled)
+ ec.EndFlowBranching ();
+
FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
ec.CurrentBlock = prev_block;
// initializer, then we must initialize all of the struct's fields.
if ((flags & Flags.IsToplevel) != 0 &&
!Toplevel.IsThisAssigned (ec) &&
- vector.Reachability.Throws != FlowBranching.FlowReturns.Always)
+ !vector.Reachability.IsUnreachable)
ok = false;
if ((labels != null) && (RootContext.WarningLevel >= 2)) {
Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
- if ((vector.Reachability.Returns == FlowBranching.FlowReturns.Always) ||
- (vector.Reachability.Throws == FlowBranching.FlowReturns.Always) ||
- (vector.Reachability.Reachable == FlowBranching.FlowReturns.Never))
+ if (vector.Reachability.IsUnreachable)
flags |= Flags.HasRet;
if (ok && (errors == Report.Errors)) {
if (emit_debug_info) {
if (is_lexical_block)
ec.BeginScope ();
+ }
+ ec.Mark (StartLocation, true);
+ if (scope_init != null)
+ scope_init.EmitStatement (ec);
+ DoEmit (ec);
+ ec.Mark (EndLocation, true);
+
+ if (emit_debug_info) {
+ if (is_lexical_block)
+ ec.EndScope ();
if (variables != null) {
foreach (DictionaryEntry de in variables) {
string name = (string) de.Key;
LocalInfo vi = (LocalInfo) de.Value;
- if (vi.LocalBuilder == null)
- continue;
-
- ec.DefineLocalVariable (name, vi.LocalBuilder);
+ vi.EmitSymbolInfo (ec, name);
}
}
}
- ec.Mark (StartLocation, true);
- DoEmit (ec);
- ec.Mark (EndLocation, true);
-
- if (emit_debug_info && is_lexical_block)
- ec.EndScope ();
-
ec.CurrentBlock = prev_block;
}
{
return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Block target = (Block) t;
+
+ if (Parent != null)
+ target.Parent = clonectx.LookupBlock (Parent);
+
+ target.statements = new ArrayList ();
+ if (target.children != null){
+ target.children = new ArrayList ();
+ foreach (Block b in children){
+ Block newblock = (Block) b.Clone (clonectx);
+
+ target.children.Add (newblock);
+ }
+
+ }
+
+ foreach (Statement s in statements)
+ target.statements.Add (s.Clone (clonectx));
+
+ if (variables != null){
+ target.variables = new Hashtable ();
+
+ foreach (DictionaryEntry de in variables){
+ LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
+ target.variables [de.Key] = newlocal;
+ clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
+ }
+ }
+
+ //
+ // TODO: labels, switch_block, constants (?), anonymous_children
+ //
+ }
}
//
// Pointer to the host of this anonymous method, or null
// if we are the topmost block
//
- ToplevelBlock container;
- CaptureContext capture_context;
- FlowBranching top_level_branching;
-
- Hashtable capture_contexts;
- ArrayList children;
+ Block container;
+ ToplevelBlock child;
+ GenericMethod generic;
+ FlowBranchingToplevel top_level_branching;
+ AnonymousContainer anonymous_container;
+ RootScopeInfo root_scope;
public bool HasVarargs {
get { return (flags & Flags.HasVarargs) != 0; }
set { flags |= Flags.HasVarargs; }
}
+ public bool IsIterator {
+ get { return (flags & Flags.IsIterator) != 0; }
+ }
+
//
// The parameters for the block.
//
- public readonly Parameters Parameters;
-
- public void RegisterCaptureContext (CaptureContext cc)
- {
- if (capture_contexts == null)
- capture_contexts = new Hashtable ();
- capture_contexts [cc] = cc;
+ Parameters parameters;
+ public Parameters Parameters {
+ get { return parameters; }
}
- public void CompleteContexts ()
+ public bool CompleteContexts (EmitContext ec)
{
- if (capture_contexts == null)
- return;
+ Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this,
+ container, root_scope);
+
+ if (root_scope != null)
+ root_scope.LinkScopes ();
- foreach (CaptureContext cc in capture_contexts.Keys){
- cc.AdjustScopes ();
+ if ((container == null) && (root_scope != null)) {
+ Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this,
+ root_scope);
+
+ if (root_scope.DefineType () == null)
+ return false;
+ if (!root_scope.ResolveType ())
+ return false;
+ if (!root_scope.ResolveMembers ())
+ return false;
+ if (!root_scope.DefineMembers ())
+ return false;
}
+
+ return true;
}
- public CaptureContext ToplevelBlockCaptureContext {
- get { return capture_context; }
+ public GenericMethod GenericMethod {
+ get { return generic; }
}
public ToplevelBlock Container {
- get { return container; }
+ get { return container != null ? container.Toplevel : null; }
}
- protected void AddChild (ToplevelBlock block)
- {
- if (children == null)
- children = new ArrayList ();
+ public Block ContainerBlock {
+ get { return container; }
+ }
- children.Add (block);
+ public AnonymousContainer AnonymousContainer {
+ get { return anonymous_container; }
+ set { anonymous_container = value; }
}
//
// Parent is only used by anonymous blocks to link back to their
// parents
//
- public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) :
+ public ToplevelBlock (Block container, Parameters parameters, Location start) :
this (container, (Flags) 0, parameters, start)
{
}
+
+ public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
+ Location start) :
+ this (container, parameters, start)
+ {
+ this.generic = generic;
+ }
public ToplevelBlock (Parameters parameters, Location start) :
this (null, (Flags) 0, parameters, start)
{
}
- public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
- this (null, flags, parameters, start)
- {
+ public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ this (null, flags, parameters, start)
+ {
+ }
+
+ public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
+ base (null, flags | Flags.IsToplevel, start, Location.Null)
+ {
+ this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+ this.container = container;
+ }
+
+ public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+ {
+ }
+
+ public bool CheckError158 (string name, Location loc)
+ {
+ if (AnonymousChildren != null) {
+ foreach (ToplevelBlock child in AnonymousChildren) {
+ if (!child.CheckError158 (name, loc))
+ return false;
+ }
+ }
+
+ for (ToplevelBlock c = Container; c != null; c = c.Container) {
+ if (!c.DoCheckError158 (name, loc))
+ return false;
+ }
+
+ return true;
}
- public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) :
- base (null, flags | Flags.IsToplevel, start, Location.Null)
+ bool DoCheckError158 (string name, Location loc)
{
- Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
- this.container = container;
+ LabeledStatement s = LookupLabel (name);
+ if (s != null) {
+ Error_158 (name, loc);
+ return false;
+ }
- if (container != null)
- container.AddChild (this);
+ return true;
}
- public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+ public RootScopeInfo CreateRootScope (TypeContainer host)
{
+ if (root_scope != null)
+ return root_scope;
+
+ if (Container == null)
+ root_scope = new RootScopeInfo (
+ this, host, generic, StartLocation);
+
+ ScopeInfo = root_scope;
+ return root_scope;
}
- public void SetHaveAnonymousMethods (Location loc, AnonymousContainer host)
+ public void CreateIteratorHost (RootScopeInfo root)
{
- if (capture_context == null)
- capture_context = new CaptureContext (this, loc, host);
+ Report.Debug (64, "CREATE ITERATOR HOST", this, root,
+ container, root_scope);
+
+ if ((container != null) || (root_scope != null))
+ throw new InternalErrorException ();
+
+ ScopeInfo = root_scope = root;
}
- public CaptureContext CaptureContext {
- get { return capture_context; }
+ public RootScopeInfo RootScope {
+ get {
+ if (root_scope != null)
+ return root_scope;
+ else if (Container != null)
+ return Container.RootScope;
+ else
+ return null;
+ }
}
- public FlowBranching TopLevelBranching {
+ public FlowBranchingToplevel TopLevelBranching {
get { return top_level_branching; }
}
// null. Later on, when resolving the iterator, we need to move the
// anonymous method into that iterator.
//
- public void ReParent (ToplevelBlock new_parent, AnonymousContainer new_host)
+ public void ReParent (ToplevelBlock new_parent)
{
- foreach (ToplevelBlock block in children) {
- if (block.CaptureContext == null)
- continue;
-
- block.container = new_parent;
- block.CaptureContext.ReParent (new_parent, new_host);
- }
+ container = new_parent;
+ Parent = new_parent;
+ new_parent.child = this;
}
//
// analysis code to ensure that it's been fully initialized before control
// leaves the constructor.
// </summary>
- public LocalInfo AddThisVariable (TypeContainer tc, Location l)
+ public LocalInfo AddThisVariable (DeclSpace ds, Location l)
{
if (this_variable == null) {
- this_variable = new LocalInfo (tc, this, l);
+ this_variable = new LocalInfo (ds, this, l);
this_variable.Used = true;
this_variable.IsThis = true;
public bool IsThisAssigned (EmitContext ec)
{
- return this_variable == null || this_variable.IsThisAssigned (ec, loc);
+ return this_variable == null || this_variable.IsThisAssigned (ec);
}
public bool ResolveMeta (EmitContext ec, Parameters ip)
if (top_level_branching != null)
return true;
+ if (ip != null)
+ parameters = ip;
+
+ if (!IsIterator && (container != null) && (parameters != null)) {
+ foreach (Parameter p in parameters.FixedParameters) {
+ if (!CheckError136_InParents (p.Name, loc))
+ return false;
+ }
+ }
+
ResolveMeta (this, ec, ip);
+ if (child != null)
+ child.ResolveMeta (this, ec, ip);
+
top_level_branching = ec.StartFlowBranching (this);
return Report.Errors == errors;
}
+
+ public override void EmitMeta (EmitContext ec)
+ {
+ base.EmitMeta (ec);
+ parameters.ResolveVariable (this);
+ }
+
+ public void MakeIterator (Iterator iterator)
+ {
+ flags |= Flags.IsIterator;
+
+ Block block = new Block (this);
+ foreach (Statement stmt in statements)
+ block.AddStatement (stmt);
+ statements = new ArrayList ();
+ statements.Add (new MoveNextStatement (iterator, block));
+ }
+
+ protected class MoveNextStatement : Statement {
+ Iterator iterator;
+ Block block;
+
+ public MoveNextStatement (Iterator iterator, Block block)
+ {
+ this.iterator = iterator;
+ this.block = block;
+ this.loc = iterator.Location;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ return block.Resolve (ec);
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ iterator.EmitMoveNext (ec, block);
+ }
+ }
+
+ public override string ToString ()
+ {
+ return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation,
+ root_scope, anonymous_container != null ?
+ anonymous_container.Scope : null);
+ }
}
public class SwitchLabel {
// 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)
+ public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
{
Expression e = label.Resolve (ec);
return true;
}
- c = c.ToType (required_type, loc);
+ if (allow_nullable && c.GetValue () == null) {
+ converted = NullStringCase;
+ return true;
+ }
+
+ c = c.ImplicitConversionRequired (required_type, loc);
if (c == null)
return false;
return true;
}
- public void Erorr_AlreadyOccurs ()
+ public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith)
{
string label;
if (converted == null)
label = "default";
else if (converted == NullStringCase)
label = "null";
+ else if (TypeManager.IsEnumType (switchType))
+ label = TypeManager.CSharpEnumValue (switchType, converted);
else
label = converted.ToString ();
-
+
+ Report.SymbolRelatedToPreviousError (collisionWith.loc, null);
Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
}
+
+ public SwitchLabel Clone (CloneContext clonectx)
+ {
+ return new SwitchLabel (label.Clone (clonectx), loc);
+ }
}
public class SwitchSection {
Labels = labels;
Block = block;
}
+
+ public SwitchSection Clone (CloneContext clonectx)
+ {
+ ArrayList cloned_labels = new ArrayList ();
+
+ foreach (SwitchLabel sl in cloned_labels)
+ cloned_labels.Add (sl.Clone (clonectx));
+
+ return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
+ }
}
public class Switch : Statement {
- public readonly ArrayList Sections;
+ public ArrayList Sections;
public Expression Expr;
/// <summary>
// Computed
//
Label default_target;
+ Label null_target;
Expression new_expr;
bool is_constant;
SwitchSection constant_section;
SwitchSection default_section;
+#if GMCS_SOURCE
+ //
+ // Nullable Types support for GMCS.
+ //
+ 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
// on the governing type
// expression that includes any potential conversions to the
// integral types or to string.
//
- Expression SwitchGoverningType (EmitContext ec, Type t)
+ Expression SwitchGoverningType (EmitContext ec, Expression expr)
{
+ Type t = TypeManager.DropGenericTypeArguments (expr.Type);
+
if (t == TypeManager.byte_type ||
t == TypeManager.sbyte_type ||
t == TypeManager.ushort_type ||
t == TypeManager.string_type ||
t == TypeManager.bool_type ||
t.IsSubclassOf (TypeManager.enum_type))
- return Expr;
+ return expr;
if (allowed_types == null){
allowed_types = new Type [] {
foreach (Type tt in allowed_types){
Expression e;
- e = Convert.ImplicitUserConversion (ec, Expr, tt, loc);
+ e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
if (e == null)
continue;
Report.ExtraInformation (
loc,
String.Format ("reason: more than one conversion to an integral type exist for type {0}",
- TypeManager.CSharpName (Expr.Type)));
+ TypeManager.CSharpName (expr.Type)));
return null;
}
foreach (SwitchLabel sl in ss.Labels){
if (sl.Label == null){
if (default_section != null){
- sl.Erorr_AlreadyOccurs ();
+ sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
error = true;
}
default_section = ss;
continue;
}
- if (!sl.ResolveAndReduce (ec, SwitchType)){
+ if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
error = true;
continue;
}
object key = sl.Converted;
try {
Elements.Add (key, sl);
+ } catch (ArgumentException) {
+ sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
+ error = true;
}
- catch (ArgumentException) {
- sl.Erorr_AlreadyOccurs ();
- error = true;
- }
}
}
return !error;
}
else if (k is ulong)
{
- if ((ulong) k < (1L<<32))
+ ulong ul = (ulong) k;
+ if (ul < (1L<<32))
{
- IntConstant.EmitInt (ig, (int) (long) k);
+ IntConstant.EmitInt (ig, unchecked ((int) ul));
ig.Emit (OpCodes.Conv_U8);
}
else
{
- LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
+ LongConstant.EmitLong (ig, unchecked ((long) ul));
}
}
else if (k is char)
// now emit the code for the sections
bool fFoundDefault = false;
+ bool fFoundNull = false;
+ foreach (SwitchSection ss in Sections)
+ {
+ foreach (SwitchLabel sl in ss.Labels)
+ if (sl.Converted == SwitchLabel.NullStringCase)
+ fFoundNull = true;
+ }
+
foreach (SwitchSection ss in Sections)
{
foreach (SwitchLabel sl in ss.Labels)
{
ig.MarkLabel (sl.GetILLabel (ec));
ig.MarkLabel (sl.GetILLabelCode (ec));
- if (sl.Label == null)
- {
+ if (sl.Converted == SwitchLabel.NullStringCase)
+ ig.MarkLabel (null_target);
+ else if (sl.Label == null) {
ig.MarkLabel (lblDefault);
fFoundDefault = true;
+ if (!fFoundNull)
+ ig.MarkLabel (null_target);
}
}
ss.Block.Emit (ec);
- //ig.Emit (OpCodes.Br, lblEnd);
}
if (!fFoundDefault) {
ILGenerator ig = ec.ig;
Label end_of_switch = ig.DefineLabel ();
Label next_test = ig.DefineLabel ();
- Label null_target = ig.DefineLabel ();
bool first_test = true;
bool pending_goto_end = false;
bool null_marked = false;
bool null_found;
+ int section_count = Sections.Count;
+
+ // TODO: implement switch optimization for string by using Hashtable
+ //if (SwitchType == TypeManager.string_type && section_count > 7)
+ // Console.WriteLine ("Switch optimization possible " + loc);
ig.Emit (OpCodes.Ldloc, val);
ig.Emit (OpCodes.Brfalse, default_target);
ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
+ ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string);
ig.Emit (OpCodes.Stloc, val);
- int section_count = Sections.Count;
for (int section = 0; section < section_count; section++){
SwitchSection ss = (SwitchSection) Sections [section];
if (lit == SwitchLabel.NullStringCase){
null_found = true;
- if (label_count == 1)
+ if (label + 1 == label_count)
ig.Emit (OpCodes.Br, next_test);
continue;
}
if (Expr == null)
return false;
- new_expr = SwitchGoverningType (ec, Expr.Type);
+ new_expr = SwitchGoverningType (ec, Expr);
+
+#if GMCS_SOURCE
+ if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
+ unwrap = Nullable.Unwrap.Create (Expr, ec);
+ 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");
return false;
// Validate switch.
SwitchType = new_expr.Type;
+ if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
+ Report.FeatureIsNotISO1 (loc, "switch expression of boolean type");
+ return false;
+ }
+
if (!CheckSwitch (ec))
return false;
+ if (HaveUnwrap)
+ Elements.Remove (SwitchLabel.NullStringCase);
+
Switch old_switch = ec.Switch;
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
{
ILGenerator ig = ec.ig;
+ default_target = ig.DefineLabel ();
+ null_target = ig.DefineLabel ();
+
// Store variable for comparission purposes
LocalBuilder value;
- if (!is_constant) {
+ if (HaveUnwrap) {
+ value = ig.DeclareLocal (SwitchType);
+#if GMCS_SOURCE
+ unwrap.EmitCheck (ec);
+ ig.Emit (OpCodes.Brfalse, null_target);
+ new_expr.Emit (ec);
+ ig.Emit (OpCodes.Stloc, value);
+#endif
+ } else if (!is_constant) {
value = ig.DeclareLocal (SwitchType);
new_expr.Emit (ec);
ig.Emit (OpCodes.Stloc, value);
} else
value = null;
- default_target = ig.DefineLabel ();
-
//
// Setup the codegen context
//
ec.LoopEnd = old_end;
ec.Switch = old_switch;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Switch target = (Switch) t;
+
+ target.Expr = Expr.Clone (clonectx);
+ target.Sections = new ArrayList ();
+ foreach (SwitchSection ss in Sections){
+ target.Sections.Add (ss.Clone (clonectx));
+ }
+ }
}
public abstract class ExceptionStatement : Statement
ResolveFinally (branching);
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
- if (reachability.Returns != FlowBranching.FlowReturns.Always) {
- // Unfortunately, System.Reflection.Emit automatically emits
- // a leave to the end of the finally block.
- // This is a problem if `returns' is true since we may jump
- // to a point after the end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ ec.EndFlowBranching ();
- temp = new TemporaryVariable (expr.Type, loc);
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
+
+ // Avoid creating libraries that reference the internal
+ // mcs NullType:
+ Type t = expr.Type;
+ if (t == TypeManager.null_type)
+ t = TypeManager.object_type;
+
+ temp = new TemporaryVariable (t, loc);
temp.Resolve (ec);
return true;
temp.Emit (ec);
ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Lock target = (Lock) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class Unchecked : Statement {
- public readonly Block Block;
+ public Block Block;
public Unchecked (Block b)
{
public override bool Resolve (EmitContext ec)
{
- bool previous_state = ec.CheckState;
- bool previous_state_const = ec.ConstantCheckState;
-
- ec.CheckState = false;
- ec.ConstantCheckState = false;
- bool ret = Block.Resolve (ec);
- ec.CheckState = previous_state;
- ec.ConstantCheckState = previous_state_const;
-
- return ret;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- bool previous_state = ec.CheckState;
- bool previous_state_const = ec.ConstantCheckState;
-
- ec.CheckState = false;
- ec.ConstantCheckState = false;
- Block.Emit (ec);
- ec.CheckState = previous_state;
- ec.ConstantCheckState = previous_state_const;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ Block.Emit (ec);
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Unchecked target = (Unchecked) t;
+
+ target.Block = clonectx.LookupBlock (Block);
}
}
public class Checked : Statement {
- public readonly Block Block;
+ public Block Block;
public Checked (Block b)
{
public override bool Resolve (EmitContext ec)
{
- bool previous_state = ec.CheckState;
- bool previous_state_const = ec.ConstantCheckState;
-
- ec.CheckState = true;
- ec.ConstantCheckState = true;
- bool ret = Block.Resolve (ec);
- ec.CheckState = previous_state;
- ec.ConstantCheckState = previous_state_const;
-
- return ret;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- bool previous_state = ec.CheckState;
- bool previous_state_const = ec.ConstantCheckState;
-
- ec.CheckState = true;
- ec.ConstantCheckState = true;
- Block.Emit (ec);
- ec.CheckState = previous_state;
- ec.ConstantCheckState = previous_state_const;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ Block.Emit (ec);
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Checked target = (Checked) t;
+
+ target.Block = clonectx.LookupBlock (Block);
}
}
public class Unsafe : Statement {
- public readonly Block Block;
+ public Block Block;
public Unsafe (Block b)
{
public override bool Resolve (EmitContext ec)
{
- bool previous_state = ec.InUnsafe;
- bool val;
-
- ec.InUnsafe = true;
- val = Block.Resolve (ec);
- ec.InUnsafe = previous_state;
-
- return val;
+ using (ec.With (EmitContext.Flags.InUnsafe, true))
+ return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- bool previous_state = ec.InUnsafe;
-
- ec.InUnsafe = true;
- Block.Emit (ec);
- ec.InUnsafe = previous_state;
+ using (ec.With (EmitContext.Flags.InUnsafe, true))
+ Block.Emit (ec);
+ }
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Unsafe target = (Unsafe) t;
+
+ target.Block = clonectx.LookupBlock (Block);
}
}
}
public abstract void Emit (EmitContext ec);
- public abstract void EmitExit (ILGenerator ig);
+ public abstract void EmitExit (EmitContext ec);
}
class ExpressionEmitter : Emitter {
// Store pointer in pinned location
//
converted.Emit (ec);
- ec.ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ vi.Variable.EmitAssign (ec);
}
- public override void EmitExit (ILGenerator ig)
+ public override void EmitExit (EmitContext ec)
{
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Conv_U);
- ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Conv_U);
+ vi.Variable.EmitAssign (ec);
}
}
return;
converted.Emit (ec);
- ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ vi.Variable.EmitAssign (ec);
}
- public override void EmitExit(ILGenerator ig)
+ public override void EmitExit (EmitContext ec)
{
- ig.Emit (OpCodes.Ldnull);
- ig.Emit (OpCodes.Stloc, pinned_string);
+ ec.ig.Emit (OpCodes.Ldnull);
+ ec.ig.Emit (OpCodes.Stloc, pinned_string);
}
}
if (texpr == null)
return false;
- expr_type = texpr.ResolveType (ec);
+ expr_type = texpr.Type;
data = new Emitter [declarators.Count];
return false;
if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
- e.Error_ValueCannotBeConverted (e.Location, expr_type, false);
+ e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
return false;
}
if (has_ret)
return;
- ILGenerator ig = ec.ig;
-
//
// Clear the pinned variable
//
for (int i = 0; i < data.Length; i++) {
- data [i].EmitExit (ig);
+ data [i].EmitExit (ec);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Fixed target = (Fixed) t;
+
+ target.type = type.Clone (clonectx);
+ target.declarators = new ArrayList ();
+ foreach (LocalInfo var in declarators)
+ target.declarators.Add (clonectx.LookupVariable (var));
+ target.statement = statement.Clone (clonectx);
+ }
}
public class Catch : Statement {
public readonly string Name;
- public readonly Block Block;
+ public Block Block;
+ public Block VarBlock;
Expression type_expr;
Type type;
- public Catch (Expression type, string name, Block block, Location l)
+ public Catch (Expression type, string name, Block block, Block var_block, Location l)
{
type_expr = type;
Name = name;
Block = block;
+ VarBlock = var_block;
loc = l;
}
protected override void DoEmit(EmitContext ec)
{
+ ILGenerator ig = ec.ig;
+
+ if (CatchType != null)
+ ig.BeginCatchBlock (CatchType);
+ else
+ ig.BeginCatchBlock (TypeManager.object_type);
+
+ if (VarBlock != null)
+ VarBlock.Emit (ec);
+
+ if (Name != null) {
+ LocalInfo vi = Block.GetLocalInfo (Name);
+ if (vi == null)
+ throw new Exception ("Variable does not exist in this block");
+
+ if (vi.Variable.NeedsTemporary) {
+ LocalBuilder e = ig.DeclareLocal (vi.VariableType);
+ ig.Emit (OpCodes.Stloc, e);
+
+ vi.Variable.EmitInstance (ec);
+ ig.Emit (OpCodes.Ldloc, e);
+ vi.Variable.EmitAssign (ec);
+ } else
+ vi.Variable.EmitAssign (ec);
+ } else
+ ig.Emit (OpCodes.Pop);
+
+ Block.Emit (ec);
}
public override bool Resolve (EmitContext ec)
{
- bool was_catch = ec.InCatch;
- ec.InCatch = true;
- try {
+ using (ec.With (EmitContext.Flags.InCatch, true)) {
if (type_expr != null) {
TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
if (te == null)
return false;
- type = te.ResolveType (ec);
+ type = te.Type;
if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
Error (155, "The type caught or thrown must be derived from System.Exception");
} else
type = null;
- return Block.Resolve (ec);
- }
- finally {
- ec.InCatch = was_catch;
+ if (!Block.Resolve (ec))
+ return false;
+
+ // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
+ // emit the "unused variable" warnings.
+ if (VarBlock != null)
+ return VarBlock.Resolve (ec);
+
+ return true;
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Catch target = (Catch) t;
+
+ target.type_expr = type_expr.Clone (clonectx);
+ target.Block = clonectx.LookupBlock (Block);
+ target.VarBlock = clonectx.LookupBlock (VarBlock);
+ }
}
public class Try : ExceptionStatement {
- public readonly Block Fini, Block;
- public readonly ArrayList Specific;
- public readonly Catch General;
+ public Block Fini, Block;
+ public ArrayList Specific;
+ public Catch General;
bool need_exc_block;
if (Fini != null) {
if (ok)
- ec.CurrentBranching.CreateSibling (
- Fini, FlowBranching.SiblingType.Finally);
+ ec.CurrentBranching.CreateSibling (Fini, FlowBranching.SiblingType.Finally);
Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
- bool was_finally = ec.InFinally;
- ec.InFinally = true;
- if (!Fini.Resolve (ec))
- ok = false;
- ec.InFinally = was_finally;
+ using (ec.With (EmitContext.Flags.InFinally, true)) {
+ if (!Fini.Resolve (ec))
+ ok = false;
+ }
if (!ec.InIterator)
need_exc_block = true;
} else
emit_finally = Fini != null;
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+ ec.EndFlowBranching ();
- FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
- Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector);
+ FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
- if (reachability.Returns != FlowBranching.FlowReturns.Always) {
- // Unfortunately, System.Reflection.Emit automatically emits
- // a leave to the end of the finally block. This is a problem
- // if `returns' is true since we may jump to a point after the
- // end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ Report.Debug (1, "END OF TRY", ec.CurrentBranching, vector, f_vector);
return ok;
}
ig.BeginExceptionBlock ();
Block.Emit (ec);
- foreach (Catch c in Specific){
- LocalInfo vi;
-
- ig.BeginCatchBlock (c.CatchType);
-
- if (c.Name != null){
- vi = c.Block.GetLocalInfo (c.Name);
- if (vi == null)
- throw new Exception ("Variable does not exist in this block");
-
- if (vi.IsCaptured){
- LocalBuilder e = ig.DeclareLocal (vi.VariableType);
- ig.Emit (OpCodes.Stloc, e);
-
- ec.EmitCapturedVariableInstance (vi);
- ig.Emit (OpCodes.Ldloc, e);
- ig.Emit (OpCodes.Stfld, vi.FieldBuilder);
- } else
- ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
- } else
- ig.Emit (OpCodes.Pop);
-
- c.Block.Emit (ec);
- }
+ foreach (Catch c in Specific)
+ c.Emit (ec);
- if (General != null){
- ig.BeginCatchBlock (TypeManager.object_type);
- ig.Emit (OpCodes.Pop);
- General.Block.Emit (ec);
- }
+ if (General != null)
+ General.Emit (ec);
DoEmitFinally (ec);
if (need_exc_block)
return General != null || Specific.Count > 0;
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Try target = (Try) t;
+
+ target.Block = clonectx.LookupBlock (Block);
+ if (Fini != null)
+ target.Fini = clonectx.LookupBlock (Fini);
+ if (General != null)
+ target.General = (Catch) General.Clone (clonectx);
+ if (Specific != null){
+ target.Specific = new ArrayList ();
+ foreach (Catch c in Specific)
+ target.Specific.Add (c.Clone (clonectx));
+ }
+ }
}
public class Using : ExceptionStatement {
Expression [] resolved_vars;
Expression [] converted_vars;
ExpressionStatement [] assign;
- LocalBuilder local_copy;
+ TemporaryVariable local_copy;
public Using (object expression_or_block, Statement stmt, Location l)
{
if (texpr == null)
return false;
- expr_type = texpr.ResolveType (ec);
+ expr_type = texpr.Type;
//
// The type must be an IDisposable or an implicit conversion
}
}
+ local_copy = new TemporaryVariable (expr_type, loc);
+ local_copy.Resolve (ec);
+
return true;
}
ig.BeginExceptionBlock ();
}
Statement.Emit (ec);
+
var_list.Reverse ();
DoEmitFinally (ec);
Expression var = resolved_vars [--i];
Label skip = ig.DefineLabel ();
+ if (emit_finally)
+ ig.BeginFinallyBlock ();
+
if (!var.Type.IsValueType) {
var.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
converted_vars [i].Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
} else {
- Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
+ Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
if (!(ml is MethodGroupExpr)) {
var.Emit (ec);
// Make a copy of the expression and operate on that.
//
ILGenerator ig = ec.ig;
- local_copy = ig.DeclareLocal (expr_type);
- expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, local_copy);
+ local_copy.Store (ec, expr);
if (emit_finally)
ig.BeginExceptionBlock ();
void EmitExpressionFinally (EmitContext ec)
{
ILGenerator ig = ec.ig;
- if (!local_copy.LocalType.IsValueType) {
+ if (!expr_type.IsValueType) {
Label skip = ig.DefineLabel ();
- ig.Emit (OpCodes.Ldloc, local_copy);
+ local_copy.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
- ig.Emit (OpCodes.Ldloc, local_copy);
+ local_copy.Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (skip);
} else {
- Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, local_copy.LocalType, "Dispose", Mono.CSharp.Location.Null);
+ Expression ml = Expression.MemberLookup (
+ ec.ContainerType, TypeManager.idisposable_type, expr_type,
+ "Dispose", Location.Null);
if (!(ml is MethodGroupExpr)) {
- ig.Emit (OpCodes.Ldloc, local_copy);
- ig.Emit (OpCodes.Box, local_copy.LocalType);
+ local_copy.Emit (ec);
+ ig.Emit (OpCodes.Box, expr_type);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
} else {
MethodInfo mi = null;
return;
}
- ig.Emit (OpCodes.Ldloca, local_copy);
+ local_copy.AddressOf (ec, AddressOp.Load);
ig.Emit (OpCodes.Call, mi);
}
}
return false;
}
- ResolveFinally (branching);
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+ ResolveFinally (branching);
- if (reachability.Returns != FlowBranching.FlowReturns.Always) {
- // Unfortunately, System.Reflection.Emit automatically emits a leave
- // to the end of the finally block. This is a problem if `returns'
- // is true since we may jump to a point after the end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ ec.EndFlowBranching ();
+
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
return true;
}
else if (expression_or_block is Expression)
EmitExpressionFinally (ec);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Using target = (Using) t;
+
+ if (expression_or_block is Expression)
+ target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx);
+ else
+ target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx);
+
+ target.Statement = Statement.Clone (clonectx);
+ }
}
/// <summary>
Type var_type = texpr.Type;
- if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethod) {
+ if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
expr.ExprClassName);
return false;
{
EmitThis (ec);
ec.ig.Emit (OpCodes.Ldc_I4_0);
- EmitStore (ec.ig);
+ EmitStore (ec);
}
public void Increment (EmitContext ec)
Emit (ec);
ec.ig.Emit (OpCodes.Ldc_I4_1);
ec.ig.Emit (OpCodes.Add);
- EmitStore (ec.ig);
+ EmitStore (ec);
}
}
if (variable == null)
ok = false;
+ ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
if (!statement.Resolve (ec))
ok = false;
+ ec.EndFlowBranching ();
+
+ // There's no direct control flow from the end of the embedded statement to the end of the loop
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
ec.EndFlowBranching ();
lengths [i].EmitThis (ec);
((ArrayAccess) access).EmitGetLength (ec, i);
- lengths [i].EmitStore (ig);
+ lengths [i].EmitStore (ec);
}
for (int i = 0; i < rank; i++) {
// way I could do this without a goto
//
+#if GMCS_SOURCE
+ //
+ // Prefer a generic enumerator over a non-generic one.
+ //
+ if (return_type.IsInterface && return_type.IsGenericType) {
+ enumerator_type = return_type;
+ if (!FetchGetCurrent (ec, return_type))
+ get_current = new PropertyExpr (
+ ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+ if (!FetchMoveNext (return_type))
+ move_next = TypeManager.bool_movenext_void;
+ return true;
+ }
+#endif
+
if (return_type.IsInterface ||
- !FetchMoveNext (ec, return_type) ||
+ !FetchMoveNext (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);
+ ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
return true;
}
} else {
// find if they support the GetEnumerator pattern.
//
- if (TypeManager.HasElementType (return_type) || !FetchMoveNext (ec, return_type) || !FetchGetCurrent (ec, return_type)) {
+ 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",
TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
return false;
//
// Retrieves a `public bool MoveNext ()' method from the Type `t'
//
- bool FetchMoveNext (EmitContext ec, Type t)
+ bool FetchMoveNext (Type t)
{
MemberList move_next_list;
bool FetchGetCurrent (EmitContext ec, Type t)
{
PropertyExpr pe = Expression.MemberLookup (
- ec, t, "Current", MemberTypes.Property,
+ ec.ContainerType, t, "Current", MemberTypes.Property,
Expression.AllBindingFlags, loc) as PropertyExpr;
if (pe == null)
return false;
bool TryType (EmitContext ec, Type t)
{
MethodGroupExpr mg = Expression.MemberLookup (
- ec, t, "GetEnumerator", MemberTypes.Method,
+ ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
Expression.AllBindingFlags, loc) as MethodGroupExpr;
if (mg == null)
return false;
- foreach (MethodBase mb in mg.Methods) {
- if (TypeManager.GetParameterData (mb).Count != 0)
+ MethodInfo 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 (TypeManager.GetParameterData (mi).Count != 0)
continue;
// Check whether GetEnumerator is public
- if ((mb.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
+ if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
continue;
- if (TypeManager.IsOverride (mb))
+ if (TypeManager.IsOverride (mi))
continue;
enumerator_found = true;
- if (!GetEnumeratorFilter (ec, (MethodInfo) mb))
+ if (!GetEnumeratorFilter (ec, mi))
continue;
- MethodInfo[] mi = new MethodInfo[] { (MethodInfo) mb };
+ if (result != null) {
+ if (TypeManager.IsGenericType (result.ReturnType)) {
+ if (!TypeManager.IsGenericType (mi.ReturnType))
+ continue;
+
+ MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
+ Report.SymbolRelatedToPreviousError (t);
+ 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;
+ }
+
+ // Always prefer generics enumerators
+ if (!TypeManager.IsGenericType (mi.ReturnType)) {
+ if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
+ 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}'",
+ TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
+ return false;
+ }
+ }
+ result = mi;
+ tmp_move_next = move_next;
+ tmp_get_cur = get_current;
+ tmp_enumerator_type = enumerator_type;
+ if (mi.DeclaringType == t)
+ break;
+ }
+
+ 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) {
bool ProbeCollectionType (EmitContext ec, Type t)
{
+ int errors = 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)
+ return false;
+
//
// Now try to find the method in the interfaces
//
bool ok = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
- ec.CurrentBranching.CreateSibling ();
-
FlowBranchingException branching = null;
if (is_disposable)
branching = ec.StartFlowBranching (this);
} else
emit_finally = true;
- ec.EndFlowBranching ();
-
return ok;
}
ILGenerator ig = ec.ig;
if (enumerator_type.IsValueType) {
- enumerator.Emit (ec);
-
MethodInfo mi = FetchMethodDispose (enumerator_type);
if (mi != null) {
enumerator.EmitLoadAddress (ec);
statement.Emit (ec);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Foreach target = (Foreach) t;
+
+ target.type = type.Clone (clonectx);
+ target.variable = variable.Clone (clonectx);
+ target.expr = expr.Clone (clonectx);
+ target.statement = statement.Clone (clonectx);
+ }
}
}