// Martin Baulig (martin@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2001, 2002, 2003 Ximian, Inc.
-// (C) 2003, 2004 Novell, Inc.
+// Copyright 2001, 2002, 2003 Ximian, Inc.
+// Copyright 2003, 2004 Novell, Inc.
//
using System;
return Clone (clonectx);
}
+ public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
}
//
{
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement target)
{
// nothing needed.
loc = l;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ TrueStatement.MutateHoistedGenericType (storey);
+ if (FalseStatement != null)
+ FalseStatement.MutateHoistedGenericType (storey);
+ }
+
public override bool Resolve (EmitContext ec)
{
bool ok = true;
// If we're a boolean constant, Resolve() already
// eliminated dead code for us.
//
- if (expr is Constant){
-
- //
- // Simple bool constant
- //
- if (expr is BoolConstant) {
- bool take = ((BoolConstant) expr).Value;
-
- if (take)
- TrueStatement.Emit (ec);
- else if (FalseStatement != null)
- FalseStatement.Emit (ec);
-
- return;
- }
-
- //
- // Bool constant with side-effects
- //
- expr.Emit (ec);
- ig.Emit (OpCodes.Pop);
+ Constant c = expr as Constant;
+ if (c != null){
+ c.EmitSideEffect (ec);
- if (TrueStatement != null)
+ if (!c.IsDefaultValue)
TrueStatement.Emit (ec);
- if (FalseStatement != null)
+ else if (FalseStatement != null)
FalseStatement.Emit (ec);
return;
- }
+ }
expr.EmitBranchable (ec, false_target, false);
public class Do : Statement {
public Expression expr;
public Statement EmbeddedStatement;
- bool infinite;
public Do (Statement statement, Expression bool_expr, Location l)
{
expr = Expression.ResolveBoolean (ec, expr, loc);
if (expr == null)
ok = false;
- else if (expr is BoolConstant){
- bool res = ((BoolConstant) expr).Value;
-
- if (res)
- infinite = true;
+ else if (expr is Constant){
+ bool infinite = !((Constant) expr).IsDefaultValue;
+ if (infinite)
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
}
- if (infinite)
- ec.CurrentBranching.CurrentUsageVector.Goto ();
ec.EndFlowBranching ();
//
// Dead code elimination
//
- if (expr is BoolConstant){
- bool res = ((BoolConstant) expr).Value;
+ if (expr is Constant){
+ bool res = !((Constant) expr).IsDefaultValue;
+ expr.EmitSideEffect (ec);
if (res)
ec.ig.Emit (OpCodes.Br, loop);
} else
ec.LoopEnd = old_end;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ EmbeddedStatement.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Do target = (Do) t;
//
// Inform whether we are infinite or not
//
- if (expr is BoolConstant){
- BoolConstant bc = (BoolConstant) expr;
+ if (expr is Constant){
+ bool value = !((Constant) expr).IsDefaultValue;
- if (bc.Value == false){
+ if (value == false){
if (!Statement.ResolveUnreachable (ec, true))
return false;
empty = true;
protected override void DoEmit (EmitContext ec)
{
- if (empty)
+ if (empty) {
+ expr.EmitSideEffect (ec);
return;
+ }
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
//
// Inform whether we are infinite or not
//
- if (expr is BoolConstant){
+ if (expr is Constant){
+ // expr is 'true', since the 'empty' case above handles the 'false' case
ig.MarkLabel (ec.LoopBegin);
+ expr.EmitSideEffect (ec);
Statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
target.expr = expr.Clone (clonectx);
target.Statement = Statement.Clone (clonectx);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
+ }
}
public class For : Statement {
Test = Expression.ResolveBoolean (ec, Test, loc);
if (Test == null)
ok = false;
- else if (Test is BoolConstant){
- BoolConstant bc = (BoolConstant) Test;
+ else if (Test is Constant){
+ bool value = !((Constant) Test).IsDefaultValue;
- if (bc.Value == false){
+ if (value == false){
if (!Statement.ResolveUnreachable (ec, true))
return false;
if ((Increment != null) &&
return ok;
}
-
+
protected override void DoEmit (EmitContext ec)
{
- if (empty)
+ if (InitStatement != null && InitStatement != EmptyStatement.Value)
+ InitStatement.Emit (ec);
+
+ if (empty) {
+ Test.EmitSideEffect (ec);
return;
+ }
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
Label loop = ig.DefineLabel ();
Label test = ig.DefineLabel ();
-
- if (InitStatement != null && InitStatement != EmptyStatement.Value)
- InitStatement.Emit (ec);
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
if (Test != null){
//
// The Resolve code already catches the case for
- // Test == BoolConstant (false) so we know that
+ // Test == Constant (false) so we know that
// this is true
//
- if (Test is BoolConstant)
+ if (Test is Constant) {
+ Test.EmitSideEffect (ec);
ig.Emit (OpCodes.Br, loop);
- else
+ } else {
Test.EmitBranchable (ec, loop, true);
+ }
} else
ig.Emit (OpCodes.Br, loop);
ec.LoopEnd = old_end;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (InitStatement != null)
+ InitStatement.MutateHoistedGenericType (storey);
+ if (Test != null)
+ Test.MutateHoistedGenericType (storey);
+ if (Increment != null)
+ Increment.MutateHoistedGenericType (storey);
+
+ Statement.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
For target = (For) t;
expr.EmitStatement (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ }
+
public override string ToString ()
{
return "StatementExpression (" + expr + ")";
}
}
+ // A 'return' or a 'yield break'
+ public abstract class ExitStatement : Statement
+ {
+ protected bool unwind_protect;
+ protected abstract bool DoResolve (EmitContext ec);
+
+ public virtual void Error_FinallyClause ()
+ {
+ Report.Error (157, loc, "Control cannot leave the body of a finally clause");
+ }
+
+ public sealed override bool Resolve (EmitContext ec)
+ {
+ if (!DoResolve (ec))
+ return false;
+
+ unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
+ if (unwind_protect)
+ ec.NeedReturnLabel ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
+ return true;
+ }
+ }
+
/// <summary>
/// Implements the return statement
/// </summary>
- public class Return : Statement {
+ public class Return : ExitStatement {
protected Expression Expr;
- bool unwind_protect;
-
public Return (Expression expr, Location l)
{
Expr = expr;
loc = l;
}
- bool DoResolve (EmitContext ec)
+ protected override bool DoResolve (EmitContext ec)
{
if (Expr == null) {
if (ec.ReturnType == TypeManager.void_type)
return false;
}
- AnonymousContainer am = ec.CurrentAnonymousMethod;
+ AnonymousExpression am = ec.CurrentAnonymousMethod;
if ((am != null) && am.IsIterator && ec.InIterator) {
Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
"statement to return a value, or yield break to end the iteration");
return true;
}
-
- public override bool Resolve (EmitContext ec)
- {
- if (!DoResolve (ec))
- return false;
-
- unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
- if (unwind_protect)
- ec.NeedReturnLabel ();
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
- }
protected override void DoEmit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Ret);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (Expr != null)
+ Expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Return target = (Return) t;
Label l = label.LabelTarget (ec);
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
}
public class LabeledStatement : Statement {
ec.ig.MarkLabel (label);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
public void AddReference ()
{
referenced = true;
}
ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
}
/// <summary>
ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
GotoCase target = (GotoCase) t;
target.expr = expr.Clone (clonectx);
- target.sl = sl.Clone (clonectx);
}
}
{
ec.CurrentBranching.CurrentUsageVector.Goto ();
- if (expr != null){
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
-
- ExprClass eclass = expr.eclass;
+ if (expr == null)
+ return ec.CurrentBranching.CheckRethrow (loc);
- if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
- eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
- expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
- return false;
- }
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
- Type t = expr.Type;
-
- if ((t != TypeManager.exception_type) &&
- !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
- !(expr is NullLiteral)) {
- Error (155,
- "The type caught or thrown must be derived " +
- "from System.Exception");
- return false;
- }
- return true;
- }
+ ExprClass eclass = expr.eclass;
- if (!ec.InCatch) {
- Error (156, "A throw statement with no arguments is not allowed outside of a catch clause");
+ if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+ eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
+ expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
return false;
}
- if (ec.InFinally) {
- Error (724, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
+ Type t = expr.Type;
+
+ if ((t != TypeManager.exception_type) &&
+ !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
+ !(expr is NullLiteral)) {
+ Error (155, "The type caught or thrown must be derived from System.Exception");
return false;
}
return true;
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (expr != null)
+ expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Throw target = (Throw) t;
{
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
protected override void CloneTo (CloneContext clonectx, Statement t)
{
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
// nothing needed.
}
}
- public abstract class Variable
+ public interface ILocalVariable
{
- 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);
+ void Emit (EmitContext ec);
+ void EmitAssign (EmitContext ec);
+ void EmitAddressOf (EmitContext ec);
}
public interface IKnownVariable {
//
// The information about a user-perceived local variable
//
- public class LocalInfo : IKnownVariable {
- public Expression Type;
+ public class LocalInfo : IKnownVariable, ILocalVariable {
+ public readonly Expression Type;
public Type VariableType;
public readonly string Name;
public readonly Block Block;
public VariableInfo VariableInfo;
-
- Variable var;
- public Variable Variable {
- get { return var; }
- }
+ public HoistedVariable HoistedVariableReference;
[Flags]
enum Flags : byte {
ReadOnly = 2,
Pinned = 4,
IsThis = 8,
- Captured = 16,
AddressTaken = 32,
CompilerGenerated = 64,
IsConstant = 128
public void ResolveVariable (EmitContext ec)
{
- Block theblock = Block;
- if (theblock.ScopeInfo != null)
- var = theblock.ScopeInfo.GetCapturedVariable (this);
+ if (HoistedVariableReference != null)
+ return;
- if (var == null) {
+ if (builder == null) {
if (Pinned)
//
// This is needed to compile on both .NET 1.x and .NET 2.x
builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
else
builder = ec.ig.DeclareLocal (VariableType);
-
- var = new LocalVariable (this, builder);
}
}
+ public void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloc, builder);
+ }
+
+ public void EmitAssign (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Stloc, builder);
+ }
+
+ public void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloca, builder);
+ }
+
public void EmitSymbolInfo (EmitContext ec, string name)
{
if (builder != null)
public bool Resolve (EmitContext ec)
{
- if (VariableType == null) {
- TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
- if (texpr == null)
- return false;
+ if (VariableType != null)
+ return true;
+
+ TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
+ if (texpr == null)
+ return false;
- VariableType = texpr.Type;
- }
+ VariableType = texpr.Type;
if (TypeManager.IsGenericParameter (VariableType))
return true;
return true;
}
- public bool IsCaptured {
- get { return (flags & Flags.Captured) != 0; }
- set { flags |= Flags.Captured; }
- }
-
public bool IsConstant {
get { return (flags & Flags.IsConstant) != 0; }
set { flags |= Flags.IsConstant; }
get { return Location; }
}
- 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)
{
//
public Location EndLocation = Location.Null;
public ExplicitBlock Explicit;
- public ToplevelBlock Toplevel;
+ public ToplevelBlock Toplevel; // TODO: Use Explicit
[Flags]
public enum Flags : byte {
VariablesInitialized = 4,
HasRet = 8,
IsDestructor = 16,
- Unsafe = 32,
- HasVarargs = 64, // Used in ToplevelBlock
- IsIterator = 128
+ Unsafe = 32
}
protected Flags flags;
// The statements in this block
//
protected ArrayList statements;
- int num_statements;
//
// An array of Blocks. We keep track of children just
//
// Labels. (label, block) pairs.
//
- HybridDictionary labels;
+ protected HybridDictionary labels;
//
// Keeps track of (name, type) pairs
//
Block switch_block;
- // TODO: merge with scope_initializers
- ExpressionStatement scope_init;
ArrayList scope_initializers;
ArrayList anonymous_children;
int this_id;
int assignable_slots;
- protected ScopeInfo scope_info;
bool unreachable_shown;
bool unreachable;
}
}
- public ScopeInfo ScopeInfo {
- get { return scope_info; }
- }
-
- public ScopeInfo CreateScopeInfo ()
- {
- if (scope_info == null)
- scope_info = ScopeInfo.CreateScope (this);
-
- return scope_info;
- }
-
public ArrayList AnonymousChildren {
get { return anonymous_children; }
}
//
public virtual void EmitMeta (EmitContext ec)
{
- 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 (variables != null){
foreach (LocalInfo vi in variables.Values)
vi.ResolveVariable (ec);
((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
}
- if (children != null){
+ if (children != null) {
for (int i = 0; i < children.Count; i++)
((Block)children[i]).EmitMeta(ec);
}
}
- void UsageWarning (FlowBranching.UsageVector vector)
+ void UsageWarning ()
{
- string name;
-
- if ((variables != null) && (Report.WarningLevel >= 3)) {
- foreach (DictionaryEntry de in variables){
- LocalInfo vi = (LocalInfo) de.Value;
+ if (variables == null || Report.WarningLevel < 3)
+ return;
- if (vi.Used)
- continue;
+ foreach (DictionaryEntry de in variables) {
+ LocalInfo vi = (LocalInfo) de.Value;
- name = (string) de.Key;
+ if (!vi.Used) {
+ string name = (string) de.Key;
// vi.VariableInfo can be null for 'catch' variables
- if (vi.VariableInfo != null && vector.IsAssigned (vi.VariableInfo, true)){
+ if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
- } else {
+ else
Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
- }
}
}
}
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 if (s is Using)
+ body = ((Using) s).EmbeddedStatement;
+ else if (s is UsingTemporary)
+ body = ((UsingTemporary) s).Statement;
else
return;
if (unreachable && !(s is LabeledStatement) && !(s is Block))
statements [ix] = EmptyStatement.Value;
- num_statements = ix + 1;
-
unreachable = ec.CurrentBranching.CurrentUsageVector.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);
+ ec.CurrentBranching, statement_count);
while (ec.CurrentBranching is FlowBranchingLabeled)
ec.EndFlowBranching ();
- FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
+ bool flow_unreachable = ec.EndFlowBranching ();
ec.CurrentBlock = prev_block;
+ if (flow_unreachable)
+ flags |= Flags.HasRet;
+
// 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 == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
+ if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
ok = false;
if ((labels != null) && (Report.WarningLevel >= 2)) {
foreach (LabeledStatement label in labels.Values)
if (!label.HasBeenReferenced)
- Report.Warning (164, 2, label.loc,
- "This label has not been referenced");
+ Report.Warning (164, 2, label.loc, "This label has not been referenced");
}
- Report.Debug (4, "RESOLVE BLOCK DONE #2", StartLocation, vector);
-
- if (vector.IsUnreachable)
- flags |= Flags.HasRet;
-
- if (ok && (errors == Report.Errors)) {
- UsageWarning (vector);
- }
+ if (ok && errors == Report.Errors)
+ UsageWarning ();
return ok;
}
protected override void DoEmit (EmitContext ec)
{
- for (int ix = 0; ix < num_statements; ix++){
+ for (int ix = 0; ix < statements.Count; ix++){
Statement s = (Statement) statements [ix];
s.Emit (ec);
}
public override void Emit (EmitContext ec)
{
Block prev_block = ec.CurrentBlock;
-
ec.CurrentBlock = this;
- bool emit_debug_info = SymbolWriter.HasSymbolWriter;
- bool is_lexical_block = (this == Explicit) && (Parent != null) &&
- ((flags & Flags.IsIterator) == 0);
-
- bool omit_debug_info = ec.OmitDebuggingInfo;
-
- if (emit_debug_info) {
- if (is_lexical_block)
- ec.BeginScope ();
- }
-
- if ((scope_init != null) || (scope_initializers != null))
+ if (scope_initializers != null) {
SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
- if (scope_init != null) {
- ec.OmitDebuggingInfo = true;
- scope_init.EmitStatement (ec);
- ec.OmitDebuggingInfo = omit_debug_info;
- }
- if (scope_initializers != null) {
+ bool omit_debug_info = ec.OmitDebuggingInfo;
ec.OmitDebuggingInfo = true;
foreach (StatementExpression s in scope_initializers)
s.Emit (ec);
ec.OmitDebuggingInfo = omit_debug_info;
- }
- if ((scope_init != null) || (scope_initializers != null))
SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+ }
ec.Mark (StartLocation, true);
DoEmit (ec);
- if (emit_debug_info) {
- EmitSymbolInfo (ec);
-
- if (is_lexical_block)
- ec.EndScope ();
- }
-
ec.CurrentBlock = prev_block;
}
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ MutateVariables (storey);
+
+ foreach (Statement s in statements)
+ s.MutateHoistedGenericType (storey);
+ }
+
+ void MutateVariables (AnonymousMethodStorey storey)
+ {
+ if (variables != null) {
+ foreach (LocalInfo vi in variables.Values) {
+ vi.VariableType = storey.MutateType (vi.VariableType);
+ }
+ }
+
+ if (temporary_variables != null) {
+ foreach (LocalInfo vi in temporary_variables)
+ vi.VariableType = storey.MutateType (vi.VariableType);
+ }
+ }
+
public override string ToString ()
{
return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
}
public class ExplicitBlock : Block {
+ HybridDictionary known_variables;
+ protected AnonymousMethodStorey am_storey;
+
public ExplicitBlock (Block parent, Location start, Location end)
: this (parent, (Flags) 0, start, end)
{
this.Explicit = this;
}
- public bool IsIterator {
- get { return (flags & Flags.IsIterator) != 0; }
- }
-
- HybridDictionary known_variables;
-
// <summary>
// Marks a variable with name @name as being used in this or a child block.
// If a variable name has been used in a child block, it's illegal to
Parent.Explicit.AddKnownVariable (name, info);
}
+ public AnonymousMethodStorey AnonymousMethodStorey {
+ get { return am_storey; }
+ }
+
+ //
+ // Creates anonymous method storey in current block
+ //
+ public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
+ {
+ //
+ // When referencing a variable in iterator storey from children anonymous method
+ //
+ if (Toplevel.am_storey is IteratorStorey) {
+ ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
+ return Toplevel.am_storey;
+ }
+
+ //
+ // An iterator has only 1 storey block
+ //
+ if (ec.CurrentIterator != null)
+ return ec.CurrentIterator.Storey;
+
+ if (am_storey == null) {
+ MemberBase mc = ec.ResolveContext as MemberBase;
+ GenericMethod gm = mc == null ? null : mc.GenericMethod;
+
+ //
+ // Create anonymous method storey for this block
+ //
+ am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
+ }
+
+ //
+ // Creates a link between this block and the anonymous method
+ //
+ // An anonymous method can reference variables from any outer block, but they are
+ // hoisted in their own ExplicitBlock. When more than one block is referenced we
+ // need to create another link between those variable storeys
+ //
+ ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
+ return am_storey;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (am_storey != null)
+ am_storey.EmitHoistedVariables (ec);
+
+ bool emit_debug_info = SymbolWriter.HasSymbolWriter;
+ bool is_lexical_block = Parent != null && !(am_storey is IteratorStorey);
+ if (emit_debug_info && is_lexical_block)
+ ec.BeginScope ();
+
+ base.Emit (ec);
+
+ if (emit_debug_info) {
+ EmitSymbolInfo (ec);
+ if (is_lexical_block)
+ ec.EndScope ();
+ }
+ }
+
+ public override void EmitMeta (EmitContext ec)
+ {
+ base.EmitMeta (ec);
+
+ //
+ // It has to be done when all storey references are resolved
+ //
+ if (am_storey != null && am_storey.HasHoistedVariables)
+ am_storey.DefineMembers ();
+ }
+
+ protected override void EmitSymbolInfo (EmitContext ec)
+ {
+ if (am_storey != null)
+ SymbolWriter.DefineScopeVariable (am_storey.ID);
+
+ base.EmitSymbolInfo (ec);
+ }
+
internal IKnownVariable GetKnownVariable (string name)
{
return known_variables == null ? null : (IKnownVariable) known_variables [name];
}
+ public void PropagateStoreyReference (AnonymousMethodStorey s)
+ {
+ if (Parent != null && am_storey != s) {
+ if (am_storey != null)
+ am_storey.AddParentStoreyReference (s);
+
+ Parent.Explicit.PropagateStoreyReference (s);
+ }
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = base.Resolve (ec);
+
+ //
+ // Define an anonymous method storey when this block has hoisted variables
+ // otherwise the storey can be discarded
+ //
+ if (am_storey != null) {
+ if (am_storey.HasHoistedVariables) {
+ am_storey.DefineType ();
+ am_storey.DefineMembers ();
+ am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+ } else {
+ am_storey.Undo ();
+ am_storey = null;
+ }
+ }
+
+ return ok;
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
ExplicitBlock target = (ExplicitBlock) t;
public class ToplevelBlock : ExplicitBlock {
GenericMethod generic;
FlowBranchingToplevel top_level_branching;
- AnonymousContainer anonymous_container;
- RootScopeInfo root_scope;
Parameters parameters;
ToplevelParameterInfo[] parameter_info;
+ LocalInfo this_variable;
- public bool HasVarargs {
- get { return (flags & Flags.HasVarargs) != 0; }
- set { flags |= Flags.HasVarargs; }
- }
+ public HoistedVariable HoistedThisVariable;
//
// The parameters for the block.
get { return parameters; }
}
- public bool CompleteContexts (EmitContext ec)
- {
- Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope);
-
- if (root_scope != null)
- root_scope.LinkScopes ();
-
- if (Parent == 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 GenericMethod GenericMethod {
get { return generic; }
}
get { return Parent == null ? null : Parent.Toplevel; }
}
- public AnonymousContainer AnonymousContainer {
- get { return anonymous_container; }
- set { anonymous_container = value; }
- }
-
public ToplevelBlock (Block parent, Parameters parameters, Location start) :
this (parent, (Flags) 0, parameters, start)
{
{
}
- public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ ToplevelBlock (Flags flags, Parameters parameters, Location start) :
this (null, flags, parameters, start)
{
}
return true;
}
- public RootScopeInfo CreateRootScope (TypeContainer host)
- {
- if (root_scope != null)
- return root_scope;
-
- if (Container == null)
- root_scope = new RootScopeInfo (
- this, host, generic, StartLocation);
-
- if (scope_info != null)
- throw new InternalErrorException ();
-
- scope_info = root_scope;
- return root_scope;
- }
-
public override Expression CreateExpressionTree (EmitContext ec)
{
return ((Statement) statements [0]).CreateExpressionTree (ec);
}
- public void CreateIteratorHost (RootScopeInfo root)
+ //
+ // Reformats this block to be top-level iterator block
+ //
+ public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
{
- Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
+ // Create block with original statements
+ ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
- if (Parent != null || root_scope != null)
- throw new InternalErrorException ();
+ // TODO: Change to iter_block.statements = statements;
+ foreach (Statement stmt in source.statements)
+ iter_block.AddStatement (stmt);
+ labels = source.labels;
+
+ AddStatement (new IteratorStatement (iterator, iter_block));
- scope_info = root_scope = root;
- }
+ source.statements = new ArrayList (1);
+ source.AddStatement (new Return (iterator, iterator.Location));
- public RootScopeInfo RootScope {
- get {
- if (root_scope != null)
- return root_scope;
- else if (Container != null)
- return Container.RootScope;
- else
- return null;
- }
+ IteratorStorey iterator_storey = new IteratorStorey (iterator);
+ source.am_storey = iterator_storey;
+ return iterator_storey;
}
public FlowBranchingToplevel TopLevelBranching {
get { return top_level_branching; }
}
- //
- // This is used if anonymous methods are used inside an iterator
- // (see 2test-22.cs for an example).
- //
- // The AnonymousMethod is created while parsing - at a time when we don't
- // know yet that we're inside an iterator, so it's `Container' is initially
- // null. Later on, when resolving the iterator, we need to move the
- // anonymous method into that iterator.
- //
- public void ReParent (ToplevelBlock new_parent)
- {
- if ((flags & Flags.VariablesInitialized) != 0)
- throw new InternalErrorException ("block has already been resolved");
-
- Parent = new_parent;
- }
-
//
// Returns a `ParameterReference' for the given name, or null if there
// is no such parameter
return null;
}
- LocalInfo this_variable = null;
-
// <summary>
// Returns the "this" instance variable of this block.
// See AddThisVariable() for more information.
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
public override void EmitMeta (EmitContext ec)
{
+ parameters.ResolveVariable ();
+
// Avoid declaring an IL variable for this_variable since it is not accessed
// from the generated IL
if (this_variable != null)
Variables.Remove ("this");
base.EmitMeta (ec);
- parameters.ResolveVariable (this);
- }
-
- protected override void EmitSymbolInfo (EmitContext ec)
- {
- if ((AnonymousContainer != null) && (AnonymousContainer.Scope != null))
- SymbolWriter.DefineScopeVariable (AnonymousContainer.Scope.ID);
-
- base.EmitSymbolInfo (ec);
- }
-
- public void MakeIterator (Iterator iterator)
- {
- flags |= Flags.IsIterator;
-
- Block block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
- foreach (Statement stmt in statements)
- block.AddStatement (stmt);
- statements.Clear ();
- 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 ()
+ public override void Emit (EmitContext ec)
{
- return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation,
- root_scope, anonymous_container != null ?
- anonymous_container.Scope : null);
+ base.Emit (ec);
+ ec.Mark (EndLocation, true);
}
}
return null;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ foreach (SwitchSection ss in Sections)
+ ss.Block.MutateHoistedGenericType (storey);
+ }
+
public override bool Resolve (EmitContext ec)
{
Expr = Expr.Resolve (ec);
}
}
- public abstract class ExceptionStatement : Statement
+ // A place where execution can restart in an iterator
+ public abstract class ResumableStatement : Statement
+ {
+ bool prepared;
+ protected Label resume_point;
+
+ public Label PrepareForEmit (EmitContext ec)
+ {
+ if (!prepared) {
+ prepared = true;
+ resume_point = ec.ig.DefineLabel ();
+ }
+ return resume_point;
+ }
+
+ public virtual Label PrepareForDispose (EmitContext ec, Label end)
+ {
+ return end;
+ }
+ public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
+ {
+ }
+ }
+
+ // Base class for statements that are implemented in terms of try...finally
+ public abstract class ExceptionStatement : ResumableStatement
{
- public abstract void EmitFinallyBody (EmitContext ec);
+ bool code_follows;
- protected bool emit_finally = true;
+ protected abstract void EmitPreTryBody (EmitContext ec);
+ protected abstract void EmitTryBody (EmitContext ec);
+ protected abstract void EmitFinallyBody (EmitContext ec);
- protected void EmitFinally (EmitContext ec)
+ protected sealed override void DoEmit (EmitContext ec)
{
- Label end_finally = ec.ig.DefineLabel ();
- if (emit_finally)
- ec.ig.BeginFinallyBlock ();
- else if (ec.InIterator) {
- ec.ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
- ec.ig.Emit (OpCodes.Brtrue, end_finally);
+ ILGenerator ig = ec.ig;
+
+ EmitPreTryBody (ec);
+
+ if (resume_points != null) {
+ IntConstant.EmitInt (ig, (int) Iterator.State.Running);
+ ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
+ }
+
+ ig.BeginExceptionBlock ();
+
+ if (resume_points != null) {
+ ig.MarkLabel (resume_point);
+
+ // For normal control flow, we want to fall-through the Switch
+ // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
+ ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
+ IntConstant.EmitInt (ig, first_resume_pc);
+ ig.Emit (OpCodes.Sub);
+
+ Label [] labels = new Label [resume_points.Count];
+ for (int i = 0; i < resume_points.Count; ++i)
+ labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
+ ig.Emit (OpCodes.Switch, labels);
+ }
+
+ EmitTryBody (ec);
+
+ ig.BeginFinallyBlock ();
+
+ Label start_finally = ec.ig.DefineLabel ();
+ if (resume_points != null) {
+ ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
+ ig.Emit (OpCodes.Brfalse_S, start_finally);
+ ig.Emit (OpCodes.Endfinally);
}
+
+ ig.MarkLabel (start_finally);
EmitFinallyBody (ec);
- ec.ig.MarkLabel (end_finally);
+
+ ig.EndExceptionBlock ();
+ }
+
+ public void SomeCodeFollows ()
+ {
+ code_follows = true;
+ }
+
+ protected void ResolveReachability (EmitContext ec)
+ {
+ // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
+ // So, ensure there's some IL code after this statement.
+ if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+ ec.NeedReturnLabel ();
+
+ }
+
+ ArrayList resume_points;
+ int first_resume_pc;
+ public void AddResumePoint (ResumableStatement stmt, Location loc, int pc)
+ {
+ if (resume_points == null) {
+ resume_points = new ArrayList ();
+ first_resume_pc = pc;
+ }
+
+ if (pc != first_resume_pc + resume_points.Count)
+ throw new InternalErrorException ("missed an intervening AddResumePoint?");
+
+ resume_points.Add (stmt);
+ }
+
+ Label dispose_try_block;
+ bool prepared_for_dispose, emitted_dispose;
+ public override Label PrepareForDispose (EmitContext ec, Label end)
+ {
+ if (!prepared_for_dispose) {
+ prepared_for_dispose = true;
+ dispose_try_block = ec.ig.DefineLabel ();
+ }
+ return dispose_try_block;
}
- protected void ResolveFinally (FlowBranchingException branching)
+ public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
{
- emit_finally = branching.EmitFinally;
+ if (emitted_dispose)
+ return;
+
+ emitted_dispose = true;
+
+ ILGenerator ig = ec.ig;
+
+ Label end_of_try = ig.DefineLabel ();
+
+ // Ensure that the only way we can get into this code is through a dispatcher
+ if (have_dispatcher)
+ ig.Emit (OpCodes.Br, end);
+
+ ig.BeginExceptionBlock ();
+
+ ig.MarkLabel (dispose_try_block);
+
+ Label [] labels = null;
+ for (int i = 0; i < resume_points.Count; ++i) {
+ ResumableStatement s = (ResumableStatement) resume_points [i];
+ Label ret = s.PrepareForDispose (ec, end_of_try);
+ if (ret.Equals (end_of_try) && labels == null)
+ continue;
+ if (labels == null) {
+ labels = new Label [resume_points.Count];
+ for (int j = 0; j < i; ++j)
+ labels [j] = end_of_try;
+ }
+ labels [i] = ret;
+ }
+
+ if (labels != null) {
+ int j;
+ for (j = 1; j < labels.Length; ++j)
+ if (!labels [0].Equals (labels [j]))
+ break;
+ bool emit_dispatcher = j < labels.Length;
+
+ if (emit_dispatcher) {
+ //SymbolWriter.StartIteratorDispatcher (ec.ig);
+ ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
+ IntConstant.EmitInt (ig, first_resume_pc);
+ ig.Emit (OpCodes.Sub);
+ ig.Emit (OpCodes.Switch, labels);
+ //SymbolWriter.EndIteratorDispatcher (ec.ig);
+ }
+
+ foreach (ResumableStatement s in resume_points)
+ s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
+ }
+
+ ig.MarkLabel (end_of_try);
+
+ ig.BeginFinallyBlock ();
+
+ EmitFinallyBody (ec);
+
+ ig.EndExceptionBlock ();
}
}
return false;
}
- FlowBranchingException branching = ec.StartFlowBranching (this);
+ ec.StartFlowBranching (this);
bool ok = Statement.Resolve (ec);
-
- ResolveFinally (branching);
-
ec.EndFlowBranching ();
- // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
- // So, ensure there's some IL code after this statement.
- ec.NeedReturnLabel ();
+ ResolveReachability (ec);
// Avoid creating libraries that reference the internal
// mcs NullType:
return ok;
}
- protected override void DoEmit (EmitContext ec)
+ protected override void EmitPreTryBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
- temp.Store (ec, expr);
+ temp.EmitAssign (ec, expr);
temp.Emit (ec);
ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+ }
- // try
- if (emit_finally)
- ig.BeginExceptionBlock ();
+ protected override void EmitTryBody (EmitContext ec)
+ {
Statement.Emit (ec);
-
- // finally
- EmitFinally (ec);
- if (emit_finally)
- ig.EndExceptionBlock ();
}
- public override void EmitFinallyBody (EmitContext ec)
+ protected override void EmitFinallyBody (EmitContext ec)
{
temp.Emit (ec);
ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ temp.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
+ }
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Block.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Unchecked target = (Unchecked) t;
Block.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Checked target = (Checked) t;
using (ec.With (EmitContext.Flags.InUnsafe, true))
Block.Emit (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Unsafe target = (Unsafe) t;
// Store pointer in pinned location
//
converted.Emit (ec);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Ldc_I4_0);
ec.ig.Emit (OpCodes.Conv_U);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
}
class StringEmitter : Emitter {
+ class StringPtr : Expression
+ {
+ LocalBuilder b;
+
+ public StringPtr (LocalBuilder b, Location l)
+ {
+ this.b = b;
+ eclass = ExprClass.Value;
+ type = TypeManager.char_ptr_type;
+ loc = l;
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (TypeManager.int_get_offset_to_string_data == null) {
+ // TODO: Move to resolve !!
+ TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
+ TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
+ }
+
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldloc, b);
+ ig.Emit (OpCodes.Conv_I);
+ ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
+ ig.Emit (OpCodes.Add);
+ }
+ }
+
LocalBuilder pinned_string;
Location loc;
return;
converted.Emit (ec);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ // Fixed statement cannot be used inside anonymous methods or lambdas
+ throw new NotSupportedException ();
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Fixed target = (Fixed) t;
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);
+ // TODO: Move to resolve
+ LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
+ lvr.Resolve (ec);
+
+ Expression source;
+ if (lvr.IsHoisted) {
+ LocalTemporary lt = new LocalTemporary (lvr.Type);
+ lt.Store (ec);
+ source = lt;
+ } else {
+ // Variable is at the top of the stack
+ source = EmptyExpression.Null;
+ }
- vi.Variable.EmitInstance (ec);
- ig.Emit (OpCodes.Ldloc, e);
- vi.Variable.EmitAssign (ec);
- } else
- vi.Variable.EmitAssign (ec);
+ lvr.EmitAssign (ec, source, false, false);
} else
ig.Emit (OpCodes.Pop);
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (type != null)
+ type = storey.MutateType (type);
+ if (VarBlock != null)
+ VarBlock.MutateHoistedGenericType (storey);
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Catch target = (Catch) t;
{
bool ok = true;
- FlowBranchingException branching = ec.StartFlowBranching (this);
+ ec.StartFlowBranching (this);
if (!stmt.Resolve (ec))
ok = false;
ok = false;
}
- ResolveFinally (branching);
ec.EndFlowBranching ();
- // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
- // So, ensure there's some IL code after this statement.
- ec.NeedReturnLabel ();
+ ResolveReachability (ec);
return ok;
}
- protected override void DoEmit (EmitContext ec)
+ protected override void EmitPreTryBody (EmitContext ec)
{
- ILGenerator ig = ec.ig;
+ }
- if (emit_finally)
- ig.BeginExceptionBlock ();
+ protected override void EmitTryBody (EmitContext ec)
+ {
stmt.Emit (ec);
-
- EmitFinally (ec);
- if (emit_finally)
- ig.EndExceptionBlock ();
}
- public override void EmitFinallyBody (EmitContext ec)
+ protected override void EmitFinallyBody (EmitContext ec)
{
fini.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ stmt.MutateHoistedGenericType (storey);
+ fini.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
TryFinally target = (TryFinally) t;
public Block Block;
public ArrayList Specific;
public Catch General;
- bool inside_try_finally;
+ bool inside_try_finally, code_follows;
public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
{
{
bool ok = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.TryCatch, loc);
+ ec.StartFlowBranching (this);
if (!Block.Resolve (ec))
ok = false;
// System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
// So, ensure there's some IL code after this statement
- ec.NeedReturnLabel ();
+ if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+ ec.NeedReturnLabel ();
return ok;
}
+
+ public void SomeCodeFollows ()
+ {
+ code_follows = true;
+ }
protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- // FIXME: remove the InIterator
- if (!inside_try_finally || ec.InIterator)
+ if (!inside_try_finally)
ig.BeginExceptionBlock ();
Block.Emit (ec);
if (General != null)
General.Emit (ec);
- // FIXME: remove the InIterator
- if (!inside_try_finally || ec.InIterator)
+ if (!inside_try_finally)
ig.EndExceptionBlock ();
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+
+ if (General != null)
+ General.MutateHoistedGenericType (storey);
+ if (Specific != null) {
+ foreach (Catch c in Specific)
+ c.MutateHoistedGenericType (storey);
+ }
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
TryCatch target = (TryCatch) t;
}
}
- public class Using : ExceptionStatement {
- object expression_or_block;
+ public class UsingTemporary : ExceptionStatement {
+ TemporaryVariable local_copy;
public Statement Statement;
- ArrayList var_list;
Expression expr;
Type expr_type;
- Expression [] resolved_vars;
- Expression [] converted_vars;
- Expression [] assign;
- TemporaryVariable local_copy;
-
- public Using (object expression_or_block, Statement stmt, Location l)
+
+ public UsingTemporary (Expression expr, Statement stmt, Location l)
{
- this.expression_or_block = expression_or_block;
+ this.expr = expr;
Statement = stmt;
loc = l;
}
- //
- // Resolves for the case of using using a local variable declaration.
- //
- bool ResolveLocalVariableDecls (EmitContext ec)
+ public override bool Resolve (EmitContext ec)
{
- resolved_vars = new Expression[var_list.Count];
- assign = new Expression [var_list.Count];
- converted_vars = new Expression[var_list.Count];
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return false;
- for (int i = 0; i < assign.Length; ++i) {
- DictionaryEntry e = (DictionaryEntry) var_list [i];
- Expression var = (Expression) e.Key;
- Expression new_expr = (Expression) e.Value;
+ expr_type = expr.Type;
- Expression a = new Assign (var, new_expr, loc);
- a = a.Resolve (ec);
- if (a == null)
+ if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
+ if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
+ Using.Error_IsNotConvertibleToIDisposable (expr);
return false;
+ }
+ }
- resolved_vars [i] = var;
- assign [i] = a;
+ local_copy = new TemporaryVariable (expr_type, loc);
+ local_copy.Resolve (ec);
- if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
- converted_vars [i] = var;
- continue;
- }
+ ec.StartFlowBranching (this);
- a = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
- if (a == null) {
- Error_IsNotConvertibleToIDisposable (var);
- return false;
- }
+ bool ok = Statement.Resolve (ec);
+
+ ec.EndFlowBranching ();
+
+ ResolveReachability (ec);
- converted_vars [i] = a;
+ if (TypeManager.void_dispose_void == null) {
+ TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
+ TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
}
- return true;
+ return ok;
}
- static void Error_IsNotConvertibleToIDisposable (Expression expr)
+ protected override void EmitPreTryBody (EmitContext ec)
{
- Report.SymbolRelatedToPreviousError (expr.Type);
- Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
- expr.GetSignatureForError ());
+ local_copy.EmitAssign (ec, expr);
}
- bool ResolveExpression (EmitContext ec)
+ protected override void EmitTryBody (EmitContext ec)
{
- if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
- if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
- Error_IsNotConvertibleToIDisposable (expr);
- return false;
- }
- }
-
- local_copy = new TemporaryVariable (expr_type, loc);
- local_copy.Resolve (ec);
-
- return true;
+ Statement.Emit (ec);
}
-
- //
- // Emits the code for the case of using using a local variable declaration.
- //
- void EmitLocalVariableDecls (EmitContext ec)
+
+ protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
- int i = 0;
+ if (!expr_type.IsValueType) {
+ Label skip = ig.DefineLabel ();
+ local_copy.Emit (ec);
+ ig.Emit (OpCodes.Brfalse, skip);
+ local_copy.Emit (ec);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ ig.MarkLabel (skip);
+ return;
+ }
+
+ Expression ml = Expression.MemberLookup (
+ ec.ContainerType, TypeManager.idisposable_type, expr_type,
+ "Dispose", Location.Null);
+
+ if (!(ml is MethodGroupExpr)) {
+ local_copy.Emit (ec);
+ ig.Emit (OpCodes.Box, expr_type);
+ ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ return;
+ }
- for (i = 0; i < assign.Length; i++) {
- ExpressionStatement es = assign [i] as ExpressionStatement;
+ MethodInfo mi = null;
- if (es != null)
- es.EmitStatement (ec);
- else {
- assign [i].Emit (ec);
- ig.Emit (OpCodes.Pop);
+ foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
+ if (TypeManager.GetParameterData (mk).Count == 0) {
+ mi = mk;
+ break;
}
+ }
- if (emit_finally)
- ig.BeginExceptionBlock ();
+ if (mi == null) {
+ Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+ return;
}
- Statement.Emit (ec);
- var_list.Reverse ();
+ local_copy.AddressOf (ec, AddressOp.Load);
+ ig.Emit (OpCodes.Call, mi);
+ }
- EmitFinally (ec);
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr_type = storey.MutateType (expr_type);
+ local_copy.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
}
- void EmitLocalVariableDeclFinally (EmitContext ec)
+ protected override void CloneTo (CloneContext clonectx, Statement t)
{
- ILGenerator ig = ec.ig;
+ UsingTemporary target = (UsingTemporary) t;
- int i = assign.Length;
- for (int ii = 0; ii < var_list.Count; ++ii){
- Expression var = resolved_vars [--i];
- Label skip = ig.DefineLabel ();
+ target.expr = expr.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
+ }
- 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.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
+ public class Using : ExceptionStatement {
+ Statement stmt;
+ public Statement EmbeddedStatement {
+ get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
+ }
- if (!(ml is MethodGroupExpr)) {
- var.Emit (ec);
- ig.Emit (OpCodes.Box, var.Type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- } else {
- MethodInfo mi = null;
+ Expression var;
+ Expression init;
- foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
- if (TypeManager.GetParameterData (mk).Count == 0) {
- mi = mk;
- break;
- }
- }
+ Expression converted_var;
+ ExpressionStatement assign;
- if (mi == null) {
- Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
- return;
- }
+ public Using (Expression var, Expression init, Statement stmt, Location l)
+ {
+ this.var = var;
+ this.init = init;
+ this.stmt = stmt;
+ loc = l;
+ }
- IMemoryLocation mloc = (IMemoryLocation) var;
+ bool ResolveVariable (EmitContext ec)
+ {
+ ExpressionStatement a = new SimpleAssign (var, init, loc);
+ a = a.ResolveStatement (ec);
+ if (a == null)
+ return false;
- mloc.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- }
- }
+ assign = a;
- ig.MarkLabel (skip);
+ if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+ converted_var = var;
+ return true;
+ }
- if (emit_finally) {
- ig.EndExceptionBlock ();
- if (i > 0)
- ig.BeginFinallyBlock ();
- }
+ Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
+ if (e == null) {
+ Error_IsNotConvertibleToIDisposable (var);
+ return false;
}
+
+ converted_var = e;
+
+ return true;
}
- void EmitExpression (EmitContext ec)
+ static public void Error_IsNotConvertibleToIDisposable (Expression expr)
{
- //
- // Make a copy of the expression and operate on that.
- //
- ILGenerator ig = ec.ig;
-
- local_copy.Store (ec, expr);
+ Report.SymbolRelatedToPreviousError (expr.Type);
+ Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+ expr.GetSignatureForError ());
+ }
- if (emit_finally)
- ig.BeginExceptionBlock ();
+ protected override void EmitPreTryBody (EmitContext ec)
+ {
+ assign.EmitStatement (ec);
+ }
- Statement.Emit (ec);
-
- EmitFinally (ec);
- if (emit_finally)
- ig.EndExceptionBlock ();
+ protected override void EmitTryBody (EmitContext ec)
+ {
+ stmt.Emit (ec);
}
- void EmitExpressionFinally (EmitContext ec)
+ protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
- if (!expr_type.IsValueType) {
+
+ if (!var.Type.IsValueType) {
Label skip = ig.DefineLabel ();
- local_copy.Emit (ec);
+ var.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
- local_copy.Emit (ec);
+ converted_var.Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (skip);
} else {
- Expression ml = Expression.MemberLookup (
- ec.ContainerType, TypeManager.idisposable_type, expr_type,
- "Dispose", Location.Null);
+ Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
if (!(ml is MethodGroupExpr)) {
- local_copy.Emit (ec);
- ig.Emit (OpCodes.Box, expr_type);
+ var.Emit (ec);
+ ig.Emit (OpCodes.Box, var.Type);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
} else {
MethodInfo mi = null;
return;
}
- local_copy.AddressOf (ec, AddressOp.Load);
+ IMemoryLocation mloc = (IMemoryLocation) var;
+
+ mloc.AddressOf (ec, AddressOp.Load);
ig.Emit (OpCodes.Call, mi);
}
}
}
-
- public override bool Resolve (EmitContext ec)
- {
- if (expression_or_block is DictionaryEntry){
- expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
- var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
- if (!ResolveLocalVariableDecls (ec))
- return false;
-
- } else if (expression_or_block is Expression){
- expr = (Expression) expression_or_block;
-
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
-
- expr_type = expr.Type;
-
- if (!ResolveExpression (ec))
- return false;
- }
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ assign.MutateHoistedGenericType (storey);
+ var.MutateHoistedGenericType (storey);
+ stmt.MutateHoistedGenericType (storey);
+ }
- FlowBranchingException branching = ec.StartFlowBranching (this);
+ public override bool Resolve (EmitContext ec)
+ {
+ if (!ResolveVariable (ec))
+ return false;
- bool ok = Statement.Resolve (ec);
+ ec.StartFlowBranching (this);
- ResolveFinally (branching);
+ bool ok = stmt.Resolve (ec);
ec.EndFlowBranching ();
- // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
- // So, ensure there's some IL code after this statement.
- ec.NeedReturnLabel ();
+ ResolveReachability (ec);
if (TypeManager.void_dispose_void == null) {
TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
return ok;
}
-
- protected override void DoEmit (EmitContext ec)
- {
- if (expression_or_block is DictionaryEntry)
- EmitLocalVariableDecls (ec);
- else if (expression_or_block is Expression)
- EmitExpression (ec);
- }
-
- public override void EmitFinallyBody (EmitContext ec)
- {
- if (expression_or_block is DictionaryEntry)
- EmitLocalVariableDeclFinally (ec);
- 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 {
- DictionaryEntry de = (DictionaryEntry) expression_or_block;
- ArrayList var_list = (ArrayList) de.Value;
- ArrayList target_var_list = new ArrayList (var_list.Count);
-
- foreach (DictionaryEntry de_variable in var_list)
- target_var_list.Add (new DictionaryEntry (
- ((Expression) de_variable.Key).Clone (clonectx),
- ((Expression) de_variable.Value).Clone (clonectx)));
-
- target.expression_or_block = new DictionaryEntry (
- ((Expression) de.Key).Clone (clonectx),
- target_var_list);
- }
-
- target.Statement = Statement.Clone (clonectx);
+ target.var = var.Clone (clonectx);
+ target.init = init.Clone (clonectx);
+ target.stmt = stmt.Clone (clonectx);
}
}
Expression variable;
Expression expr;
Statement statement;
- ArrayForeach array;
- CollectionForeach collection;
public Foreach (Expression type, LocalVariableReference var, Expression expr,
Statement stmt, Location l)
return false;
}
- //
- // We need an instance variable. Not sure this is the best
- // way of doing this.
- //
- // FIXME: When we implement propertyaccess, will those turn
- // out to return values in ExprClass? I think they should.
- //
- if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
- expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
- collection.Error_Enumerator ();
- return false;
- }
-
if (expr.Type.IsArray) {
- array = new ArrayForeach (type, variable, expr, statement, loc);
- return array.Resolve (ec);
+ statement = new ArrayForeach (type, variable, expr, statement, loc);
+ } else {
+ statement = new CollectionForeach (type, variable, expr, statement, loc);
}
- collection = new CollectionForeach (type, variable, expr, statement, loc);
- return collection.Resolve (ec);
+ return statement.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- if (collection != null)
- collection.Emit (ec);
- else
- array.Emit (ec);
+ statement.Emit (ec);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
protected class ArrayCounter : TemporaryVariable
{
+ StatementExpression increment;
+
public ArrayCounter (Location loc)
: base (TypeManager.int32_type, loc)
- { }
+ {
+ }
- public void Initialize (EmitContext ec)
+ public void ResolveIncrement (EmitContext ec)
{
- EmitThis (ec);
- ec.ig.Emit (OpCodes.Ldc_I4_0);
- EmitStore (ec);
+ increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
+ increment.Resolve (ec);
}
- public void Increment (EmitContext ec)
+ public void EmitIncrement (EmitContext ec)
{
- EmitThis (ec);
- Emit (ec);
- ec.ig.Emit (OpCodes.Ldc_I4_1);
- ec.ig.Emit (OpCodes.Add);
- EmitStore (ec);
+ increment.Emit (ec);
}
}
TemporaryVariable copy;
Expression access;
+ Expression[] length_exprs;
public ArrayForeach (Expression var_type, Expression var,
Expression expr, Statement stmt, Location l)
counter = new ArrayCounter [rank];
lengths = new TemporaryVariable [rank];
+ length_exprs = new Expression [rank];
- ArrayList list = new ArrayList ();
+ ArrayList list = new ArrayList (rank);
for (int i = 0; i < rank; i++) {
counter [i] = new ArrayCounter (loc);
- counter [i].Resolve (ec);
+ counter [i].ResolveIncrement (ec);
lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
lengths [i].Resolve (ec);
+ if (rank == 1) {
+ length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
+ } else {
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (new IntConstant (i, loc)));
+ length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
+ }
+
list.Add (counter [i]);
}
{
ILGenerator ig = ec.ig;
- copy.Store (ec, expr);
+ copy.EmitAssign (ec, expr);
Label[] test = new Label [rank];
Label[] loop = new Label [rank];
test [i] = ig.DefineLabel ();
loop [i] = ig.DefineLabel ();
- lengths [i].EmitThis (ec);
- ((ArrayAccess) access).EmitGetLength (ec, i);
- lengths [i].EmitStore (ec);
+ lengths [i].EmitAssign (ec, length_exprs [i]);
}
+ IntConstant zero = new IntConstant (0, loc);
for (int i = 0; i < rank; i++) {
- counter [i].Initialize (ec);
+ counter [i].EmitAssign (ec, zero);
ig.Emit (OpCodes.Br, test [i]);
ig.MarkLabel (loop [i]);
ig.MarkLabel (ec.LoopBegin);
for (int i = rank - 1; i >= 0; i--){
- counter [i].Increment (ec);
+ counter [i].EmitIncrement (ec);
ig.MarkLabel (test [i]);
counter [i].Emit (ec);
ig.MarkLabel (ec.LoopEnd);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ copy.MutateHoistedGenericType (storey);
+ conv.MutateHoistedGenericType (storey);
+ variable.MutateHoistedGenericType (storey);
+ statement.MutateHoistedGenericType (storey);
+
+ for (int i = 0; i < rank; i++) {
+ counter [i].MutateHoistedGenericType (storey);
+ lengths [i].MutateHoistedGenericType (storey);
+ }
+ }
}
protected class CollectionForeach : Statement
TemporaryVariable enumerator;
Expression init;
Statement loop;
+ Statement wrapper;
MethodGroupExpr get_enumerator;
PropertyExpr get_current;
return null;
}
- public void Error_Enumerator ()
+ void Error_Enumerator ()
{
if (enumerator_found) {
return;
loop = new While (move_next_expr, block, loc);
- if (is_disposable)
- loop = new DisposableWrapper (this, loop);
-
- return loop.Resolve (ec);
+ wrapper = is_disposable ?
+ (Statement) new DisposableWrapper (this) :
+ (Statement) new NonDisposableWrapper (this);
+ return wrapper.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- enumerator.Store (ec, init);
- loop.Emit (ec);
+ wrapper.Emit (ec);
+ }
+
+ class NonDisposableWrapper : Statement {
+ CollectionForeach parent;
+
+ internal NonDisposableWrapper (CollectionForeach parent)
+ {
+ this.parent = parent;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ return parent.ResolveLoop (ec);
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ parent.EmitLoopInit (ec);
+ parent.EmitLoopBody (ec);
+ }
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ throw new NotSupportedException ();
+ }
}
class DisposableWrapper : ExceptionStatement {
CollectionForeach parent;
- Statement loop;
- internal DisposableWrapper (CollectionForeach parent, Statement loop)
+ internal DisposableWrapper (CollectionForeach parent)
{
this.parent = parent;
- this.loop = loop;
}
public override bool Resolve (EmitContext ec)
{
bool ok = true;
- FlowBranchingException branching = ec.StartFlowBranching (this);
+ ec.StartFlowBranching (this);
- if (!loop.Resolve (ec))
+ if (!parent.ResolveLoop (ec))
ok = false;
- ResolveFinally (branching);
ec.EndFlowBranching ();
+ ResolveReachability (ec);
+
if (TypeManager.void_dispose_void == null) {
TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
return ok;
}
- protected override void DoEmit (EmitContext ec)
+ protected override void EmitPreTryBody (EmitContext ec)
{
- ILGenerator ig = ec.ig;
+ parent.EmitLoopInit (ec);
+ }
- if (emit_finally)
- ig.BeginExceptionBlock ();
- loop.Emit (ec);
- EmitFinally (ec);
- if (emit_finally)
- ig.EndExceptionBlock ();
+ protected override void EmitTryBody (EmitContext ec)
+ {
+ parent.EmitLoopBody (ec);
}
- public override void EmitFinallyBody (EmitContext ec)
+ protected override void EmitFinallyBody (EmitContext ec)
{
parent.EmitFinallyBody (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ throw new NotSupportedException ();
+ }
+ }
+
+ bool ResolveLoop (EmitContext ec)
+ {
+ return loop.Resolve (ec);
+ }
+
+ void EmitLoopInit (EmitContext ec)
+ {
+ enumerator.EmitAssign (ec, init);
+ }
+
+ void EmitLoopBody (EmitContext ec)
+ {
+ loop.Emit (ec);
}
void EmitFinallyBody (EmitContext ec)
if (enumerator_type.IsValueType) {
MethodInfo mi = FetchMethodDispose (enumerator_type);
if (mi != null) {
- enumerator.EmitLoadAddress (ec);
+ enumerator.AddressOf (ec, AddressOp.Load);
ig.Emit (OpCodes.Call, mi);
} else {
enumerator.Emit (ec);
ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
ig.Emit (OpCodes.Dup);
ig.Emit (OpCodes.Brtrue_S, call_dispose);
- ig.Emit (OpCodes.Pop);
- Label end_finally = ig.DefineLabel ();
- ig.Emit (OpCodes.Br, end_finally);
+ // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
+ // (Partition III, Section 3.35)
+ ig.Emit (OpCodes.Endfinally);
ig.MarkLabel (call_dispose);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- ig.MarkLabel (end_finally);
}
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ enumerator_type = storey.MutateType (enumerator_type);
+ init.MutateHoistedGenericType (storey);
+ loop.MutateHoistedGenericType (storey);
+ }
}
protected class CollectionForeachStatement : Statement
if (conv == null)
return false;
- assign = new Assign (variable, conv, loc);
+ assign = new SimpleAssign (variable, conv, loc);
if (assign.Resolve (ec) == null)
return false;
assign.EmitStatement (ec);
statement.Emit (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ assign.MutateHoistedGenericType (storey);
+ statement.MutateHoistedGenericType (storey);
+ }
}
protected override void CloneTo (CloneContext clonectx, Statement t)
target.expr = expr.Clone (clonectx);
target.statement = statement.Clone (clonectx);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ statement.MutateHoistedGenericType (storey);
+ }
}
}