/mcs/mcs/statement.cs
C# | 6461 lines | 4695 code | 1203 blank | 563 comment | 1052 complexity | d1889fc01f02f011c13a627ec1b68019 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- //
- // statement.cs: Statement representation for the IL tree.
- //
- // Authors:
- // Miguel de Icaza (miguel@ximian.com)
- // Martin Baulig (martin@ximian.com)
- // Marek Safar (marek.safar@gmail.com)
- //
- // Copyright 2001, 2002, 2003 Ximian, Inc.
- // Copyright 2003, 2004 Novell, Inc.
- // Copyright 2011 Xamarin Inc.
- //
- using System;
- using System.Collections.Generic;
- #if STATIC
- using IKVM.Reflection.Emit;
- #else
- using System.Reflection.Emit;
- #endif
- namespace Mono.CSharp {
-
- public abstract class Statement {
- public Location loc;
-
- /// <summary>
- /// Resolves the statement, true means that all sub-statements
- /// did resolve ok.
- // </summary>
- public virtual bool Resolve (BlockContext bc)
- {
- return true;
- }
- /// <summary>
- /// We already know that the statement is unreachable, but we still
- /// need to resolve it to catch errors.
- /// </summary>
- public virtual bool ResolveUnreachable (BlockContext ec, bool warn)
- {
- //
- // This conflicts with csc's way of doing this, but IMHO it's
- // the right thing to do.
- //
- // If something is unreachable, we still check whether it's
- // correct. This means that you cannot use unassigned variables
- // in unreachable code, for instance.
- //
- bool unreachable = false;
- if (warn && !ec.UnreachableReported) {
- ec.UnreachableReported = true;
- unreachable = true;
- ec.Report.Warning (162, 2, loc, "Unreachable code detected");
- }
- ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
- bool ok = Resolve (ec);
- ec.KillFlowBranching ();
- if (unreachable) {
- ec.UnreachableReported = false;
- }
- return ok;
- }
-
- /// <summary>
- /// Return value indicates whether all code paths emitted return.
- /// </summary>
- protected abstract void DoEmit (EmitContext ec);
- public virtual void Emit (EmitContext ec)
- {
- ec.Mark (loc);
- DoEmit (ec);
- if (ec.StatementEpilogue != null) {
- ec.EmitEpilogue ();
- }
- }
- //
- // This routine must be overrided in derived classes and make copies
- // of all the data that might be modified if resolved
- //
- protected abstract void CloneTo (CloneContext clonectx, Statement target);
- public Statement Clone (CloneContext clonectx)
- {
- Statement s = (Statement) this.MemberwiseClone ();
- CloneTo (clonectx, s);
- return s;
- }
- public virtual Expression CreateExpressionTree (ResolveContext ec)
- {
- ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
- return null;
- }
-
- public virtual object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public sealed class EmptyStatement : Statement
- {
- public EmptyStatement (Location loc)
- {
- this.loc = loc;
- }
-
- public override bool Resolve (BlockContext ec)
- {
- return true;
- }
- public override bool ResolveUnreachable (BlockContext ec, bool warn)
- {
- return true;
- }
- public override void Emit (EmitContext ec)
- {
- }
- protected override void DoEmit (EmitContext ec)
- {
- throw new NotSupportedException ();
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- // nothing needed.
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- public class If : Statement {
- Expression expr;
- public Statement TrueStatement;
- public Statement FalseStatement;
- bool is_true_ret;
- public If (Expression bool_expr, Statement true_statement, Location l)
- : this (bool_expr, true_statement, null, l)
- {
- }
- public If (Expression bool_expr,
- Statement true_statement,
- Statement false_statement,
- Location l)
- {
- this.expr = bool_expr;
- TrueStatement = true_statement;
- FalseStatement = false_statement;
- loc = l;
- }
- public Expression Expr {
- get {
- return this.expr;
- }
- }
-
- public override bool Resolve (BlockContext ec)
- {
- bool ok = true;
- expr = expr.Resolve (ec);
- if (expr == null) {
- ok = false;
- } else {
- //
- // Dead code elimination
- //
- if (expr is Constant) {
- bool take = !((Constant) expr).IsDefaultValue;
- if (take) {
- if (!TrueStatement.Resolve (ec))
- return false;
- if ((FalseStatement != null) &&
- !FalseStatement.ResolveUnreachable (ec, true))
- return false;
- FalseStatement = null;
- } else {
- if (!TrueStatement.ResolveUnreachable (ec, true))
- return false;
- TrueStatement = null;
- if ((FalseStatement != null) &&
- !FalseStatement.Resolve (ec))
- return false;
- }
- return true;
- }
- }
- ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
-
- ok &= TrueStatement.Resolve (ec);
- is_true_ret = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
- ec.CurrentBranching.CreateSibling ();
- if (FalseStatement != null)
- ok &= FalseStatement.Resolve (ec);
-
- ec.EndFlowBranching ();
- return ok;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- Label false_target = ec.DefineLabel ();
- Label end;
- //
- // If we're a boolean constant, Resolve() already
- // eliminated dead code for us.
- //
- Constant c = expr as Constant;
- if (c != null){
- c.EmitSideEffect (ec);
- if (!c.IsDefaultValue)
- TrueStatement.Emit (ec);
- else if (FalseStatement != null)
- FalseStatement.Emit (ec);
- return;
- }
-
- expr.EmitBranchable (ec, false_target, false);
-
- TrueStatement.Emit (ec);
- if (FalseStatement != null){
- bool branch_emitted = false;
-
- end = ec.DefineLabel ();
- if (!is_true_ret){
- ec.Emit (OpCodes.Br, end);
- branch_emitted = true;
- }
- ec.MarkLabel (false_target);
- FalseStatement.Emit (ec);
- if (branch_emitted)
- ec.MarkLabel (end);
- } else {
- ec.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);
- if (FalseStatement != null)
- target.FalseStatement = FalseStatement.Clone (clonectx);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class Do : Statement {
- public Expression expr;
- public Statement EmbeddedStatement;
- public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
- {
- expr = bool_expr;
- EmbeddedStatement = statement;
- loc = doLocation;
- WhileLocation = whileLocation;
- }
- public Location WhileLocation {
- get; private set;
- }
- public override bool Resolve (BlockContext ec)
- {
- bool ok = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
- bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
- ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
- if (!EmbeddedStatement.Resolve (ec))
- ok = false;
- ec.EndFlowBranching ();
- if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
- ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected");
- expr = expr.Resolve (ec);
- if (expr == null)
- ok = false;
- else if (expr is Constant){
- bool infinite = !((Constant) expr).IsDefaultValue;
- if (infinite)
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- }
- ec.EndFlowBranching ();
- return ok;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- Label loop = ec.DefineLabel ();
- Label old_begin = ec.LoopBegin;
- Label old_end = ec.LoopEnd;
-
- ec.LoopBegin = ec.DefineLabel ();
- ec.LoopEnd = ec.DefineLabel ();
-
- ec.MarkLabel (loop);
- EmbeddedStatement.Emit (ec);
- ec.MarkLabel (ec.LoopBegin);
- // Mark start of while condition
- ec.Mark (WhileLocation);
- //
- // Dead code elimination
- //
- if (expr is Constant) {
- bool res = !((Constant) expr).IsDefaultValue;
- expr.EmitSideEffect (ec);
- if (res)
- ec.Emit (OpCodes.Br, loop);
- } else {
- expr.EmitBranchable (ec, loop, true);
- }
-
- ec.MarkLabel (ec.LoopEnd);
- 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 override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class While : Statement {
- public Expression expr;
- public Statement Statement;
- bool infinite, empty;
- public While (BooleanExpression bool_expr, Statement statement, Location l)
- {
- this.expr = bool_expr;
- Statement = statement;
- loc = l;
- }
- public override bool Resolve (BlockContext ec)
- {
- bool ok = true;
- expr = expr.Resolve (ec);
- if (expr == null)
- ok = false;
- //
- // Inform whether we are infinite or not
- //
- if (expr is Constant){
- bool value = !((Constant) expr).IsDefaultValue;
- if (value == false){
- if (!Statement.ResolveUnreachable (ec, true))
- return false;
- empty = true;
- return true;
- } else
- infinite = true;
- }
- ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
- 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.EndFlowBranching ();
- return ok;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- if (empty) {
- expr.EmitSideEffect (ec);
- return;
- }
- Label old_begin = ec.LoopBegin;
- Label old_end = ec.LoopEnd;
-
- ec.LoopBegin = ec.DefineLabel ();
- ec.LoopEnd = ec.DefineLabel ();
- //
- // Inform whether we are infinite or not
- //
- if (expr is Constant) {
- // expr is 'true', since the 'empty' case above handles the 'false' case
- ec.MarkLabel (ec.LoopBegin);
- if (ec.EmitAccurateDebugInfo)
- ec.Emit (OpCodes.Nop);
- expr.EmitSideEffect (ec);
- Statement.Emit (ec);
- ec.Emit (OpCodes.Br, ec.LoopBegin);
-
- //
- // Inform that we are infinite (ie, `we return'), only
- // if we do not `break' inside the code.
- //
- ec.MarkLabel (ec.LoopEnd);
- } else {
- Label while_loop = ec.DefineLabel ();
- ec.Emit (OpCodes.Br, ec.LoopBegin);
- ec.MarkLabel (while_loop);
- Statement.Emit (ec);
-
- ec.MarkLabel (ec.LoopBegin);
- ec.Mark (loc);
- expr.EmitBranchable (ec, while_loop, true);
-
- ec.MarkLabel (ec.LoopEnd);
- }
- 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 override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class For : Statement
- {
- bool infinite, empty;
-
- public For (Location l)
- {
- loc = l;
- }
- public Statement Initializer {
- get; set;
- }
- public Expression Condition {
- get; set;
- }
- public Statement Iterator {
- get; set;
- }
- public Statement Statement {
- get; set;
- }
- public override bool Resolve (BlockContext ec)
- {
- bool ok = true;
- if (Initializer != null) {
- if (!Initializer.Resolve (ec))
- ok = false;
- }
- if (Condition != null) {
- Condition = Condition.Resolve (ec);
- if (Condition == null)
- ok = false;
- else if (Condition is Constant) {
- bool value = !((Constant) Condition).IsDefaultValue;
- if (value == false){
- if (!Statement.ResolveUnreachable (ec, true))
- return false;
- if ((Iterator != null) &&
- !Iterator.ResolveUnreachable (ec, false))
- return false;
- empty = true;
- return true;
- } else
- infinite = true;
- }
- } else
- infinite = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
- if (!infinite)
- ec.CurrentBranching.CreateSibling ();
- bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
- ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
- if (!Statement.Resolve (ec))
- ok = false;
- ec.EndFlowBranching ();
- if (Iterator != null){
- if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
- if (!Iterator.ResolveUnreachable (ec, !was_unreachable))
- ok = false;
- } else {
- if (!Iterator.Resolve (ec))
- ok = false;
- }
- }
- // 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;
- }
- protected override void DoEmit (EmitContext ec)
- {
- if (Initializer != null)
- Initializer.Emit (ec);
- if (empty) {
- Condition.EmitSideEffect (ec);
- return;
- }
- Label old_begin = ec.LoopBegin;
- Label old_end = ec.LoopEnd;
- Label loop = ec.DefineLabel ();
- Label test = ec.DefineLabel ();
- ec.LoopBegin = ec.DefineLabel ();
- ec.LoopEnd = ec.DefineLabel ();
- ec.Emit (OpCodes.Br, test);
- ec.MarkLabel (loop);
- Statement.Emit (ec);
- ec.MarkLabel (ec.LoopBegin);
- Iterator.Emit (ec);
- ec.MarkLabel (test);
- //
- // If test is null, there is no test, and we are just
- // an infinite loop
- //
- if (Condition != null) {
- ec.Mark (Condition.Location);
- //
- // The Resolve code already catches the case for
- // Test == Constant (false) so we know that
- // this is true
- //
- if (Condition is Constant) {
- Condition.EmitSideEffect (ec);
- ec.Emit (OpCodes.Br, loop);
- } else {
- Condition.EmitBranchable (ec, loop, true);
- }
-
- } else
- ec.Emit (OpCodes.Br, loop);
- ec.MarkLabel (ec.LoopEnd);
- ec.LoopBegin = old_begin;
- ec.LoopEnd = old_end;
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- For target = (For) t;
- if (Initializer != null)
- target.Initializer = Initializer.Clone (clonectx);
- if (Condition != null)
- target.Condition = Condition.Clone (clonectx);
- if (Iterator != null)
- target.Iterator = Iterator.Clone (clonectx);
- target.Statement = Statement.Clone (clonectx);
- }
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- public class StatementExpression : Statement
- {
- ExpressionStatement expr;
-
- public StatementExpression (ExpressionStatement expr)
- {
- this.expr = expr;
- loc = expr.Location;
- }
- public StatementExpression (ExpressionStatement expr, Location loc)
- {
- this.expr = expr;
- this.loc = loc;
- }
- public ExpressionStatement Expr {
- get {
- return this.expr;
- }
- }
-
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- StatementExpression target = (StatementExpression) t;
- target.expr = (ExpressionStatement) expr.Clone (clonectx);
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- expr.EmitStatement (ec);
- }
- public override bool Resolve (BlockContext ec)
- {
- expr = expr.ResolveStatement (ec);
- return expr != null;
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class StatementErrorExpression : Statement
- {
- readonly Expression expr;
- public StatementErrorExpression (Expression expr)
- {
- this.expr = expr;
- }
- public Expression Expr {
- get {
- return expr;
- }
- }
- protected override void DoEmit (EmitContext ec)
- {
- throw new NotSupportedException ();
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- throw new NotImplementedException ();
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- //
- // Simple version of statement list not requiring a block
- //
- public class StatementList : Statement
- {
- List<Statement> statements;
- public StatementList (Statement first, Statement second)
- {
- statements = new List<Statement> () { first, second };
- }
- #region Properties
- public IList<Statement> Statements {
- get {
- return statements;
- }
- }
- #endregion
- public void Add (Statement statement)
- {
- statements.Add (statement);
- }
- public override bool Resolve (BlockContext ec)
- {
- foreach (var s in statements)
- s.Resolve (ec);
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- foreach (var s in statements)
- s.Emit (ec);
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- StatementList t = (StatementList) target;
- t.statements = new List<Statement> (statements.Count);
- foreach (Statement s in statements)
- t.statements.Add (s.Clone (clonectx));
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- // A 'return' or a 'yield break'
- public abstract class ExitStatement : Statement
- {
- protected bool unwind_protect;
- protected abstract bool DoResolve (BlockContext ec);
- public virtual void Error_FinallyClause (Report Report)
- {
- Report.Error (157, loc, "Control cannot leave the body of a finally clause");
- }
- public sealed override bool Resolve (BlockContext ec)
- {
- var res = DoResolve (ec);
- unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return res;
- }
- }
- /// <summary>
- /// Implements the return statement
- /// </summary>
- public class Return : ExitStatement
- {
- Expression expr;
- public Return (Expression expr, Location l)
- {
- this.expr = expr;
- loc = l;
- }
- #region Properties
- public Expression Expr {
- get {
- return expr;
- }
- protected set {
- expr = value;
- }
- }
- #endregion
- protected override bool DoResolve (BlockContext ec)
- {
- if (expr == null) {
- if (ec.ReturnType.Kind == MemberKind.Void)
- return true;
- //
- // Return must not be followed by an expression when
- // the method return type is Task
- //
- if (ec.CurrentAnonymousMethod is AsyncInitializer) {
- var storey = (AsyncTaskStorey) ec.CurrentAnonymousMethod.Storey;
- if (storey.ReturnType == ec.Module.PredefinedTypes.Task.TypeSpec) {
- //
- // Extra trick not to emit ret/leave inside awaiter body
- //
- expr = EmptyExpression.Null;
- return true;
- }
- }
- if (ec.CurrentIterator != null) {
- Error_ReturnFromIterator (ec);
- } else if (ec.ReturnType != InternalType.ErrorType) {
- ec.Report.Error (126, loc,
- "An object of a type convertible to `{0}' is required for the return statement",
- ec.ReturnType.GetSignatureForError ());
- }
- return false;
- }
- expr = expr.Resolve (ec);
- TypeSpec block_return_type = ec.ReturnType;
- AnonymousExpression am = ec.CurrentAnonymousMethod;
- if (am == null) {
- if (block_return_type.Kind == MemberKind.Void) {
- ec.Report.Error (127, loc,
- "`{0}': A return keyword must not be followed by any expression when method returns void",
- ec.GetSignatureForError ());
- return false;
- }
- } else {
- if (am.IsIterator) {
- Error_ReturnFromIterator (ec);
- return false;
- }
- var async_block = am as AsyncInitializer;
- if (async_block != null) {
- if (expr != null) {
- var storey = (AsyncTaskStorey) am.Storey;
- var async_type = storey.ReturnType;
- if (async_type == null && async_block.ReturnTypeInference != null) {
- async_block.ReturnTypeInference.AddCommonTypeBound (expr.Type);
- return true;
- }
- if (async_type.Kind == MemberKind.Void) {
- ec.Report.Error (127, loc,
- "`{0}': A return keyword must not be followed by any expression when method returns void",
- ec.GetSignatureForError ());
- return false;
- }
- if (!async_type.IsGenericTask) {
- 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 ());
- return false;
- }
- //
- // The return type is actually Task<T> type argument
- //
- if (expr.Type == async_type) {
- ec.Report.Error (4016, loc,
- "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
- ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
- } else {
- block_return_type = async_type.TypeArguments[0];
- }
- }
- } else {
- // Same error code as .NET but better error message
- if (block_return_type.Kind == MemberKind.Void) {
- ec.Report.Error (127, loc,
- "`{0}': A return keyword must not be followed by any expression when delegate returns void",
- am.GetSignatureForError ());
- return false;
- }
- var l = am as AnonymousMethodBody;
- if (l != null && l.ReturnTypeInference != null && expr != null) {
- l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
- return true;
- }
- }
- }
- if (expr == null)
- return false;
- if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
- expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
- if (expr == null) {
- if (am != null && block_return_type == ec.ReturnType) {
- ec.Report.Error (1662, loc,
- "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
- am.ContainerType, am.GetSignatureForError ());
- }
- return false;
- }
- }
- return true;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- if (expr != null) {
- expr.Emit (ec);
- var async_body = ec.CurrentAnonymousMethod as AsyncInitializer;
- if (async_body != null) {
- var async_return = ((AsyncTaskStorey) async_body.Storey).HoistedReturn;
- // It's null for await without async
- if (async_return != null) {
- async_return.EmitAssign (ec);
- ec.EmitEpilogue ();
- }
- ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
- return;
- }
- ec.EmitEpilogue ();
- if (unwind_protect || ec.EmitAccurateDebugInfo)
- ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
- }
- if (unwind_protect) {
- ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
- } else if (ec.EmitAccurateDebugInfo) {
- ec.Emit (OpCodes.Br, ec.CreateReturnLabel ());
- } else {
- ec.Emit (OpCodes.Ret);
- }
- }
- void Error_ReturnFromIterator (ResolveContext rc)
- {
- rc.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");
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- Return target = (Return) t;
- // It's null for simple return;
- if (expr != null)
- target.expr = expr.Clone (clonectx);
- }
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class Goto : Statement {
- string target;
- LabeledStatement label;
- bool unwind_protect;
- public override bool Resolve (BlockContext ec)
- {
- unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
- }
-
- public Goto (string label, Location l)
- {
- loc = l;
- target = label;
- }
- public string Target {
- get { return target; }
- }
- public void SetResolvedTarget (LabeledStatement label)
- {
- this.label = label;
- label.AddReference ();
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- // Nothing to clone
- }
- protected override void DoEmit (EmitContext ec)
- {
- if (label == null)
- throw new InternalErrorException ("goto emitted before target resolved");
- Label l = label.LabelTarget (ec);
- ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class LabeledStatement : Statement {
- string name;
- bool defined;
- bool referenced;
- Label label;
- Block block;
- FlowBranching.UsageVector vectors;
-
- public LabeledStatement (string name, Block block, Location l)
- {
- this.name = name;
- this.block = block;
- this.loc = l;
- }
- public Label LabelTarget (EmitContext ec)
- {
- if (defined)
- return label;
- label = ec.DefineLabel ();
- defined = true;
- return label;
- }
- public Block Block {
- get {
- return block;
- }
- }
- public string Name {
- get { return name; }
- }
- public bool IsDefined {
- get { return defined; }
- }
- public bool HasBeenReferenced {
- get { return referenced; }
- }
- public FlowBranching.UsageVector JumpOrigins {
- get { return vectors; }
- }
- public void AddUsageVector (FlowBranching.UsageVector vector)
- {
- vector = vector.Clone ();
- vector.Next = vectors;
- vectors = vector;
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- // nothing to clone
- }
- public override bool Resolve (BlockContext ec)
- {
- // this flow-branching will be terminated when the surrounding block ends
- ec.StartFlowBranching (this);
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- if (!HasBeenReferenced)
- ec.Report.Warning (164, 2, loc, "This label has not been referenced");
- LabelTarget (ec);
- ec.MarkLabel (label);
- }
- public void AddReference ()
- {
- referenced = true;
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- /// <summary>
- /// `goto default' statement
- /// </summary>
- public class GotoDefault : Statement {
-
- public GotoDefault (Location l)
- {
- loc = l;
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- // nothing to clone
- }
- public override bool Resolve (BlockContext ec)
- {
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- if (ec.Switch == null) {
- ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
- return false;
- }
- if (!ec.Switch.GotDefault) {
- FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
- return false;
- }
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- /// <summary>
- /// `goto case' statement
- /// </summary>
- public class GotoCase : Statement {
- Expression expr;
- SwitchLabel sl;
-
- public GotoCase (Expression e, Location l)
- {
- expr = e;
- loc = l;
- }
- public Expression Expr {
- get {
- return this.expr;
- }
- }
-
- public override bool Resolve (BlockContext ec)
- {
- if (ec.Switch == null){
- ec.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
- return false;
- }
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
- Constant c = expr as Constant;
- if (c == null) {
- ec.Report.Error (150, expr.Location, "A constant value is expected");
- return false;
- }
- Constant res;
- if (ec.Switch.IsNullable && c is NullLiteral) {
- res = c;
- } else {
- TypeSpec type = ec.Switch.SwitchType;
- res = c.Reduce (ec, type);
- if (res == null) {
- c.Error_ValueCannotBeConverted (ec, type, true);
- 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));
- }
- sl = ec.Switch.ResolveGotoCase (ec, res);
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- ec.Emit (OpCodes.Br, sl.GetILLabel (ec));
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- GotoCase target = (GotoCase) t;
- target.expr = expr.Clone (clonectx);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- public class Throw : Statement {
- Expression expr;
-
- public Throw (Expression expr, Location l)
- {
- this.expr = expr;
- loc = l;
- }
- public Expression Expr {
- get {
- return this.expr;
- }
- }
- public override bool Resolve (BlockContext ec)
- {
- if (expr == null) {
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return ec.CurrentBranching.CheckRethrow (loc);
- }
- expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- if (expr == null)
- return false;
- var et = ec.BuiltinTypes.Exception;
- if (Convert.ImplicitConversionExists (ec, expr, et))
- expr = Convert.ImplicitConversion (ec, expr, et, loc);
- else
- ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
- return true;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- if (expr == null)
- ec.Emit (OpCodes.Rethrow);
- else {
- expr.Emit (ec);
- ec.Emit (OpCodes.Throw);
- }
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- Throw target = (Throw) t;
- if (expr != null)
- target.expr = expr.Clone (clonectx);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class Break : Statement {
-
- public Break (Location l)
- {
- loc = l;
- }
- bool unwind_protect;
- public override bool Resolve (BlockContext ec)
- {
- unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- // nothing needed
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class Continue : Statement {
-
- public Continue (Location l)
- {
- loc = l;
- }
- bool unwind_protect;
- public override bool Resolve (BlockContext ec)
- {
- unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
- }
- protected override void CloneTo (CloneContext clonectx, Statement t)
- {
- // nothing needed.
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public interface ILocalVariable
- {
- void Emit (EmitContext ec);
- void EmitAssign (EmitContext ec);
- void EmitAddressOf (EmitContext ec);
- }
- public interface INamedBlockVariable
- {
- Block Block { get; }
- Expression CreateReferenceExpression (ResolveContext rc, Location loc);
- bool IsDeclared { get; }
- bool IsParameter { get; }
- Location Location { get; }
- }
- public class BlockVariableDeclaration : Statement
- {
- public class Declarator
- {
- LocalVariable li;
- Expression initializer;
- public Declarator (LocalVariable li, Expression initializer)
- {
- if (li.Type != null)
- throw new ArgumentException ("Expected null variable type");
- this.li = li;
- this.initializer = initializer;
- }
- public Declarator (Declarator clone, Expression initializer)
- {
- this.li = clone.li;
- this.initializer = initializer;
- }
- #region Properties
- public LocalVariable Variable {
- get {
- return li;
- }
- }
- public Expression Initializer {
- get {
- return initializer;
- }
- set {
- initializer = value;
- }
- }
- #endregion
- }
- Expression initializer;
- protected FullNamedExpression type_expr;
- protected LocalVariable li;
- protected List<Declarator> declarators;
- TypeSpec type;
- public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
- {
- this.type_expr = type;
- this.li = li;
- this.loc = type_expr.Location;
- }
- protected BlockVariableDeclaration (LocalVariable li)
- {
- this.li = li;
- }
- #region Properties
- public List<Declarator> Declarators {
- get {
- return declarators;
- }
- }
- public Expression Initializer {
- get {
- return initializer;
- }
- set {
- initializer = value;
- }
- }
- public FullNamedExpression TypeExpression {
- get {
- return type_expr;
- }
- }
- public LocalVariable Variable {
- get {
- return li;
- }
- }
- #endregion
- public void AddDeclarator (Declarator decl)
- {
- if (declarators == null)
- declarators = new List<Declarator> ();
- declarators.Add (decl);
- }
- static void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
- {
- if (bc.Report.Errors != 0)
- return;
- var container = bc.CurrentMemberDefinition.Parent.PartialContainer;
- Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
- new MemberName (li.Name, li.Location), null);
- container.AddField (f);
- f.Define ();
- li.HoistedVariant = new HoistedEvaluatorVariable (f);
- li.SetIsUsed ();
- }
- public override bool Resolve (BlockContext bc)
- {
- return Resolve (bc, true);
- }
- public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
- {
- if (type == null && !li.IsCompilerGenerated) {
- var vexpr = type_expr as VarExpr;
- //
- // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
- // same name exists or as a keyword when no type was found
- //
- if (vexpr != null && !vexpr.IsPossibleTypeOrNamespace (bc)) {
- if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
- bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
- if (li.IsFixed) {
- bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
- return false;
- }
- if (li.IsConstant) {
- bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
- return false;
- }
- if (Initializer == null) {
- bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
- return false;
- }
- if (declarators != null) {
- bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
- declarators = null;
- }
- Initializer = Initializer.Resolve (bc);
- if (Initializer != null) {
- ((VarExpr) type_expr).InferType (bc, Initializer);
- type = type_expr.Type;
- } else {
- // Set error type to indicate the var was placed correctly but could
- // not be infered
- //
- // var a = missing ();
- //
- type = InternalType.ErrorType;
- }
- }
- if (type == null) {
- type = type_expr.ResolveAsType (bc);
- if (type == null)
- return false;
- if (li.IsConstant && !type.IsConstantCompatible) {
- Const.Error_InvalidConstantType (type, loc, bc.Report);
- }
- }
- if (type.IsStatic)
- FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
- li.Type = type;
- }
- bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
- if (eval_global) {
- CreateEvaluatorVariable (bc, li);
- } else {
- li.PrepareForFlowAnalysis (bc);
- }
- if (initializer != null) {
- initializer = ResolveInitializer (bc, li, initializer);
- // li.Variable.DefinitelyAssigned
- }
- if (declarators != null) {
- foreach (var d in declarators) {
- d.Variable.Type = li.Type;
- if (eval_global) {
- CreateEvaluatorVariable (bc, d.Variable);
- } else {
- d.Variable.PrepareForFlowAnalysis (bc);
- }
- if (d.Initializer != null && resolveDeclaratorInitializers) {
- d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
- // d.Variable.DefinitelyAssigned
- }
- }
- }
- return true;
- }
- protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
- {
- var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
- return a.ResolveStatement (bc);
- }
- protected override void DoEmit (EmitContext ec)
- {
- li.CreateBuilder (ec);
- if (Initializer != null)
- ((ExpressionStatement) Initializer).EmitStatement (ec);
- if (declarators != null) {
- foreach (var d in declarators) {
- d.Variable.CreateBuilder (ec);
- if (d.Initializer != null) {
- ec.Mark (d.Variable.Location);
- ((ExpressionStatement) d.Initializer).EmitStatement (ec);
- }
- }
- }
- }
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- BlockVariableDeclaration t = (BlockVariableDeclaration) target;
- if (type_expr != null)
- t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
- if (initializer != null)
- t.initializer = initializer.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)));
- }
- }
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- public class BlockConstantDeclaration : BlockVariableDeclaration
- {
- public BlockConstantDeclaration (FullNamedExpression type, LocalVariable li)
- : base (type, li)
- {
- }
- public override void Emit (EmitContext ec)
- {
- // Nothing to emit, not even sequence point
- }
- protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
- {
- initializer = initializer.Resolve (bc);
- if (initializer == null)
- return null;
- var c = initializer as Constant;
- if (c == null) {
- initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
- return null;
- }
- c = c.ConvertImplicitly (li.Type);
- if (c == null) {
- if (TypeSpec.IsReferenceType (li.Type))
- initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
- else
- initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
- return null;
- }
- li.ConstantValue = c;
- return initializer;
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- //
- // The information about a user-perceived local variable
- //
- public class LocalVariable : INamedBlockVariable, ILocalVariable
- {
- [Flags]
- public enum Flags
- {
- Used = 1,
- IsThis = 1 << 1,
- AddressTaken = 1 << 2,
- CompilerGenerated = 1 << 3,
- Constant = 1 << 4,
- ForeachVariable = 1 << 5,
- FixedVariable = 1 << 6,
- UsingVariable = 1 << 7,
- // DefinitelyAssigned = 1 << 8,
- IsLocked = 1 << 9,
- ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
- }
- TypeSpec type;
- readonly string name;
- readonly Location loc;
- readonly Block block;
- Flags flags;
- Constant const_value;
- public VariableInfo VariableInfo;
- HoistedVariable hoisted_variant;
- LocalBuilder builder;
- public LocalVariable (Block block, string name, Location loc)
- {
- this.block = block;
- this.name = name;
- this.loc = loc;
- }
- public LocalVariable (Block block, string name, Flags flags, Location loc)
- : this (block, name, loc)
- {
- this.flags = flags;
- }
- //
- // Used by variable declarators
- //
- public LocalVariable (LocalVariable li, string name, Location loc)
- : this (li.block, name, li.flags, loc)
- {
- }
- #region Properties
- public bool AddressTaken {
- get {
- return (flags & Flags.AddressTaken) != 0;
- }
- }
- public Block Block {
- get {
- return block;
- }
- }
- public Constant ConstantValue {
- get {
- return const_value;
- }
- set {
- const_value = value;
- }
- }
- //
- // Hoisted local variable variant
- //
- public HoistedVariable HoistedVariant {
- get {
- return hoisted_variant;
- }
- set {
- hoisted_variant = value;
- }
- }
- public bool IsDeclared {
- get {
- return type != null;
- }
- }
- public bool IsCompilerGenerated {
- get {
- return (flags & Flags.CompilerGenerated) != 0;
- }
- }
- public bool IsConstant {
- get {
- return (flags & Flags.Constant) != 0;
- }
- }
- public bool IsLocked {
- get {
- return (flags & Flags.IsLocked) != 0;
- }
- set {
- flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
- }
- }
- public bool IsThis {
- get {
- return (flags & Flags.IsThis) != 0;
- }
- }
- public bool IsFixed {
- get {
- return (flags & Flags.FixedVariable) != 0;
- }
- }
- bool INamedBlockVariable.IsParameter {
- get {
- return false;
- }
- }
- public bool IsReadonly {
- get {
- return (flags & Flags.ReadonlyMask) != 0;
- }
- }
- public Location Location {
- get {
- return loc;
- }
- }
- public string Name {
- get {
- return name;
- }
- }
- public TypeSpec Type {
- get {
- return type;
- }
- set {
- type = value;
- }
- }
- #endregion
- public void CreateBuilder (EmitContext ec)
- {
- if ((flags & Flags.Used) == 0) {
- if (VariableInfo == null) {
- // Missing flow analysis or wrong variable flags
- throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
- }
- if (VariableInfo.IsEverAssigned)
- ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
- else
- ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
- }
- if (HoistedVariant != null)
- return;
- if (builder != null) {
- if ((flags & Flags.CompilerGenerated) != 0)
- return;
- // To avoid Used warning duplicates
- throw new InternalErrorException ("Already created variable `{0}'", name);
- }
- //
- // All fixed variabled are pinned, a slot has to be alocated
- //
- builder = ec.DeclareLocal (Type, IsFixed);
- if (!ec.HasSet (BuilderContext.Options.OmitDebugInfo) && (flags & Flags.CompilerGenerated) == 0)
- ec.DefineLocalVariable (name, builder);
- }
- public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
- {
- LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
- li.Type = type;
- return li;
- }
- public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
- {
- if (IsConstant && const_value != null)
- return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
- return new LocalVariableReference (this, loc);
- }
- public void Emit (EmitContext ec)
- {
- // TODO: Need something better for temporary variables
- if ((flags & Flags.CompilerGenerated) != 0)
- CreateBuilder (ec);
- ec.Emit (OpCodes.Ldloc, builder);
- }
- public void EmitAssign (EmitContext ec)
- {
- // TODO: Need something better for temporary variables
- if ((flags & Flags.CompilerGenerated) != 0)
- CreateBuilder (ec);
- ec.Emit (OpCodes.Stloc, builder);
- }
- public void EmitAddressOf (EmitContext ec)
- {
- ec.Emit (OpCodes.Ldloca, builder);
- }
- public static string GetCompilerGeneratedName (Block block)
- {
- // HACK: Debugger depends on the name semantics
- return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
- }
- public string GetReadOnlyContext ()
- {
- switch (flags & Flags.ReadonlyMask) {
- case Flags.FixedVariable:
- return "fixed variable";
- case Flags.ForeachVariable:
- return "foreach iteration variable";
- case Flags.UsingVariable:
- return "using variable";
- }
- throw new InternalErrorException ("Variable is not readonly");
- }
- public bool IsThisAssigned (BlockContext ec, Block block)
- {
- if (VariableInfo == null)
- throw new Exception ();
- if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
- return true;
- return VariableInfo.IsFullyInitialized (ec, block.StartLocation);
- }
- public bool IsAssigned (BlockContext ec)
- {
- if (VariableInfo == null)
- throw new Exception ();
- return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
- }
- public void PrepareForFlowAnalysis (BlockContext bc)
- {
- //
- // No need for definitely assigned check for these guys
- //
- if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
- return;
- VariableInfo = new VariableInfo (this, bc.FlowOffset);
- bc.FlowOffset += VariableInfo.Length;
- }
- //
- // Mark the variables as referenced in the user code
- //
- public void SetIsUsed ()
- {
- flags |= Flags.Used;
- }
- public void SetHasAddressTaken ()
- {
- flags |= (Flags.AddressTaken | Flags.Used);
- }
- public override string ToString ()
- {
- return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
- }
- }
- /// <summary>
- /// Block represents a C# block.
- /// </summary>
- ///
- /// <remarks>
- /// This class is used in a number of places: either to represent
- /// explicit blocks that the programmer places or implicit blocks.
- ///
- /// Implicit blocks are used as labels or to introduce variable
- /// declarations.
- ///
- /// Top-level blocks derive from Block, and they are called ToplevelBlock
- /// they contain extra information that is not necessary on normal blocks.
- /// </remarks>
- public class Block : Statement {
- [Flags]
- public enum Flags
- {
- Unchecked = 1,
- HasRet = 8,
- Unsafe = 16,
- HasCapturedVariable = 64,
- HasCapturedThis = 1 << 7,
- IsExpressionTree = 1 << 8,
- CompilerGenerated = 1 << 9,
- HasAsyncModifier = 1 << 10,
- Resolved = 1 << 11,
- YieldBlock = 1 << 12,
- AwaitBlock = 1 << 13
- }
- public Block Parent;
- public Location StartLocation;
- public Location EndLocation;
- public ExplicitBlock Explicit;
- public ParametersBlock ParametersBlock;
- protected Flags flags;
- //
- // The statements in this block
- //
- protected List<Statement> statements;
- protected List<Statement> scope_initializers;
- int? resolving_init_idx;
- Block original;
- #if DEBUG
- static int id;
- public int ID = id++;
- static int clone_id_counter;
- int clone_id;
- #endif
- // int assignable_slots;
- public Block (Block parent, Location start, Location end)
- : this (parent, 0, start, end)
- {
- }
- public Block (Block parent, Flags flags, Location start, Location end)
- {
- if (parent != null) {
- // the appropriate constructors will fixup these fields
- ParametersBlock = parent.ParametersBlock;
- Explicit = parent.Explicit;
- }
-
- this.Parent = parent;
- this.flags = flags;
- this.StartLocation = start;
- this.EndLocation = end;
- this.loc = start;
- statements = new List<Statement> (4);
- this.original = this;
- }
- #region Properties
- public bool HasUnreachableClosingBrace {
- get {
- return (flags & Flags.HasRet) != 0;
- }
- set {
- flags = value ? flags | Flags.HasRet : flags & ~Flags.HasRet;
- }
- }
- public Block Original {
- get {
- return original;
- }
- protected set {
- original = value;
- }
- }
- public bool IsCompilerGenerated {
- get { return (flags & Flags.CompilerGenerated) != 0; }
- set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
- }
- public bool Unchecked {
- get { return (flags & Flags.Unchecked) != 0; }
- set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
- }
- public bool Unsafe {
- get { return (flags & Flags.Unsafe) != 0; }
- set { flags |= Flags.Unsafe; }
- }
- public List<Statement> Statements {
- get { return statements; }
- }
- #endregion
- public Block CreateSwitchBlock (Location start)
- {
- // FIXME: Only explicit block should be created
- var new_block = new Block (this, start, start);
- new_block.IsCompilerGenerated = true;
- return new_block;
- }
- public void SetEndLocation (Location loc)
- {
- EndLocation = loc;
- }
- public void AddLabel (LabeledStatement target)
- {
- ParametersBlock.TopBlock.AddLabel (target.Name, target);
- }
- public void AddLocalName (LocalVariable li)
- {
- AddLocalName (li.Name, li);
- }
- public void AddLocalName (string name, INamedBlockVariable li)
- {
- ParametersBlock.TopBlock.AddLocalName (name, li, false);
- }
- public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
- {
- if (reason == null) {
- Error_AlreadyDeclared (name, variable);
- return;
- }
- ParametersBlock.TopBlock.Report.Error (136, variable.Location,
- "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",
- name, reason);
- }
- public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
- {
- var pi = variable as ParametersBlock.ParameterInfo;
- if (pi != null) {
- pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
- } else {
- ParametersBlock.TopBlock.Report.Error (128, variable.Location,
- "A local variable named `{0}' is already defined in this scope", name);
- }
- }
-
- public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
- {
- ParametersBlock.TopBlock.Repo…
Large files files are truncated, but you can click here to view the full file