/// <summary>
/// Resolves the statement, true means that all sub-statements
/// did resolve ok.
- // </summary>
+ /// </summary>
public virtual bool Resolve (BlockContext bc)
{
return true;
}
ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
bool ok = Resolve (ec);
ec.KillFlowBranching ();
return false;
empty = true;
return true;
- } else
- infinite = true;
+ }
+
+ infinite = true;
}
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
return false;
empty = true;
return true;
- } else
- infinite = true;
+ }
+
+ infinite = true;
}
} else
infinite = true;
public class StatementErrorExpression : Statement
{
- readonly Expression expr;
+ Expression expr;
public StatementErrorExpression (Expression expr)
{
this.expr = expr;
+ this.loc = expr.StartLocation;
}
public Expression Expr {
}
}
+ public override bool Resolve (BlockContext bc)
+ {
+ expr.Error_InvalidExpressionStatement (bc);
+ return true;
+ }
+
protected override void DoEmit (EmitContext ec)
{
throw new NotSupportedException ();
protected override void CloneTo (CloneContext clonectx, Statement target)
{
- throw new NotImplementedException ();
+ var t = (StatementErrorExpression) target;
+
+ t.expr = expr.Clone (clonectx);
}
public override object Accept (StructuralVisitor visitor)
public StatementList (Statement first, Statement second)
{
- statements = new List<Statement> () { first, second };
+ statements = new List<Statement> { first, second };
}
#region Properties
if (this is ContextualReturn)
return true;
- ec.Report.Error (1997, loc,
- "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
- ec.GetSignatureForError ());
+ // Same error code as .NET but better error message
+ if (async_block.DelegateType != null) {
+ ec.Report.Error (1997, loc,
+ "`{0}': A return keyword must not be followed by an expression when async delegate returns `Task'. Consider using `Task<T>' return type",
+ async_block.DelegateType.GetSignatureForError ());
+ } else {
+ ec.Report.Error (1997, loc,
+ "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
+ ec.GetSignatureForError ());
+
+ }
+
return false;
}
return false;
}
- if (ec.Switch.DefaultLabel == null) {
- FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
- return false;
- }
+ ec.Switch.RegisterGotoCase (null, null);
return true;
}
/// </summary>
public class GotoCase : Statement {
Expression expr;
- SwitchLabel sl;
public GotoCase (Expression e, Location l)
{
return this.expr;
}
}
+
+ public SwitchLabel Label { get; set; }
public override bool Resolve (BlockContext ec)
{
ec.CurrentBranching.CurrentUsageVector.Goto ();
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
-
- Constant c = expr as Constant;
+ Constant c = expr.ResolveLabelConstant (ec);
if (c == null) {
- ec.Report.Error (150, expr.Location, "A constant value is expected");
return false;
}
if (!Convert.ImplicitStandardConversionExists (c, type))
ec.Report.Warning (469, 2, loc,
"The `goto case' value is not implicitly convertible to type `{0}'",
- TypeManager.CSharpName (type));
+ type.GetSignatureForError ());
}
- sl = ec.Switch.ResolveGotoCase (ec, res);
+ ec.Switch.RegisterGotoCase (this, res);
return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.Emit (OpCodes.Br, sl.GetILLabel (ec));
+ ec.Emit (OpCodes.Br, Label.GetILLabel (ec));
}
protected override void CloneTo (CloneContext clonectx, Statement t)
Location Location { get; }
}
- public class BlockVariableDeclaration : Statement
+ public class BlockVariableDeclarator
{
- public class Declarator
+ LocalVariable li;
+ Expression initializer;
+
+ public BlockVariableDeclarator (LocalVariable li, Expression initializer)
{
- LocalVariable li;
- Expression initializer;
+ if (li.Type != null)
+ throw new ArgumentException ("Expected null variable type");
- public Declarator (LocalVariable li, Expression initializer)
- {
- if (li.Type != null)
- throw new ArgumentException ("Expected null variable type");
+ this.li = li;
+ this.initializer = initializer;
+ }
- this.li = li;
- this.initializer = initializer;
- }
+ #region Properties
- public Declarator (Declarator clone, Expression initializer)
- {
- this.li = clone.li;
- this.initializer = initializer;
+ public LocalVariable Variable {
+ get {
+ return li;
}
+ }
- #region Properties
-
- public LocalVariable Variable {
- get {
- return li;
- }
+ public Expression Initializer {
+ get {
+ return initializer;
}
-
- public Expression Initializer {
- get {
- return initializer;
- }
- set {
- initializer = value;
- }
+ set {
+ initializer = value;
}
+ }
- #endregion
+ #endregion
+
+ public virtual BlockVariableDeclarator Clone (CloneContext cloneCtx)
+ {
+ var t = (BlockVariableDeclarator) MemberwiseClone ();
+ if (initializer != null)
+ t.initializer = initializer.Clone (cloneCtx);
+
+ return t;
}
+ }
+ public class BlockVariable : Statement
+ {
Expression initializer;
protected FullNamedExpression type_expr;
protected LocalVariable li;
- protected List<Declarator> declarators;
+ protected List<BlockVariableDeclarator> declarators;
TypeSpec type;
- public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
+ public BlockVariable (FullNamedExpression type, LocalVariable li)
{
this.type_expr = type;
this.li = li;
this.loc = type_expr.Location;
}
- protected BlockVariableDeclaration (LocalVariable li)
+ protected BlockVariable (LocalVariable li)
{
this.li = li;
}
#region Properties
- public List<Declarator> Declarators {
+ public List<BlockVariableDeclarator> Declarators {
get {
return declarators;
}
#endregion
- public void AddDeclarator (Declarator decl)
+ public void AddDeclarator (BlockVariableDeclarator decl)
{
if (declarators == null)
- declarators = new List<Declarator> ();
+ declarators = new List<BlockVariableDeclarator> ();
declarators.Add (decl);
}
bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
if (eval_global) {
CreateEvaluatorVariable (bc, li);
- } else {
+ } else if (type != InternalType.ErrorType) {
li.PrepareForFlowAnalysis (bc);
}
d.Variable.Type = li.Type;
if (eval_global) {
CreateEvaluatorVariable (bc, d.Variable);
- } else {
+ } else if (type != InternalType.ErrorType) {
d.Variable.PrepareForFlowAnalysis (bc);
}
protected override void CloneTo (CloneContext clonectx, Statement target)
{
- BlockVariableDeclaration t = (BlockVariableDeclaration) target;
+ BlockVariable t = (BlockVariable) target;
if (type_expr != null)
t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
if (declarators != null) {
t.declarators = null;
foreach (var d in declarators)
- t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
+ t.AddDeclarator (d.Clone (clonectx));
}
}
}
}
- public class BlockConstantDeclaration : BlockVariableDeclaration
+ public class BlockConstant : BlockVariable
{
- public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
+ public BlockConstant (FullNamedExpression type, LocalVariable li)
: base (type, li)
{
}
scope_initializers.Add (s);
}
}
+
+ public void InsertStatement (int index, Statement s)
+ {
+ statements.Insert (index, s);
+ }
public void AddStatement (Statement s)
{
}
if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
- storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
+ if (storey.HoistedThis == null)
+ storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
if (storey.HoistedThis != null)
break;
continue;
if (storey.HoistedThis == null) {
- storey.AddCapturedThisField (ec);
+ storey.AddCapturedThisField (ec, null);
}
for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
+ ParametersBlock pb;
+
if (b.AnonymousMethodStorey != null) {
+ //
+ // Don't add storey cross reference for `this' when the storey ends up not
+ // beeing attached to any parent
+ //
+ if (b.ParametersBlock.StateMachine == null) {
+ AnonymousMethodStorey s = null;
+ for (Block ab = b.AnonymousMethodStorey.OriginalSourceBlock.Parent; ab != null; ab = ab.Parent) {
+ s = ab.Explicit.AnonymousMethodStorey;
+ if (s != null)
+ break;
+ }
+
+ // Needs to be in sync with AnonymousMethodBody::DoCreateMethodHost
+ if (s == null) {
+ var parent = storey == null || storey.Kind == MemberKind.Struct ? null : storey;
+ b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
+ break;
+ }
+ }
+
b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
b = b.ParametersBlock;
}
- var pb = b as ParametersBlock;
+ pb = b as ParametersBlock;
if (pb != null && pb.StateMachine != null) {
if (pb.StateMachine == storey)
break;
+ //
+ // If we are state machine with no parent. We can hook into parent without additional
+ // reference and capture this directly
+ //
+ ExplicitBlock parent_storey_block = pb;
+ while (parent_storey_block.Parent != null) {
+ parent_storey_block = parent_storey_block.Parent.Explicit;
+ if (parent_storey_block.AnonymousMethodStorey != null) {
+ break;
+ }
+ }
+
+ if (parent_storey_block.AnonymousMethodStorey == null) {
+ pb.StateMachine.AddCapturedThisField (ec, null);
+ b.HasCapturedThis = true;
+ continue;
+ }
+
pb.StateMachine.AddParentStoreyReference (ec, storey);
}
}
storey.Define ();
+ storey.PrepareEmit ();
storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
if (statements.Count == 1) {
- Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
+ Expression expr = statements[0].CreateExpressionTree (ec);
if (scope_initializers != null)
expr = new BlockScopeExpression (expr, this);
unreachable = top_level.End ();
}
} catch (Exception e) {
- if (e is CompletionResult || rc.Report.IsDisabled || e is FatalException)
+ if (e is CompletionResult || rc.Report.IsDisabled || e is FatalException || rc.Report.Printer is NullReportPrinter)
throw;
if (rc.CurrentBlock != null) {
return tlb;
}
- public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, Location loc)
+ public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, TypeSpec delegateType, Location loc)
{
for (int i = 0; i < parameters.Count; i++) {
Parameter p = parameters[i];
var block_type = host.Module.Compiler.BuiltinTypes.Void;
var initializer = new AsyncInitializer (this, host, block_type);
initializer.Type = block_type;
+ initializer.DelegateType = delegateType;
var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
int count = parameters.Count;
Arguments args = new Arguments (count);
for (int i = 0; i < count; ++i) {
- var arg_expr = GetParameterReference (i, parameter_info[i].Location);
- args.Add (new Argument (arg_expr));
+ var pi = parameter_info[i];
+ var arg_expr = GetParameterReference (i, pi.Location);
+
+ Argument.AType atype_modifier;
+ switch (pi.Parameter.ParameterModifier & Parameter.Modifier.RefOutMask) {
+ case Parameter.Modifier.REF:
+ atype_modifier = Argument.AType.Ref;
+ break;
+ case Parameter.Modifier.OUT:
+ atype_modifier = Argument.AType.Out;
+ break;
+ default:
+ atype_modifier = 0;
+ break;
+ }
+
+ args.Add (new Argument (arg_expr, atype_modifier));
}
return args;
public override bool Resolve (BlockContext bc)
{
+ if (ResolveAndReduce (bc))
+ bc.Switch.RegisterLabel (bc, this);
+
bc.CurrentBranching.CurrentUsageVector.ResetBarrier ();
return base.Resolve (bc);
// Resolves the expression, reduces it to a literal if possible
// and then converts it to the requested type.
//
- public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
- {
- Expression e = label.Resolve (ec);
-
- if (e == null)
- return false;
+ bool ResolveAndReduce (ResolveContext rc)
+ {
+ if (IsDefault)
+ return true;
- Constant c = e as Constant;
- if (c == null){
- ec.Report.Error (150, loc, "A constant value is expected");
+ var c = label.ResolveLabelConstant (rc);
+ if (c == null)
return false;
- }
- if (allow_nullable && c is NullLiteral) {
+ if (rc.Switch.IsNullable && c is NullLiteral) {
converted = c;
return true;
}
- converted = c.ImplicitConversionRequired (ec, required_type, loc);
+ converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType);
return converted != null;
}
- public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
+ public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
{
string label;
if (converted == null)
Dictionary<string, SwitchLabel> string_labels;
List<SwitchLabel> case_labels;
+ List<Tuple<GotoCase, Constant>> goto_cases;
+
/// <summary>
/// The governing switch type
/// </summary>
};
}
- //
- // Performs the basic sanity checks on the switch statement
- // (looks for duplicate keys and non-constant expressions).
- //
- // It also returns a hashtable with the keys that we will later
- // use to compute the switch tables
- //
- bool ResolveLabels (ResolveContext ec, Constant value)
+ public void RegisterLabel (ResolveContext rc, SwitchLabel sl)
{
- bool error = false;
- if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
- string_labels = new Dictionary<string, SwitchLabel> ();
- } else {
- labels = new Dictionary<long, SwitchLabel> ();
- }
-
- case_labels = new List<SwitchLabel> ();
- int default_label_index = -1;
- bool constant_label_found = false;
-
- for (int i = 0; i < block.Statements.Count; ++i) {
- var s = block.Statements[i];
+ case_labels.Add (sl);
- var sl = s as SwitchLabel;
- if (sl == null) {
- continue;
- }
-
- case_labels.Add (sl);
-
- if (sl.IsDefault) {
- if (case_default != null) {
- sl.Error_AlreadyOccurs (ec, SwitchType, case_default);
- error = true;
- }
-
- default_label_index = i;
+ if (sl.IsDefault) {
+ if (case_default != null) {
+ sl.Error_AlreadyOccurs (rc, case_default);
+ } else {
case_default = sl;
- continue;
}
- if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
- error = true;
- continue;
- }
+ return;
+ }
- try {
- if (string_labels != null) {
- string string_value = sl.Converted.GetValue () as string;
- if (string_value == null)
- case_null = sl;
- else
- string_labels.Add (string_value, sl);
+ try {
+ if (string_labels != null) {
+ string string_value = sl.Converted.GetValue () as string;
+ if (string_value == null)
+ case_null = sl;
+ else
+ string_labels.Add (string_value, sl);
+ } else {
+ if (sl.Converted is NullLiteral) {
+ case_null = sl;
} else {
- if (sl.Converted is NullLiteral) {
- case_null = sl;
- } else {
- labels.Add (sl.Converted.GetValueAsLong (), sl);
- }
+ labels.Add (sl.Converted.GetValueAsLong (), sl);
}
- } catch (ArgumentException) {
- if (string_labels != null)
- sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
- else
- sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
-
- error = true;
- }
-
- if (value != null) {
- var constant_label = constant_label_found ? null : FindLabel (value);
- if (constant_label == null || constant_label != sl)
- block.Statements[i] = new EmptyStatement (s.loc);
- else
- constant_label_found = true;
}
+ } catch (ArgumentException) {
+ if (string_labels != null)
+ sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
+ else
+ sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
}
-
- if (value != null && constant_label_found && default_label_index >= 0)
- block.Statements[default_label_index] = new EmptyStatement (case_default.loc);
-
- return !error;
}
//
new_expr = SwitchGoverningType (ec, unwrap);
}
- if (new_expr == null){
- ec.Report.Error (151, loc,
- "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
- TypeManager.CSharpName (Expr.Type));
+ if (new_expr == null) {
+ if (Expr.Type != InternalType.ErrorType) {
+ ec.Report.Error (151, loc,
+ "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
+ Expr.Type.GetSignatureForError ());
+ }
+
return false;
}
if (block.Statements.Count == 0)
return true;
- var constant = new_expr as Constant;
+ if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+ string_labels = new Dictionary<string, SwitchLabel> ();
+ } else {
+ labels = new Dictionary<long, SwitchLabel> ();
+ }
- if (!ResolveLabels (ec, constant))
- return false;
+ case_labels = new List<SwitchLabel> ();
+
+ var constant = new_expr as Constant;
//
// Don't need extra variable for constant switch or switch with
// only default case
//
- if (constant == null && (case_labels.Count - (case_default != null ? 1 : 0)) != 0) {
+ if (constant == null) {
//
// Store switch expression for comparison purposes
//
value = new_expr as VariableReference;
- if (value == null) {
- // Create temporary variable inside switch scope
+ if (value == null && !HasOnlyDefaultSection ()) {
var current_block = ec.CurrentBlock;
ec.CurrentBlock = Block;
+ // Create temporary variable inside switch scope
value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
value.Resolve (ec);
ec.CurrentBlock = current_block;
var ok = block.Resolve (ec);
if (case_default == null)
- ec.CurrentBranching.CurrentUsageVector.ResetBarrier ();
+ ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
+
+ if (ec.IsUnreachable)
+ ec.KillFlowBranching ();
+ else
+ ec.EndFlowBranching ();
- ec.EndFlowBranching ();
ec.Switch = old_switch;
+ //
+ // Check if all goto cases are valid. Needs to be done after switch
+ // is resolved becuase goto can jump forward in the scope.
+ //
+ if (goto_cases != null) {
+ foreach (var gc in goto_cases) {
+ if (gc.Item1 == null) {
+ if (DefaultLabel == null) {
+ FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
+ }
+
+ continue;
+ }
+
+ var sl = FindLabel (gc.Item2);
+ if (sl == null) {
+ FlowBranchingBlock.Error_UnknownLabel (loc, "case " + gc.Item2.GetValueAsLiteral (), ec.Report);
+ } else {
+ gc.Item1.Label = sl;
+ }
+ }
+ }
+
+ if (constant != null) {
+ ResolveUnreachableSections (ec, constant);
+ }
+
if (!ok)
return false;
}
//
- // Needed to emit anonymous storey initialization before
+ // Anonymous storey initialization has to happen before
// any generated switch dispatch
//
- block.AddScopeStatement (new DispatchStatement (this));
+ block.InsertStatement (0, new DispatchStatement (this));
return true;
}
- public SwitchLabel ResolveGotoCase (ResolveContext rc, Constant value)
+ bool HasOnlyDefaultSection ()
{
- var sl = FindLabel (value);
+ for (int i = 0; i < block.Statements.Count; ++i) {
+ var s = block.Statements[i] as SwitchLabel;
+
+ if (s == null || s.IsDefault)
+ continue;
- if (sl == null) {
- FlowBranchingBlock.Error_UnknownLabel (loc, "case " + value.GetValueAsLiteral (), rc.Report);
+ return false;
}
- return sl;
+ return true;
+ }
+
+ public void RegisterGotoCase (GotoCase gotoCase, Constant value)
+ {
+ if (goto_cases == null)
+ goto_cases = new List<Tuple<GotoCase, Constant>> ();
+
+ goto_cases.Add (Tuple.Create (gotoCase, value));
}
//
string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
}
+ void ResolveUnreachableSections (BlockContext bc, Constant value)
+ {
+ var constant_label = FindLabel (value) ?? case_default;
+
+ bool found = false;
+ bool unreachable_reported = false;
+ for (int i = 0; i < block.Statements.Count; ++i) {
+ var s = block.Statements[i];
+
+ if (s is SwitchLabel) {
+ if (unreachable_reported) {
+ found = unreachable_reported = false;
+ }
+
+ found |= s == constant_label;
+ continue;
+ }
+
+ if (found) {
+ unreachable_reported = true;
+ continue;
+ }
+
+ if (!unreachable_reported) {
+ unreachable_reported = true;
+ if (!bc.IsUnreachable) {
+ bc.Report.Warning (162, 2, s.loc, "Unreachable code detected");
+ }
+ }
+
+ block.Statements[i] = new EmptyStatement (s.loc);
+ }
+ }
+
void DoEmitStringSwitch (EmitContext ec)
{
Label l_initialized = ec.DefineLabel ();
return;
}
- //
- // Mark sequence point explicitly to switch
- //
- ec.Mark (block.StartLocation);
- block.IsCompilerGenerated = true;
-
if (string_dictionary != null) {
DoEmitStringSwitch (ec);
} else if (case_labels.Count < 4 || string_labels != null) {
} else if (new_expr != value) {
value.EmitAssign (ec, new_expr, false, false);
}
+
+
+ //
+ // Next statement is compiler generated we don't need extra
+ // nop when we can use the statement for sequence point
+ //
+ ec.Mark (block.StartLocation);
+ block.IsCompilerGenerated = true;
}
block.Emit (ec);
if (finally_host != null) {
finally_host.Define ();
+ finally_host.PrepareEmit ();
finally_host.Emit ();
// Now it's safe to add, to close it properly and emit sequence points
{
LocalVariable pinned_string;
- public StringEmitter (Expression expr, LocalVariable li, Location loc)
+ public StringEmitter (Expression expr, LocalVariable li)
: base (expr, li)
{
}
}
}
- public class VariableDeclaration : BlockVariableDeclaration
+ public class VariableDeclaration : BlockVariable
{
public VariableDeclaration (FullNamedExpression type, LocalVariable li)
: base (type, li)
// Case 2: string
//
if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
- return new StringEmitter (initializer, li, loc).Resolve (bc);
+ return new StringEmitter (initializer, li).Resolve (bc);
}
// Case 3: fixed buffer
}
}
- public BlockVariableDeclaration Variables {
+ public BlockVariable Variables {
get {
return decl;
}
{
TryFinally target = (TryFinally) t;
- target.stmt = (Statement) stmt.Clone (clonectx);
+ target.stmt = stmt.Clone (clonectx);
if (fini != null)
target.fini = clonectx.LookupBlock (fini);
}
public class Using : TryFinallyBlock
{
- public class VariableDeclaration : BlockVariableDeclaration
+ public class VariableDeclaration : BlockVariable
{
Statement dispose_call;
}
}
- public BlockVariableDeclaration Variables {
+ public BlockVariable Variables {
get {
return decl;
}
protected override void DoEmit (EmitContext ec)
{
- variable.CreateBuilder (ec);
-
Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
ec.LoopBegin = ec.DefineLabel ();
ec.LoopEnd = ec.DefineLabel ();
+ if (!(statement is Block))
+ ec.BeginCompilerScope ();
+
+ variable.CreateBuilder (ec);
+
statement.Emit (ec);
+ if (!(statement is Block))
+ ec.EndScope ();
+
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}