{
ec.Mark (loc);
DoEmit (ec);
+
+ if (ec.StatementEpilogue != null) {
+ ec.EmitEpilogue ();
+ }
}
//
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
{
// nothing needed.
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class If : Statement {
loc = l;
}
+ public Expression Expr {
+ get {
+ return this.expr;
+ }
+ }
+
public override bool Resolve (BlockContext ec)
{
bool ok = true;
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 l)
+ public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
{
expr = bool_expr;
EmbeddedStatement = statement;
- loc = l;
+ loc = doLocation;
+ WhileLocation = whileLocation;
+ }
+
+ public Location WhileLocation {
+ get; private set;
}
public override bool Resolve (BlockContext ec)
EmbeddedStatement.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
+ // Mark start of while condition
+ ec.Mark (WhileLocation);
+
//
// Dead code elimination
//
- if (expr is Constant){
+ if (expr is Constant) {
bool res = !((Constant) expr).IsDefaultValue;
expr.EmitSideEffect (ec);
if (res)
- ec.Emit (OpCodes.Br, loop);
- } else
+ ec.Emit (OpCodes.Br, loop);
+ } else {
expr.EmitBranchable (ec, loop, true);
+ }
ec.MarkLabel (ec.LoopEnd);
target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
target.expr = expr.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class While : Statement {
//
// Inform whether we are infinite or not
//
- if (expr is Constant){
+ 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);
Statement.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
- ec.Mark (loc);
+ ec.Mark (loc);
expr.EmitBranchable (ec, while_loop, true);
ec.MarkLabel (ec.LoopEnd);
ec.LoopEnd = old_end;
}
- public override void Emit (EmitContext ec)
- {
- DoEmit (ec);
- }
-
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 {
- Expression Test;
- Statement InitStatement;
- Statement Increment;
- public Statement Statement;
+ public class For : Statement
+ {
bool infinite, empty;
- public For (Statement init_statement,
- BooleanExpression test,
- Statement increment,
- Statement statement,
- Location l)
- {
- InitStatement = init_statement;
- Test = test;
- Increment = increment;
- Statement = statement;
+ 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 (InitStatement != null){
- if (!InitStatement.Resolve (ec))
+ if (Initializer != null) {
+ if (!Initializer.Resolve (ec))
ok = false;
}
- if (Test != null){
- Test = Test.Resolve (ec);
- if (Test == null)
+ if (Condition != null) {
+ Condition = Condition.Resolve (ec);
+ if (Condition == null)
ok = false;
- else if (Test is Constant){
- bool value = !((Constant) Test).IsDefaultValue;
+ else if (Condition is Constant) {
+ bool value = !((Constant) Condition).IsDefaultValue;
if (value == false){
if (!Statement.ResolveUnreachable (ec, true))
return false;
- if ((Increment != null) &&
- !Increment.ResolveUnreachable (ec, false))
+ if ((Iterator != null) &&
+ !Iterator.ResolveUnreachable (ec, false))
return false;
empty = true;
return true;
ok = false;
ec.EndFlowBranching ();
- if (Increment != null){
+ if (Iterator != null){
if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
- if (!Increment.ResolveUnreachable (ec, !was_unreachable))
+ if (!Iterator.ResolveUnreachable (ec, !was_unreachable))
ok = false;
} else {
- if (!Increment.Resolve (ec))
+ if (!Iterator.Resolve (ec))
ok = false;
}
}
protected override void DoEmit (EmitContext ec)
{
- if (InitStatement != null)
- InitStatement.Emit (ec);
+ if (Initializer != null)
+ Initializer.Emit (ec);
if (empty) {
- Test.EmitSideEffect (ec);
+ Condition.EmitSideEffect (ec);
return;
}
Statement.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
- Increment.Emit (ec);
+ Iterator.Emit (ec);
ec.MarkLabel (test);
//
// If test is null, there is no test, and we are just
// an infinite loop
//
- if (Test != null){
+ 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 (Test is Constant) {
- Test.EmitSideEffect (ec);
+ if (Condition is Constant) {
+ Condition.EmitSideEffect (ec);
ec.Emit (OpCodes.Br, loop);
} else {
- Test.EmitBranchable (ec, loop, true);
+ Condition.EmitBranchable (ec, loop, true);
}
} else
{
For target = (For) t;
- if (InitStatement != null)
- target.InitStatement = InitStatement.Clone (clonectx);
- if (Test != null)
- target.Test = Test.Clone (clonectx);
- if (Increment != null)
- target.Increment = Increment.Clone (clonectx);
+ 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
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;
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);
+ }
}
//
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 sealed override bool Resolve (BlockContext ec)
{
- if (!DoResolve (ec))
- return false;
-
+ var res = DoResolve (ec);
unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
+ return res;
}
}
/// </summary>
public class Return : ExitStatement
{
- protected Expression Expr;
+ Expression expr;
public Return (Expression expr, Location l)
{
- Expr = expr;
+ this.expr = expr;
loc = l;
}
#region Properties
- public Expression Expression {
+
+ public Expression Expr {
get {
- return Expr;
+ return expr;
+ }
+ protected set {
+ expr = value;
}
}
+
#endregion
protected override bool DoResolve (BlockContext ec)
{
- if (Expr == null) {
+ if (expr == null) {
if (ec.ReturnType.Kind == MemberKind.Void)
return true;
//
// Extra trick not to emit ret/leave inside awaiter body
//
- Expr = EmptyExpression.Null;
+ expr = EmptyExpression.Null;
return true;
}
}
return false;
}
- Expr = Expr.Resolve (ec);
+ expr = expr.Resolve (ec);
TypeSpec block_return_type = ec.ReturnType;
AnonymousExpression am = ec.CurrentAnonymousMethod;
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) {
var async_block = am as AsyncInitializer;
if (async_block != null) {
- if (Expr != 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);
+ 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>",
+ "`{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
//
- block_return_type = async_type.TypeArguments[0];
+ 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);
+ if (l != null && l.ReturnTypeInference != null && expr != null) {
+ l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
return true;
}
}
}
- if (Expr == null)
+ if (expr == null)
return false;
- if (Expr.Type != block_return_type) {
- Expr = Convert.ImplicitConversionRequired (ec, Expr, block_return_type, loc);
+ if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
+ expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
- if (Expr == null) {
+ 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",
protected override void DoEmit (EmitContext ec)
{
- if (Expr != null) {
- Expr.Emit (ec);
+ if (expr != null) {
+ expr.Emit (ec);
var async_body = ec.CurrentAnonymousMethod as AsyncInitializer;
if (async_body != null) {
if (async_return != null) {
async_return.EmitAssign (ec);
- ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
+ ec.EmitEpilogue ();
}
+ ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
return;
}
- if (unwind_protect)
+ ec.EmitEpilogue ();
+
+ if (unwind_protect || ec.EmitAccurateDebugInfo)
ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
}
- if (unwind_protect)
+ if (unwind_protect) {
ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
- else
+ } else if (ec.EmitAccurateDebugInfo) {
+ ec.Emit (OpCodes.Br, ec.CreateReturnLabel ());
+ } else {
ec.Emit (OpCodes.Ret);
+ }
}
void Error_ReturnFromIterator (ResolveContext rc)
{
Return target = (Return) t;
// It's null for simple return;
- if (Expr != null)
- target.Expr = Expr.Clone (clonectx);
+ if (expr != null)
+ target.expr = expr.Clone (clonectx);
+ }
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
}
}
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 {
{
referenced = true;
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
{
ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
loc = l;
}
+ public Expression Expr {
+ get {
+ return this.expr;
+ }
+ }
+
public override bool Resolve (BlockContext ec)
{
if (ec.Switch == null){
res = c;
} else {
TypeSpec type = ec.Switch.SwitchType;
- res = c.TryReduce (ec, type, c.Location);
+ res = c.TryReduce (ec, type);
if (res == null) {
- c.Error_ValueCannotBeConverted (ec, loc, type, true);
+ c.Error_ValueCannotBeConverted (ec, type, true);
return false;
}
target.expr = expr.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Throw : Statement {
loc = l;
}
+ public Expression Expr {
+ get {
+ return this.expr;
+ }
+ }
+
public override bool Resolve (BlockContext ec)
{
if (expr == null) {
if (expr != null)
target.expr = expr.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Break : Statement {
{
// nothing needed
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Continue : Statement {
{
// nothing needed.
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public interface ILocalVariable
protected FullNamedExpression type_expr;
protected LocalVariable li;
protected List<Declarator> declarators;
+ TypeSpec type;
public BlockVariableDeclaration (FullNamedExpression type, LocalVariable li)
{
declarators.Add (decl);
}
- void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
+ static void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
{
- var container = bc.CurrentMemberDefinition.Parent;
+ 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);
public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
{
- if (li.Type == null) {
- TypeSpec type = null;
+ if (type == null && !li.IsCompilerGenerated) {
var vexpr = type_expr as VarExpr;
//
protected override void DoEmit (EmitContext ec)
{
- if (li.IsConstant)
- return;
-
li.CreateBuilder (ec);
if (Initializer != null)
if (declarators != null) {
foreach (var d in declarators) {
d.Variable.CreateBuilder (ec);
- if (d.Initializer != null)
+ if (d.Initializer != null) {
+ ec.Mark (d.Variable.Location);
((ExpressionStatement) d.Initializer).EmitStatement (ec);
+ }
}
}
}
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 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 (TypeSpec.IsReferenceType (li.Type))
initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
else
- initializer.Error_ValueCannotBeConverted (bc, initializer.Location, li.Type, false);
+ initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
return null;
}
li.ConstantValue = c;
return initializer;
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
//
}
}
+ public bool IsCompilerGenerated {
+ get {
+ return (flags & Flags.CompilerGenerated) != 0;
+ }
+ }
+
public bool IsConstant {
get {
return (flags & Flags.Constant) != 0;
// All fixed variabled are pinned, a slot has to be alocated
//
builder = ec.DeclareLocal (Type, IsFixed);
- if (SymbolWriter.HasSymbolWriter)
+ if (!ec.HasSet (BuilderContext.Options.OmitDebugInfo) && (flags & Flags.CompilerGenerated) == 0)
ec.DefineLocalVariable (name, builder);
}
public static string GetCompilerGeneratedName (Block block)
{
+ // HACK: Debugger depends on the name semantics
return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
}
if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
return true;
- return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
+ return VariableInfo.IsFullyInitialized (ec, block.StartLocation);
}
public bool IsAssigned (BlockContext ec)
int? resolving_init_idx;
- protected Block original;
+ Block original;
#if DEBUG
static int id;
#region Properties
- public bool HasRet {
- get { return (flags & Flags.HasRet) != 0; }
+ 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 {
set { flags |= Flags.Unsafe; }
}
+ public List<Statement> Statements {
+ get { return statements; }
+ }
+
#endregion
public Block CreateSwitchBlock (Location start)
AddLocalName (li.Name, li);
}
- public virtual void AddLocalName (string name, INamedBlockVariable li)
+ public void AddLocalName (string name, INamedBlockVariable li)
{
- ParametersBlock.TopBlock.AddLocalName (name, li);
+ ParametersBlock.TopBlock.AddLocalName (name, li, false);
}
public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
if (warn)
ec.Report.Warning (162, 2, loc, "Unreachable code detected");
- ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ fb.CurrentUsageVector.IsUnreachable = true;
bool ok = Resolve (ec);
ec.KillFlowBranching ();
if (scope_initializers != null)
EmitScopeInitializers (ec);
- ec.Mark (StartLocation);
DoEmit (ec);
-
- if (SymbolWriter.HasSymbolWriter)
- EmitSymbolInfo (ec);
}
protected void EmitScopeInitializers (EmitContext ec)
{
- SymbolWriter.OpenCompilerGeneratedBlock (ec);
-
- using (ec.With (EmitContext.Options.OmitDebugInfo, true)) {
- foreach (Statement s in scope_initializers)
- s.Emit (ec);
- }
-
- SymbolWriter.CloseCompilerGeneratedBlock (ec);
- }
-
- protected virtual void EmitSymbolInfo (EmitContext ec)
- {
+ foreach (Statement s in scope_initializers)
+ s.Emit (ec);
}
#if DEBUG
foreach (Statement s in statements)
target.statements.Add (s.Clone (clonectx));
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class ExplicitBlock : Block
}
public bool HasCapturedThis {
- set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+ set {
+ flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
+ }
get {
return (flags & Flags.HasCapturedThis) != 0;
}
}
+ //
+ // Used to indicate that the block has reference to parent
+ // block and cannot be made static when defining anonymous method
+ //
public bool HasCapturedVariable {
- set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+ set {
+ flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
+ }
get {
return (flags & Flags.HasCapturedVariable) != 0;
}
if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
return ec.CurrentAnonymousMethod.Storey;
- //
- // When referencing a variable in parent iterator/async storey
- // from nested anonymous method
- //
- if (ParametersBlock.am_storey is StateMachine) {
- return ParametersBlock.am_storey;
- }
-
if (am_storey == null) {
MemberBase mc = ec.MemberContext as MemberBase;
//
// Creates anonymous method storey for this block
//
- am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey");
+ am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
}
return am_storey;
public override void Emit (EmitContext ec)
{
if (am_storey != null) {
- DefineAnonymousStorey (ec);
+ DefineStoreyContainer (ec, am_storey);
am_storey.EmitStoreyInstantiation (ec, this);
}
- bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
- if (emit_debug_info)
+ if (scope_initializers != null)
+ EmitScopeInitializers (ec);
+
+ if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
+ ec.Emit (OpCodes.Nop);
+ }
+
+ if (Parent != null)
ec.BeginScope ();
- base.Emit (ec);
+ DoEmit (ec);
- if (emit_debug_info)
+ if (Parent != null)
ec.EndScope ();
+
+ if (ec.EmitAccurateDebugInfo && !HasUnreachableClosingBrace && !IsCompilerGenerated && ec.Mark (EndLocation)) {
+ ec.Emit (OpCodes.Nop);
+ }
}
- void DefineAnonymousStorey (EmitContext ec)
+ protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
{
+ if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+ storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+ storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
+ }
+
//
// Creates anonymous method storey
//
- if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+ storey.CreateContainer ();
+ storey.DefineContainer ();
+
+ if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
+
//
- // Creates parent storey reference when hoisted this is accessible
+ // Only first storey in path will hold this reference. All children blocks will
+ // reference it indirectly using $ref field
//
- if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
- ExplicitBlock parent = am_storey.OriginalSourceBlock.Explicit.Parent.Explicit;
+ for (Block b = Original.Explicit.Parent; b != null; b = b.Parent) {
+ var s = b.Explicit.AnonymousMethodStorey;
+ if (s != null) {
+ storey.HoistedThis = s.HoistedThis;
+ break;
+ }
+ }
- //
- // Hoisted this exists in top-level parent storey only
- //
- while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
- parent = parent.Parent.Explicit;
+ //
+ // We are the first storey on path and this has to be hoisted
+ //
+ if (storey.HoistedThis == null) {
+ foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
+ //
+ // ThisReferencesFromChildrenBlock holds all reference even if they
+ // are not on this path. It saves some memory otherwise it'd have to
+ // be in every explicit block. We run this check to see if the reference
+ // is valid for this storey
+ //
+ Block block_on_path = ref_block;
+ for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
- am_storey.AddParentStoreyReference (ec, parent.am_storey);
- }
+ if (block_on_path == null)
+ continue;
- am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+ if (storey.HoistedThis == null)
+ storey.AddCapturedThisField (ec);
- // TODO MemberCache: Review
- am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
- }
+ for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
+ if (b.AnonymousMethodStorey != null) {
+ b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
+ b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
+
+ //
+ // Stop propagation inside same top block
+ //
+ if (b.ParametersBlock == ParametersBlock.Original)
+ break;
+
+ b = b.ParametersBlock;
+ }
+
+ var pb = b as ParametersBlock;
+ if (pb != null && pb.StateMachine != null) {
+ if (pb.StateMachine == storey)
+ break;
- am_storey.CreateType ();
- am_storey.DefineType ();
- am_storey.ResolveTypeParameters ();
+ pb.StateMachine.AddParentStoreyReference (ec, storey);
+ }
+
+ b.HasCapturedVariable = true;
+ }
+ }
+ }
+ }
- var ref_blocks = am_storey.ReferencesFromChildrenBlock;
+ var ref_blocks = storey.ReferencesFromChildrenBlock;
if (ref_blocks != null) {
foreach (ExplicitBlock ref_block in ref_blocks) {
- for (ExplicitBlock b = ref_block.Explicit; b.am_storey != am_storey; b = b.Parent.Explicit) {
- if (b.am_storey != null) {
- b.am_storey.AddParentStoreyReference (ec, am_storey);
+ for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
+ if (b.AnonymousMethodStorey != null) {
+ b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
+ //
// Stop propagation inside same top block
- if (b.ParametersBlock.Original == ParametersBlock.Original)
+ //
+ if (b.ParametersBlock == ParametersBlock.Original)
break;
b = b.ParametersBlock;
}
+ var pb = b as ParametersBlock;
+ if (pb != null && pb.StateMachine != null) {
+ if (pb.StateMachine == storey)
+ break;
+
+ pb.StateMachine.AddParentStoreyReference (ec, storey);
+ }
+
b.HasCapturedVariable = true;
}
}
}
- am_storey.Define ();
- am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+ storey.Define ();
+ storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
}
public void RegisterAsyncAwait ()
while ((block.flags & Flags.AwaitBlock) == 0) {
block.flags |= Flags.AwaitBlock;
- if (block.Parent == null)
+ if (block is ParametersBlock)
return;
block = block.Parent.Explicit;
#region Properties
- public Block Block {
+ public ParametersBlock Block {
+ get {
+ return block;
+ }
+ }
+
+ Block INamedBlockVariable.Block {
get {
return block;
}
bool resolved;
protected bool unreachable;
protected ToplevelBlock top_block;
+ protected StateMachine state_machine;
public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
: base (parent, 0, start, start)
this.resolved = true;
this.unreachable = source.unreachable;
this.am_storey = source.am_storey;
+ this.state_machine = source.state_machine;
ParametersBlock = this;
// Overwrite original for comparison purposes when linking cross references
// between anonymous methods
//
- original = source;
+ Original = source.Original;
}
#region Properties
}
}
+ public StateMachine StateMachine {
+ get {
+ return state_machine;
+ }
+ }
+
public ToplevelBlock TopBlock {
get {
return top_block;
return base.CreateExpressionTree (ec);
}
+ public override void Emit (EmitContext ec)
+ {
+ if (state_machine != null && state_machine.OriginalSourceBlock != this) {
+ DefineStoreyContainer (ec, state_machine);
+ state_machine.EmitStoreyInstantiation (ec, this);
+ }
+
+ base.Emit (ec);
+ }
+
+ public void EmitEmbedded (EmitContext ec)
+ {
+ if (state_machine != null && state_machine.OriginalSourceBlock != this) {
+ DefineStoreyContainer (ec, state_machine);
+ state_machine.EmitStoreyInstantiation (ec, this);
+ }
+
+ base.Emit (ec);
+ }
+
public ParameterInfo GetParameterInfo (Parameter p)
{
for (int i = 0; i < parameters.Count; ++i) {
throw new ArgumentException ("Invalid parameter");
}
- public Expression GetParameterReference (int index, Location loc)
+ public ParameterReference GetParameterReference (int index, Location loc)
{
return new ParameterReference (parameter_info[index], loc);
}
unreachable = top_level.End ();
}
} catch (Exception e) {
- if (e is CompletionResult || rc.Report.IsDisabled)
+ if (e is CompletionResult || rc.Report.IsDisabled || e is FatalException)
throw;
if (rc.CurrentBlock != null) {
for (int i = 0; i < orig_count; ++i) {
Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
- if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+ if ((mod & Parameter.Modifier.OUT) == 0)
continue;
VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
}
}
- public void WrapIntoIterator (IMethodData method, TypeContainer host, TypeSpec iterator_type, bool is_enumerable)
+ public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
{
- ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
- pb.EndLocation = EndLocation;
- pb.statements = statements;
- pb.original = this;
+ var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
+ var stateMachine = new IteratorStorey (iterator);
- var iterator = new Iterator (pb, method, host, iterator_type, is_enumerable);
- am_storey = new IteratorStorey (iterator);
+ state_machine = stateMachine;
+ iterator.SetStateMachine (stateMachine);
- statements = new List<Statement> (1);
- AddStatement (new Return (iterator, iterator.Location));
- flags &= ~Flags.YieldBlock;
+ var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null);
+ tlb.Original = this;
+ tlb.IsCompilerGenerated = true;
+ tlb.state_machine = stateMachine;
+ tlb.AddStatement (new Return (iterator, iterator.Location));
+ return tlb;
}
- public void WrapIntoAsyncTask (IMemberContext context, TypeContainer host, TypeSpec returnType)
+ public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, Location loc)
{
- ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
- pb.EndLocation = EndLocation;
- pb.statements = statements;
- pb.original = this;
+ for (int i = 0; i < parameters.Count; i++) {
+ Parameter p = parameters[i];
+ Parameter.Modifier mod = p.ModFlags;
+ if ((mod & Parameter.Modifier.RefOutMask) != 0) {
+ host.Compiler.Report.Error (1988, p.Location,
+ "Async methods cannot have ref or out parameters");
+ return this;
+ }
+
+ if (p is ArglistParameter) {
+ host.Compiler.Report.Error (4006, p.Location,
+ "__arglist is not allowed in parameter list of async methods");
+ return this;
+ }
+
+ if (parameters.Types[i].IsPointer) {
+ host.Compiler.Report.Error (4005, p.Location,
+ "Async methods cannot have unsafe parameters");
+ return this;
+ }
+ }
+
+ if (!HasAwait) {
+ host.Compiler.Report.Warning (1998, 1, loc,
+ "Async block lacks `await' operator and will run synchronously");
+ }
var block_type = host.Module.Compiler.BuiltinTypes.Void;
- var initializer = new AsyncInitializer (pb, host, block_type);
+ var initializer = new AsyncInitializer (this, host, block_type);
initializer.Type = block_type;
- am_storey = new AsyncTaskStorey (context, initializer, returnType);
+ var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
- statements = new List<Statement> (1);
- AddStatement (new StatementExpression (initializer));
- flags &= ~Flags.AwaitBlock;
+ state_machine = stateMachine;
+ initializer.SetStateMachine (stateMachine);
+
+ var b = this is ToplevelBlock ?
+ new ToplevelBlock (host.Compiler, Parameters, Location.Null) :
+ new ParametersBlock (Parent, parameters, Location.Null) {
+ IsAsync = true,
+ };
+
+ b.Original = this;
+ b.IsCompilerGenerated = true;
+ b.state_machine = stateMachine;
+ b.AddStatement (new StatementExpression (initializer));
+ return b;
}
}
Dictionary<string, object> names;
Dictionary<string, object> labels;
- public HoistedVariable HoistedThisVariable;
-
- public Report Report {
- get { return compiler.Report; }
- }
+ List<ExplicitBlock> this_references;
public ToplevelBlock (CompilerContext ctx, Location loc)
: this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
{
this.compiler = ctx;
top_block = this;
+ flags |= Flags.HasRet;
ProcessParameters ();
}
//
- // Recreates a top level block from parameters block. Used for
- // compiler generated methods where the original block comes from
- // explicit child block. This works for already resolved blocks
- // only to ensure we resolve them in the correct flow order
+ // Recreates a top level block from parameters block. Used for
+ // compiler generated methods where the original block comes from
+ // explicit child block. This works for already resolved blocks
+ // only to ensure we resolve them in the correct flow order
+ //
+ public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
+ : base (source, parameters)
+ {
+ this.compiler = source.TopBlock.compiler;
+ top_block = this;
+ flags |= Flags.HasRet;
+ }
+
+ public bool IsIterator {
+ get {
+ return HasYield;
+ }
+ }
+
+ public Report Report {
+ get {
+ return compiler.Report;
+ }
+ }
+
+ //
+ // Used by anonymous blocks to track references of `this' variable
//
- public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
- : base (source, parameters)
- {
- this.compiler = source.TopBlock.compiler;
- top_block = this;
+ public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
+ get {
+ return this_references;
+ }
}
- public bool IsIterator {
+ //
+ // Returns the "this" instance variable of this block.
+ // See AddThisVariable() for more information.
+ //
+ public LocalVariable ThisVariable {
get {
- return HasYield;
+ return this_variable;
}
}
- public override void AddLocalName (string name, INamedBlockVariable li)
+ public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
{
if (names == null)
names = new Dictionary<string, object> ();
//
for (int i = 0; i < existing_list.Count; ++i) {
existing = existing_list[i];
- Block b = existing.Block;
+ Block b = existing.Block.Explicit;
// Collision at same level
- if (li.Block == b) {
+ if (li.Block.Explicit == b) {
li.Block.Error_AlreadyDeclared (name, li);
break;
}
// Collision with parent
- b = li.Block;
- while ((b = b.Parent) != null) {
- if (existing.Block == b) {
+ Block parent = li.Block.Explicit;
+ while ((parent = parent.Parent) != null) {
+ if (parent == b) {
li.Block.Error_AlreadyDeclared (name, li, "parent or current");
i = existing_list.Count;
break;
}
}
- // Collision with with children
- b = existing.Block;
- while ((b = b.Parent) != null) {
- if (li.Block == b) {
- li.Block.Error_AlreadyDeclared (name, li, "child");
- i = existing_list.Count;
- break;
+ if (!ignoreChildrenBlocks) {
+ // Collision with children
+ while ((b = b.Parent) != null) {
+ if (li.Block.Explicit == b) {
+ li.Block.Error_AlreadyDeclared (name, li, "child");
+ i = existing_list.Count;
+ break;
+ }
}
}
}
existing_list.Add (label);
}
+ public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
+ {
+ if (this_references == null)
+ this_references = new List<ExplicitBlock> ();
+
+ if (!this_references.Contains (block))
+ this_references.Add (block);
+ }
+
+ public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
+ {
+ this_references.Remove (block);
+ }
+
//
// Creates an arguments set from all parameters, useful for method proxy calls
//
return null;
}
- // <summary>
- // Returns the "this" instance variable of this block.
- // See AddThisVariable() for more information.
- // </summary>
- public LocalVariable ThisVariable {
- 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
#if PRODUCTION
try {
#endif
+ if (IsCompilerGenerated) {
+ using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+ base.Emit (ec);
+ }
+ } else {
+ base.Emit (ec);
+ }
- base.Emit (ec);
+ //
+ // If `HasReturnLabel' is set, then we already emitted a
+ // jump to the end of the method, so we must emit a `ret'
+ // there.
+ //
+ // Unfortunately, System.Reflection.Emit automatically emits
+ // a leave to the end of a finally block. This is a problem
+ // if no code is following the try/finally block since we may
+ // jump to a point after the end of the method.
+ // As a workaround, we're always creating a return label in
+ // this case.
+ //
+ if (ec.HasReturnLabel || !unreachable) {
+ if (ec.HasReturnLabel)
+ ec.MarkLabel (ec.ReturnLabel);
- ec.Mark (EndLocation);
+ if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
+ ec.Mark (EndLocation);
- if (ec.HasReturnLabel)
- ec.MarkLabel (ec.ReturnLabel);
+ if (ec.ReturnType.Kind != MemberKind.Void)
+ ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
- if (ec.return_value != null) {
- ec.Emit (OpCodes.Ldloc, ec.return_value);
ec.Emit (OpCodes.Ret);
- } else {
- //
- // If `HasReturnLabel' is set, then we already emitted a
- // jump to the end of the method, so we must emit a `ret'
- // there.
- //
- // Unfortunately, System.Reflection.Emit automatically emits
- // a leave to the end of a finally block. This is a problem
- // if no code is following the try/finally block since we may
- // jump to a point after the end of the method.
- // As a workaround, we're always creating a return label in
- // this case.
- //
-
- if (ec.HasReturnLabel || !unreachable) {
- if (ec.ReturnType.Kind != MemberKind.Void)
- ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
- ec.Emit (OpCodes.Ret);
- }
}
#if PRODUCTION
}
#endif
}
-
- protected override void EmitSymbolInfo (EmitContext ec)
- {
- AnonymousExpression ae = ec.CurrentAnonymousMethod;
- if ((ae != null) && (ae.Storey != null))
- SymbolWriter.DefineScopeVariable (ae.Storey.ID);
-
- base.EmitSymbolInfo (ec);
- }
}
public class SwitchLabel {
VariableReference value;
ExpressionStatement string_dictionary;
FieldExpr switch_cache_field;
- static int unique_counter;
ExplicitBlock block;
//
return null;
}
- public static void Reset ()
- {
- unique_counter = 0;
- }
-
public override bool Resolve (BlockContext ec)
{
Expr = Expr.Resolve (ec);
Expression cond = null;
for (int ci = 0; ci < s.Labels.Count; ++ci) {
- var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted, loc);
+ var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted);
if (ci > 0) {
- cond = new Binary (Binary.Operator.LogicalOr, cond, e, loc);
+ cond = new Binary (Binary.Operator.LogicalOr, cond, e);
} else {
cond = e;
}
}
- simple_stmt = new If (cond, s.Block, simple_stmt, loc);
+ //
+ // Compiler generated, hide from symbol file
+ //
+ simple_stmt = new If (cond, s.Block, simple_stmt, Location.Null);
}
// It's null for empty switch
var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
Field field = new Field (ctype, string_dictionary_type,
Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
- new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
+ new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
if (!field.Define ())
return;
ctype.AddField (field);
// Check if string dictionary is initialized and initialize
//
switch_cache_field.EmitBranchable (ec, l_initialized, true);
- string_dictionary.EmitStatement (ec);
+ using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+ string_dictionary.EmitStatement (ec);
+ }
ec.MarkLabel (l_initialized);
LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
protected override void DoEmit (EmitContext ec)
{
+ // Workaround broken flow-analysis
+ block.HasUnreachableClosingBrace = true;
+
//
// Needed to emit anonymous storey initialization
// Otherwise it does not contain any statements for now
target.Sections.Add (ss.Clone (clonectx));
}
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
// A place where execution can restart in an iterator
protected Statement stmt;
Label dispose_try_block;
bool prepared_for_dispose, emitted_dispose;
+ Method finally_host;
protected TryFinallyBlock (Statement stmt, Location loc)
: base (loc)
#endregion
protected abstract void EmitTryBody (EmitContext ec);
- protected abstract void EmitFinallyBody (EmitContext ec);
+ public abstract void EmitFinallyBody (EmitContext ec);
public override Label PrepareForDispose (EmitContext ec, Label end)
{
}
ec.MarkLabel (start_finally);
- EmitFinallyBody (ec);
+
+ if (finally_host != null) {
+ finally_host.Define ();
+ finally_host.Emit ();
+
+ // Now it's safe to add, to close it properly and emit sequence points
+ finally_host.Parent.AddMember (finally_host);
+
+ var ce = new CallEmitter ();
+ ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+ ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+ } else {
+ EmitFinallyBody (ec);
+ }
ec.EndExceptionBlock ();
}
bool emit_dispatcher = j < labels.Length;
if (emit_dispatcher) {
- //SymbolWriter.StartIteratorDispatcher (ec.ig);
ec.Emit (OpCodes.Ldloc, pc);
ec.EmitInt (first_resume_pc);
ec.Emit (OpCodes.Sub);
ec.Emit (OpCodes.Switch, labels);
- //SymbolWriter.EndIteratorDispatcher (ec.ig);
}
foreach (ResumableStatement s in resume_points)
ec.BeginFinallyBlock ();
- EmitFinallyBody (ec);
+ if (finally_host != null) {
+ var ce = new CallEmitter ();
+ ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+ ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+ } else {
+ EmitFinallyBody (ec);
+ }
ec.EndExceptionBlock ();
}
+
+ public override bool Resolve (BlockContext bc)
+ {
+ //
+ // Finally block inside iterator is called from MoveNext and
+ // Dispose methods that means we need to lift the block into
+ // newly created host method to emit the body only once. The
+ // original block then simply calls the newly generated method.
+ //
+ if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
+ var b = stmt as Block;
+ if (b != null && b.Explicit.HasYield) {
+ finally_host = bc.CurrentIterator.CreateFinallyHost (this);
+ }
+ }
+
+ return base.Resolve (bc);
+ }
}
//
this.expr = expr;
}
+ public Expression Expr {
+ get {
+ return this.expr;
+ }
+ }
+
public override bool Resolve (BlockContext ec)
{
expr = expr.Resolve (ec);
locked = false;
}
- using (ec.Set (ResolveContext.Options.LockScope)) {
- ec.StartFlowBranching (this);
- Statement.Resolve (ec);
- ec.EndFlowBranching ();
- }
-
- if (lv != null) {
- lv.IsLockedByStatement = locked;
- }
-
- base.Resolve (ec);
-
//
// Have to keep original lock value around to unlock same location
- // in the case the original has changed or is null
+ // in the case of original value has changed or is null
//
expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
expr_copy.Resolve (ec);
lock_taken.Resolve (ec);
}
+ using (ec.Set (ResolveContext.Options.LockScope)) {
+ ec.StartFlowBranching (this);
+ Statement.Resolve (ec);
+ ec.EndFlowBranching ();
+ }
+
+ if (lv != null) {
+ lv.IsLockedByStatement = locked;
+ }
+
+ base.Resolve (ec);
+
return true;
}
Statement.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
//
// if (lock_taken) Monitor.Exit (expr_copy)
target.expr = expr.Clone (clonectx);
target.stmt = Statement.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
+
}
public class Unchecked : Statement {
target.Block = clonectx.LookupBlock (Block);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Checked : Statement {
target.Block = clonectx.LookupBlock (Block);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Unsafe : Statement {
target.Block = clonectx.LookupBlock (Block);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
//
// fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
//
converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
- new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
- new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc), loc), loc)),
+ new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
+ new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
new NullLiteral (loc),
converted, loc);
target.decl = (VariableDeclaration) decl.Clone (clonectx);
target.statement = statement.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Catch : Statement
//
if (li.HoistedVariant != null) {
LocalTemporary lt = new LocalTemporary (li.Type);
- SymbolWriter.OpenCompilerGeneratedBlock (ec);
lt.Store (ec);
- SymbolWriter.CloseCompilerGeneratedBlock (ec);
// switch to assigning from the temporary variable and not from top of the stack
assign.UpdateSource (lt);
}
} else {
- SymbolWriter.OpenCompilerGeneratedBlock (ec);
ec.Emit (OpCodes.Pop);
- SymbolWriter.CloseCompilerGeneratedBlock (ec);
}
Block.Emit (ec);
if (li.Type.IsGenericParameter)
source = new UnboxCast (source, li.Type);
- assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc);
- Block.AddScopeStatement (new StatementExpression (assign));
+ //
+ // Uses Location.Null to hide from symbol file
+ //
+ assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
+ Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
}
}
this.fini = fini;
}
+ public Block Finallyblock {
+ get {
+ return fini;
+ }
+ }
+
public override bool Resolve (BlockContext ec)
{
bool ok = true;
if (ok)
ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
+
using (ec.With (ResolveContext.Options.FinallyScope, true)) {
if (!fini.Resolve (ec))
ok = false;
stmt.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
fini.Emit (ec);
}
if (fini != null)
target.fini = clonectx.LookupBlock (fini);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class TryCatch : ExceptionStatement
{
public Block Block;
- public List<Catch> Specific;
- public Catch General;
+ List<Catch> clauses;
readonly bool inside_try_finally;
public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
: base (l)
{
this.Block = block;
- this.Specific = catch_clauses;
+ this.clauses = catch_clauses;
this.inside_try_finally = inside_try_finally;
+ }
- Catch c = catch_clauses [0];
- if (c.IsGeneral) {
- this.General = c;
- catch_clauses.RemoveAt (0);
+ public List<Catch> Clauses {
+ get {
+ return clauses;
}
}
if (!Block.Resolve (ec))
ok = false;
- TypeSpec[] prev_catches = new TypeSpec [Specific.Count];
- int last_index = 0;
- foreach (Catch c in Specific){
+ for (int i = 0; i < clauses.Count; ++i) {
+ var c = clauses[i];
ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
if (!c.Resolve (ec)) {
}
TypeSpec resolved_type = c.CatchType;
- for (int ii = 0; ii < last_index; ++ii) {
- if (resolved_type == prev_catches[ii] || TypeSpec.IsBaseClass (resolved_type, prev_catches[ii], true)) {
- ec.Report.Error (160, c.loc,
- "A previous catch clause already catches all exceptions of this or a super type `{0}'",
- TypeManager.CSharpName (prev_catches [ii]));
- ok = false;
- }
- }
+ for (int ii = 0; ii < clauses.Count; ++ii) {
+ if (ii == i)
+ continue;
- prev_catches [last_index++] = resolved_type;
- }
+ if (clauses[ii].IsGeneral) {
+ if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
+ continue;
+
+ if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
+ continue;
+
+ if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
+ continue;
+
+ ec.Report.Warning (1058, 1, c.loc,
+ "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
- if (General != null) {
- foreach (Catch c in Specific) {
- if (c.CatchType.BuiltinType != BuiltinTypeSpec.Type.Exception)
continue;
+ }
- if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
+ if (ii >= i)
continue;
- if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
+ var ct = clauses[ii].CatchType;
+ if (ct == null)
continue;
- ec.Report.Warning (1058, 1, c.loc,
- "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
+ if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
+ ec.Report.Error (160, c.loc,
+ "A previous catch clause already catches all exceptions of this or a super type `{0}'",
+ ct.GetSignatureForError ());
+ ok = false;
+ }
}
-
- ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
-
- if (!General.Resolve (ec))
- ok = false;
}
ec.EndFlowBranching ();
Block.Emit (ec);
- foreach (Catch c in Specific)
+ foreach (Catch c in clauses)
c.Emit (ec);
- if (General != null)
- General.Emit (ec);
-
if (!inside_try_finally)
ec.EndExceptionBlock ();
}
TryCatch target = (TryCatch) t;
target.Block = clonectx.LookupBlock (Block);
- if (General != null)
- target.General = (Catch) General.Clone (clonectx);
- if (Specific != null){
- target.Specific = new List<Catch> ();
- foreach (Catch c in Specific)
- target.Specific.Add ((Catch) c.Clone (clonectx));
+ if (clauses != null){
+ target.clauses = new List<Catch> ();
+ foreach (Catch c in clauses)
+ target.clauses.Add ((Catch) c.Clone (clonectx));
}
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
public class Using : TryFinallyBlock
new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
lvr;
- Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
+ //
+ // Hide it from symbol file via null location
+ //
+ Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
// Add conditional call when disposing possible null variable
if (!type.IsStruct || type.IsNullableType)
- dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, loc);
+ dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
return dispose;
}
{
for (int i = declarators.Count - 1; i >= 0; --i) {
var d = declarators [i];
- var vd = new VariableDeclaration (d.Variable, type_expr.Location);
+ var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
vd.Initializer = d.Initializer;
vd.IsNested = true;
vd.dispose_call = CreateDisposeCall (bc, d.Variable);
declarators = null;
return stmt;
- }
+ }
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
VariableDeclaration decl;
#region Properties
- public Expression Expression {
+ public Expression Expr {
get {
return decl.Variable == null ? decl.Initializer : null;
}
#endregion
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // Don't emit sequence point it will be set on variable declaration
+ //
+ DoEmit (ec);
+ }
+
protected override void EmitTryBodyPrepare (EmitContext ec)
{
decl.Emit (ec);
stmt.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
decl.EmitDispose (ec);
}
target.decl = (VariableDeclaration) decl.Clone (clonectx);
target.stmt = stmt.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
/// <summary>
/// </summary>
public class Foreach : Statement
{
- sealed class ArrayForeach : Statement
+ abstract class IteratorStatement : Statement
{
- readonly Foreach for_each;
- readonly Statement statement;
+ protected readonly Foreach for_each;
+
+ protected IteratorStatement (Foreach @foreach)
+ {
+ this.for_each = @foreach;
+ this.loc = @foreach.expr.Location;
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (ec.EmitAccurateDebugInfo) {
+ ec.Emit (OpCodes.Nop);
+ }
+
+ base.Emit (ec);
+ }
+ }
- Expression conv;
+ sealed class ArrayForeach : IteratorStatement
+ {
TemporaryVariableReference[] lengths;
Expression [] length_exprs;
StatementExpression[] counter;
TemporaryVariableReference[] variables;
TemporaryVariableReference copy;
- Expression access;
- LocalVariableReference variable;
public ArrayForeach (Foreach @foreach, int rank)
+ : base (@foreach)
{
- for_each = @foreach;
- statement = for_each.statement;
- loc = @foreach.loc;
-
counter = new StatementExpression[rank];
variables = new TemporaryVariableReference[rank];
length_exprs = new Expression [rank];
lengths = new TemporaryVariableReference [rank];
}
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- throw new NotImplementedException ();
- }
-
public override bool Resolve (BlockContext ec)
{
Block variables_block = for_each.variable.Block;
for (int i = 0; i < rank; i++) {
var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
variables[i] = v;
- counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
+ counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
counter[i].Resolve (ec);
if (rank == 1) {
list.Add (new Argument (v));
}
- access = new ElementAccess (copy, list, loc).Resolve (ec);
+ var access = new ElementAccess (copy, list, loc).Resolve (ec);
if (access == null)
return false;
var_type = access.Type;
} else {
var_type = for_each.type.ResolveAsType (ec);
+
+ if (var_type == null)
+ return false;
+
+ access = Convert.ExplicitConversion (ec, access, var_type, loc);
+ if (access == null)
+ return false;
}
- if (var_type == null)
- return false;
+ for_each.variable.Type = var_type;
- conv = Convert.ExplicitConversion (ec, access, var_type, loc);
- if (conv == null)
+ var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
+ if (variable_ref == null)
return false;
+ for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
+
bool ok = true;
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling ();
- for_each.variable.Type = conv.Type;
- variable = new LocalVariableReference (for_each.variable, loc);
- variable.Resolve (ec);
-
ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
- if (!statement.Resolve (ec))
+ if (!for_each.body.Resolve (ec))
ok = false;
ec.EndFlowBranching ();
ec.MarkLabel (loop [i]);
}
- variable.local_info.CreateBuilder (ec);
- variable.EmitAssign (ec, conv, false, false);
-
- statement.Emit (ec);
+ for_each.body.Emit (ec);
ec.MarkLabel (ec.LoopBegin);
+ ec.Mark (for_each.expr.Location);
for (int i = rank - 1; i >= 0; i--){
counter [i].Emit (ec);
}
}
- sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
+ sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
{
- class Body : Statement
- {
- TypeSpec type;
- LocalVariableReference variable;
- Expression current, conv;
- Statement statement;
-
- public Body (TypeSpec type, LocalVariable variable,
- Expression current, Statement statement,
- Location loc)
- {
- this.type = type;
- this.variable = new LocalVariableReference (variable, loc);
- this.current = current;
- this.statement = statement;
- this.loc = loc;
- }
-
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- throw new NotImplementedException ();
- }
-
- public override bool Resolve (BlockContext ec)
- {
- current = current.Resolve (ec);
- if (current == null)
- return false;
-
- conv = Convert.ExplicitConversion (ec, current, type, loc);
- if (conv == null)
- return false;
-
- variable.local_info.Type = conv.Type;
- variable.Resolve (ec);
-
- if (!statement.Resolve (ec))
- return false;
-
- return true;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- variable.local_info.CreateBuilder (ec);
- variable.EmitAssign (ec, conv, false, false);
-
- statement.Emit (ec);
- }
- }
-
class RuntimeDispose : Using.VariableDeclaration
{
public RuntimeDispose (LocalVariable lv, Location loc)
var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
dispose_variable.CreateReferenceExpression (bc, loc),
new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
- loc), new NullLiteral (loc), loc);
+ loc), new NullLiteral (loc));
var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
LocalVariable variable;
Expression expr;
Statement statement;
- Expression var_type;
ExpressionStatement init;
TemporaryVariableReference enumerator_variable;
bool ambiguous_getenumerator_name;
- public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
+ public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
+ : base (@foreach)
{
- this.var_type = var_type;
this.variable = var;
this.expr = expr;
- statement = stmt;
- loc = l;
- }
-
- protected override void CloneTo (CloneContext clonectx, Statement target)
- {
- throw new NotImplementedException ();
}
void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
} while (t != null);
if (iface_candidate == null) {
- rc.Report.Error (1579, loc,
- "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
- expr.Type.GetSignatureForError (), "GetEnumerator");
+ if (expr.Type != InternalType.ErrorType) {
+ rc.Report.Error (1579, loc,
+ "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
+ expr.Type.GetSignatureForError (), "GetEnumerator");
+ }
return null;
}
return null;
}
- return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
+ return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
}
PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
if (current_pe == null)
return false;
- VarExpr ve = var_type as VarExpr;
+ VarExpr ve = for_each.type as VarExpr;
if (ve != null) {
if (is_dynamic) {
current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
}
- variable.Type = var_type.ResolveAsType (ec);
+ variable.Type = for_each.type.ResolveAsType (ec);
+
+ if (variable.Type == null)
+ return false;
+
+ current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
+ if (current_pe == null)
+ return false;
}
- if (variable.Type == null)
+ var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
+ if (variable_ref == null)
return false;
+ for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
+
var init = new Invocation (get_enumerator_mg, null);
statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
- new Body (variable.Type, variable, current_pe, statement, loc), loc);
+ for_each.body, Location.Null);
var enum_type = enumerator_variable.Type;
//
// Runtime Dispose check
//
- var vd = new RuntimeDispose (enumerator_variable.LocalInfo, loc);
+ var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
vd.Initializer = init;
- statement = new Using (vd, statement, loc);
+ statement = new Using (vd, statement, Location.Null);
} else {
//
// No Dispose call needed
//
- this.init = new SimpleAssign (enumerator_variable, init);
+ this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
this.init.Resolve (ec);
}
} else {
//
// Static Dispose check
//
- var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
+ var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
vd.Initializer = init;
- statement = new Using (vd, statement, loc);
+ statement = new Using (vd, statement, Location.Null);
}
return statement.Resolve (ec);
bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
{
ec.Report.SymbolRelatedToPreviousError (best);
- ec.Report.Warning (278, 2, loc,
+ ec.Report.Warning (278, 2, expr.Location,
"`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
expr.Type.GetSignatureForError (), "enumerable",
best.GetSignatureForError (), ambiguous.GetSignatureForError ());
LocalVariable variable;
Expression expr;
Statement statement;
+ Block body;
- public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
+ public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
{
this.type = type;
this.variable = var;
this.expr = expr;
- statement = stmt;
+ this.statement = stmt;
+ this.body = body;
loc = l;
}
+ public Expression Expr {
+ get { return expr; }
+ }
+
public Statement Statement {
get { return statement; }
}
+ public Expression TypeExpression {
+ get { return type; }
+ }
+
+ public LocalVariable Variable {
+ get { return variable; }
+ }
+
public override bool Resolve (BlockContext ec)
{
expr = expr.Resolve (ec);
return false;
}
+ body.AddStatement (statement);
+
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
statement = new ArrayForeach (this, 1);
} else if (expr.Type is ArrayContainer) {
return false;
}
- statement = new CollectionForeach (type, variable, expr, statement, loc);
+ statement = new CollectionForeach (this, variable, expr);
}
return statement.Resolve (ec);
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 ();
target.type = type.Clone (clonectx);
target.expr = expr.Clone (clonectx);
+ target.body = (Block) body.Clone (clonectx);
target.statement = statement.Clone (clonectx);
}
+
+ public override object Accept (StructuralVisitor visitor)
+ {
+ return visitor.Visit (this);
+ }
}
}