using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
-using System.Collections;
-using System.Collections.Specialized;
+using System.Collections.Generic;
namespace Mono.CSharp {
/// Resolves the statement, true means that all sub-statements
/// did resolve ok.
// </summary>
- public virtual bool Resolve (EmitContext ec)
+ public virtual bool Resolve (BlockContext ec)
{
return true;
}
/// We already know that the statement is unreachable, but we still
/// need to resolve it to catch errors.
/// </summary>
- public virtual bool ResolveUnreachable (EmitContext ec, bool warn)
+ public virtual bool ResolveUnreachable (BlockContext ec, bool warn)
{
//
// This conflicts with csc's way of doing this, but IMHO it's
//
if (warn)
- Report.Warning (162, 2, loc, "Unreachable code detected");
+ ec.Report.Warning (162, 2, loc, "Unreachable code detected");
ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
bool ok = Resolve (ec);
/// </summary>
protected abstract void DoEmit (EmitContext ec);
- /// <summary>
- /// Utility wrapper routine for Error, just to beautify the code
- /// </summary>
- public void Error (int error, string format, params object[] args)
- {
- Error (error, String.Format (format, args));
- }
-
- public void Error (int error, string s)
- {
- if (!loc.IsNull)
- Report.Error (error, loc, s);
- else
- Report.Error (error, s);
- }
-
- /// <summary>
- /// Return value indicates whether all code paths emitted return.
- /// </summary>
public virtual void Emit (EmitContext ec)
{
ec.Mark (loc);
return s;
}
- public virtual Expression CreateExpressionTree (EmitContext ec)
+ public virtual Expression CreateExpressionTree (ResolveContext ec)
{
- Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
+ ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
return null;
}
return Clone (clonectx);
}
-
- public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
}
- //
- // This class is used during the Statement.Clone operation
- // to remap objects that have been cloned.
- //
- // Since blocks are cloned by Block.Clone, we need a way for
- // expressions that must reference the block to be cloned
- // pointing to the new cloned block.
- //
- public class CloneContext {
- Hashtable block_map = new Hashtable ();
- Hashtable variable_map;
-
- public void AddBlockMap (Block from, Block to)
- {
- if (block_map.Contains (from))
- return;
- block_map [from] = to;
- }
-
- public Block LookupBlock (Block from)
- {
- Block result = (Block) block_map [from];
-
- if (result == null){
- result = (Block) from.Clone (this);
- block_map [from] = result;
- }
-
- return result;
- }
-
- ///
- /// Remaps block to cloned copy if one exists.
- ///
- public Block RemapBlockCopy (Block from)
- {
- Block mapped_to = (Block)block_map[from];
- if (mapped_to == null)
- return from;
-
- return mapped_to;
- }
-
- public void AddVariableMap (LocalInfo from, LocalInfo to)
- {
- if (variable_map == null)
- variable_map = new Hashtable ();
-
- if (variable_map.Contains (from))
- return;
- variable_map [from] = to;
- }
-
- public LocalInfo LookupVariable (LocalInfo from)
+ public sealed class EmptyStatement : Statement
+ {
+ public EmptyStatement (Location loc)
{
- LocalInfo result = (LocalInfo) variable_map [from];
-
- if (result == null)
- throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
-
- return result;
+ this.loc = loc;
}
- }
-
- public sealed class EmptyStatement : Statement {
- private EmptyStatement () {}
-
- public static readonly EmptyStatement Value = new EmptyStatement ();
-
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
return true;
}
- public override bool ResolveUnreachable (EmitContext ec, bool warn)
+ public override bool ResolveUnreachable (BlockContext ec, bool warn)
{
return true;
}
- protected override void DoEmit (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ protected override void DoEmit (EmitContext ec)
{
+ throw new NotSupportedException ();
}
protected override void CloneTo (CloneContext clonectx, Statement target)
public Statement FalseStatement;
bool is_true_ret;
-
- public If (Expression expr, Statement true_statement, Location l)
+
+ public If (Expression bool_expr, Statement true_statement, Location l)
+ : this (bool_expr, true_statement, null, l)
{
- this.expr = expr;
- TrueStatement = true_statement;
- loc = l;
}
- public If (Expression expr,
+ public If (Expression bool_expr,
Statement true_statement,
Statement false_statement,
Location l)
{
- this.expr = expr;
+ this.expr = bool_expr;
TrueStatement = true_statement;
FalseStatement = false_statement;
loc = l;
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
- TrueStatement.MutateHoistedGenericType (storey);
- if (FalseStatement != null)
- FalseStatement.MutateHoistedGenericType (storey);
- }
-
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
Report.Debug (1, "START IF BLOCK", loc);
- expr = Expression.ResolveBoolean (ec, expr, loc);
- if (expr == null){
+ expr = expr.Resolve (ec);
+ if (expr == null) {
ok = false;
- goto skip;
- }
-
- Assign ass = expr as Assign;
- if (ass != null && ass.Source is Constant) {
- Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
- }
+ } else {
+ //
+ // Dead code elimination
+ //
+ if (expr is Constant) {
+ bool take = !((Constant) expr).IsDefaultValue;
- //
- // Dead code elimination
- //
- if (expr is Constant){
- bool take = !((Constant) expr).IsDefaultValue;
+ if (take) {
+ if (!TrueStatement.Resolve (ec))
+ return false;
- 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.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;
+ }
- if ((FalseStatement != null) &&
- !FalseStatement.Resolve (ec))
- return false;
+ return true;
}
-
- return true;
}
- skip:
+
ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
ok &= TrueStatement.Resolve (ec);
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- Label false_target = ig.DefineLabel ();
+ Label false_target = ec.DefineLabel ();
Label end;
//
if (FalseStatement != null){
bool branch_emitted = false;
- end = ig.DefineLabel ();
+ end = ec.DefineLabel ();
if (!is_true_ret){
- ig.Emit (OpCodes.Br, end);
+ ec.Emit (OpCodes.Br, end);
branch_emitted = true;
}
- ig.MarkLabel (false_target);
+ ec.MarkLabel (false_target);
FalseStatement.Emit (ec);
if (branch_emitted)
- ig.MarkLabel (end);
+ ec.MarkLabel (end);
} else {
- ig.MarkLabel (false_target);
+ ec.MarkLabel (false_target);
}
}
public class Do : Statement {
public Expression expr;
public Statement EmbeddedStatement;
-
- public Do (Statement statement, Expression bool_expr, Location l)
+
+ public Do (Statement statement, BooleanExpression bool_expr, Location l)
{
expr = bool_expr;
EmbeddedStatement = statement;
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
ec.EndFlowBranching ();
if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
- Report.Warning (162, 2, expr.Location, "Unreachable code detected");
+ ec.Report.Warning (162, 2, expr.Location, "Unreachable code detected");
- expr = Expression.ResolveBoolean (ec, expr, loc);
+ expr = expr.Resolve (ec);
if (expr == null)
ok = false;
else if (expr is Constant){
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- Label loop = ig.DefineLabel ();
+ Label loop = ec.DefineLabel ();
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- ec.LoopBegin = ig.DefineLabel ();
- ec.LoopEnd = ig.DefineLabel ();
+ ec.LoopBegin = ec.DefineLabel ();
+ ec.LoopEnd = ec.DefineLabel ();
- ig.MarkLabel (loop);
+ ec.MarkLabel (loop);
EmbeddedStatement.Emit (ec);
- ig.MarkLabel (ec.LoopBegin);
+ ec.MarkLabel (ec.LoopBegin);
//
// Dead code elimination
expr.EmitSideEffect (ec);
if (res)
- ec.ig.Emit (OpCodes.Br, loop);
+ ec.Emit (OpCodes.Br, loop);
} else
expr.EmitBranchable (ec, loop, true);
- ig.MarkLabel (ec.LoopEnd);
+ ec.MarkLabel (ec.LoopEnd);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
- EmbeddedStatement.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Do target = (Do) t;
public Expression expr;
public Statement Statement;
bool infinite, empty;
-
- public While (Expression bool_expr, Statement statement, Location l)
+
+ public While (BooleanExpression bool_expr, Statement statement, Location l)
{
this.expr = bool_expr;
Statement = statement;
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
- expr = Expression.ResolveBoolean (ec, expr, loc);
+ expr = expr.Resolve (ec);
if (expr == null)
- return false;
+ ok = false;
//
// Inform whether we are infinite or not
return;
}
- ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- ec.LoopBegin = ig.DefineLabel ();
- ec.LoopEnd = ig.DefineLabel ();
+ 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
- ig.MarkLabel (ec.LoopBegin);
+ ec.MarkLabel (ec.LoopBegin);
expr.EmitSideEffect (ec);
Statement.Emit (ec);
- ig.Emit (OpCodes.Br, ec.LoopBegin);
+ ec.Emit (OpCodes.Br, ec.LoopBegin);
//
// Inform that we are infinite (ie, `we return'), only
// if we do not `break' inside the code.
//
- ig.MarkLabel (ec.LoopEnd);
+ ec.MarkLabel (ec.LoopEnd);
} else {
- Label while_loop = ig.DefineLabel ();
+ Label while_loop = ec.DefineLabel ();
- ig.Emit (OpCodes.Br, ec.LoopBegin);
- ig.MarkLabel (while_loop);
+ ec.Emit (OpCodes.Br, ec.LoopBegin);
+ ec.MarkLabel (while_loop);
Statement.Emit (ec);
- ig.MarkLabel (ec.LoopBegin);
+ ec.MarkLabel (ec.LoopBegin);
ec.Mark (loc);
expr.EmitBranchable (ec, while_loop, true);
- ig.MarkLabel (ec.LoopEnd);
+ ec.MarkLabel (ec.LoopEnd);
}
ec.LoopBegin = old_begin;
target.expr = expr.Clone (clonectx);
target.Statement = Statement.Clone (clonectx);
}
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
- Statement.MutateHoistedGenericType (storey);
- }
}
public class For : Statement {
bool infinite, empty;
public For (Statement init_statement,
- Expression test,
+ BooleanExpression test,
Statement increment,
Statement statement,
Location l)
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
}
if (Test != null){
- Test = Expression.ResolveBoolean (ec, Test, loc);
+ Test = Test.Resolve (ec);
if (Test == null)
ok = false;
else if (Test is Constant){
protected override void DoEmit (EmitContext ec)
{
- if (InitStatement != null && InitStatement != EmptyStatement.Value)
+ if (InitStatement != null)
InitStatement.Emit (ec);
if (empty) {
return;
}
- ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- Label loop = ig.DefineLabel ();
- Label test = ig.DefineLabel ();
+ Label loop = ec.DefineLabel ();
+ Label test = ec.DefineLabel ();
- ec.LoopBegin = ig.DefineLabel ();
- ec.LoopEnd = ig.DefineLabel ();
+ ec.LoopBegin = ec.DefineLabel ();
+ ec.LoopEnd = ec.DefineLabel ();
- ig.Emit (OpCodes.Br, test);
- ig.MarkLabel (loop);
+ ec.Emit (OpCodes.Br, test);
+ ec.MarkLabel (loop);
Statement.Emit (ec);
- ig.MarkLabel (ec.LoopBegin);
- if (Increment != EmptyStatement.Value)
- Increment.Emit (ec);
+ ec.MarkLabel (ec.LoopBegin);
+ Increment.Emit (ec);
- ig.MarkLabel (test);
+ ec.MarkLabel (test);
//
// If test is null, there is no test, and we are just
// an infinite loop
//
if (Test is Constant) {
Test.EmitSideEffect (ec);
- ig.Emit (OpCodes.Br, loop);
+ ec.Emit (OpCodes.Br, loop);
} else {
Test.EmitBranchable (ec, loop, true);
}
} else
- ig.Emit (OpCodes.Br, loop);
- ig.MarkLabel (ec.LoopEnd);
+ ec.Emit (OpCodes.Br, loop);
+ ec.MarkLabel (ec.LoopEnd);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- if (InitStatement != null)
- InitStatement.MutateHoistedGenericType (storey);
- if (Test != null)
- Test.MutateHoistedGenericType (storey);
- if (Increment != null)
- Increment.MutateHoistedGenericType (storey);
-
- Statement.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
For target = (For) t;
loc = expr.Location;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- if (expr != null)
- expr = expr.ResolveStatement (ec);
+ expr = expr.ResolveStatement (ec);
return expr != null;
}
expr.EmitStatement (ec);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
- }
-
public override string ToString ()
{
return "StatementExpression (" + expr + ")";
public abstract class ExitStatement : Statement
{
protected bool unwind_protect;
- protected abstract bool DoResolve (EmitContext ec);
+ protected abstract bool DoResolve (BlockContext ec);
- public virtual void Error_FinallyClause ()
+ 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 (EmitContext ec)
+ public sealed override bool Resolve (BlockContext ec)
{
if (!DoResolve (ec))
return false;
loc = l;
}
- protected override bool DoResolve (EmitContext ec)
+ protected override bool DoResolve (BlockContext ec)
{
if (Expr == null) {
if (ec.ReturnType == TypeManager.void_type)
return true;
- Error (126, "An object of a type convertible to `{0}' is required " +
- "for the return statement",
- TypeManager.CSharpName (ec.ReturnType));
+ ec.Report.Error (126, loc,
+ "An object of a type convertible to `{0}' is required for the return statement",
+ TypeManager.CSharpName (ec.ReturnType));
return false;
}
if (ec.CurrentBlock.Toplevel.IsIterator) {
- Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
+ ec.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");
}
AnonymousExpression am = ec.CurrentAnonymousMethod;
if (am == null && ec.ReturnType == TypeManager.void_type) {
- MemberCore mc = ec.ResolveContext as MemberCore;
- Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
- mc.GetSignatureForError ());
+ ec.Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
+ ec.GetSignatureForError ());
}
Expr = Expr.Resolve (ec);
if (Expr == null)
return false;
+ if (ec.HasSet (ResolveContext.Options.InferReturnType)) {
+ ec.ReturnTypeInference.AddCommonTypeBound (Expr.Type);
+ return true;
+ }
+
if (Expr.Type != ec.ReturnType) {
- if (ec.InferReturnType) {
- //
- // void cannot be used in contextual return
- //
- if (Expr.Type == TypeManager.void_type)
- return false;
+ Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc);
- ec.ReturnType = Expr.Type;
- } else {
- Expr = Convert.ImplicitConversionRequired (
- ec, Expr, ec.ReturnType, loc);
-
- if (Expr == null) {
- if (am != null) {
- 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;
+ if (Expr == null) {
+ if (am != null) {
+ 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;
}
}
Expr.Emit (ec);
if (unwind_protect)
- ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
+ ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
}
if (unwind_protect)
- ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+ ec.Emit (OpCodes.Leave, ec.ReturnLabel);
else
- ec.ig.Emit (OpCodes.Ret);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- if (Expr != null)
- Expr.MutateHoistedGenericType (storey);
+ ec.Emit (OpCodes.Ret);
}
protected override void CloneTo (CloneContext clonectx, Statement t)
string target;
LabeledStatement label;
bool unwind_protect;
-
- public override bool Resolve (EmitContext ec)
+
+ public override bool Resolve (BlockContext ec)
{
- int errors = Report.Errors;
unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return errors == Report.Errors;
+ return true;
}
public Goto (string label, Location l)
if (label == null)
throw new InternalErrorException ("goto emitted before target resolved");
Label l = label.LabelTarget (ec);
- ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
+ ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
}
}
bool defined;
bool referenced;
Label label;
- ILGenerator ig;
FlowBranching.UsageVector vectors;
{
if (defined)
return label;
- ig = ec.ig;
- label = ec.ig.DefineLabel ();
- defined = true;
+ label = ec.DefineLabel ();
+ defined = true;
return label;
}
// nothing to clone
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
// this flow-branching will be terminated when the surrounding block ends
ec.StartFlowBranching (this);
protected override void DoEmit (EmitContext ec)
{
- if (ig != null && ig != ec.ig)
- throw new InternalErrorException ("cannot happen");
LabelTarget (ec);
- ec.ig.MarkLabel (label);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
+ ec.MarkLabel (label);
}
public void AddReference ()
// nothing to clone
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
- }
- protected override void DoEmit (EmitContext ec)
- {
- if (ec.Switch == null){
- Report.Error (153, loc, "A goto case is only valid inside a switch statement");
- return;
+ 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");
- return;
+ if (!ec.Switch.GotDefault) {
+ FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
+ return false;
}
- ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
+
+ return true;
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ protected override void DoEmit (EmitContext ec)
{
+ ec.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
}
}
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
if (ec.Switch == null){
- Report.Error (153, loc, "A goto case is only valid inside a switch statement");
+ 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) {
- Error (150, "A constant value is expected");
+ ec.Report.Error (150, expr.Location, "A constant value is expected");
return false;
}
- Type type = ec.Switch.SwitchType;
- if (!Convert.ImplicitStandardConversionExists (c, type))
- Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " +
- "convertible to type `{0}'", TypeManager.CSharpName (type));
-
- bool fail = false;
- object val = c.GetValue ();
- if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type))
- val = TypeManager.ChangeType (val, type, out fail);
-
- if (fail) {
- Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
- c.GetSignatureForError (), TypeManager.CSharpName (type));
+ TypeSpec type = ec.Switch.SwitchType;
+ Constant res = c.TryReduce (ec, type, c.Location);
+ if (res == null) {
+ c.Error_ValueCannotBeConverted (ec, loc, 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));
+
+ object val = res.GetValue ();
if (val == null)
val = SwitchLabel.NullStringCase;
- sl = (SwitchLabel) ec.Switch.Elements [val];
-
- if (sl == null){
+ if (!ec.Switch.Elements.TryGetValue (val, out sl)) {
FlowBranchingBlock.Error_UnknownLabel (loc, "case " +
- (c.GetValue () == null ? "null" : val.ToString ()));
+ (c.GetValue () == null ? "null" : val.ToString ()), ec.Report);
return false;
}
- ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
+ ec.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
}
protected override void CloneTo (CloneContext clonectx, Statement t)
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
if (expr == null) {
ec.CurrentBranching.CurrentUsageVector.Goto ();
if (expr == null)
return false;
- Type t = expr.Type;
+ if (Convert.ImplicitConversionExists (ec, expr, TypeManager.exception_type))
+ expr = Convert.ImplicitConversion (ec, expr, TypeManager.exception_type, loc);
+ else
+ ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
- if ((t != TypeManager.exception_type) &&
- !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
- !(expr is NullLiteral)) {
- Error (155, "The type caught or thrown must be derived from System.Exception");
- return false;
- }
return true;
}
protected override void DoEmit (EmitContext ec)
{
if (expr == null)
- ec.ig.Emit (OpCodes.Rethrow);
+ ec.Emit (OpCodes.Rethrow);
else {
expr.Emit (ec);
- ec.ig.Emit (OpCodes.Throw);
+ ec.Emit (OpCodes.Throw);
}
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- if (expr != null)
- expr.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Throw target = (Throw) t;
bool unwind_protect;
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- int errors = Report.Errors;
unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return errors == Report.Errors;
+ return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
+ ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
// nothing needed
bool unwind_protect;
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- int errors = Report.Errors;
unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
ec.CurrentBranching.CurrentUsageVector.Goto ();
- return errors == Report.Errors;
+ return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
+ ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
}
protected override void CloneTo (CloneContext clonectx, Statement t)
// The information about a user-perceived local variable
//
public class LocalInfo : IKnownVariable, ILocalVariable {
- public readonly Expression Type;
+ public readonly FullNamedExpression Type;
- public Type VariableType;
+ public TypeSpec VariableType;
public readonly string Name;
public readonly Location Location;
public readonly Block Block;
public VariableInfo VariableInfo;
- public HoistedVariable HoistedVariableReference;
+ HoistedVariable hoisted_variant;
[Flags]
enum Flags : byte {
Flags flags;
ReadOnlyContext ro_context;
LocalBuilder builder;
-
- public LocalInfo (Expression type, string name, Block block, Location l)
+
+ public LocalInfo (FullNamedExpression type, string name, Block block, Location l)
{
Type = type;
Name = name;
Location = l;
}
- public LocalInfo (DeclSpace ds, Block block, Location l)
+ public LocalInfo (TypeContainer ds, Block block, Location l)
{
- VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
+ VariableType = ds.IsGeneric ? ds.CurrentType : ds.Definition;
Block = block;
Location = l;
}
public void ResolveVariable (EmitContext ec)
{
- if (HoistedVariableReference != null)
+ if (HoistedVariant != null)
return;
if (builder == null) {
- if (Pinned)
- //
- // This is needed to compile on both .NET 1.x and .NET 2.x
- // the later introduced `DeclareLocal (Type t, bool pinned)'
- //
- builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
- else
- builder = ec.ig.DeclareLocal (VariableType);
+ builder = ec.DeclareLocal (VariableType, Pinned);
}
}
public void Emit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldloc, builder);
+ ec.Emit (OpCodes.Ldloc, builder);
}
public void EmitAssign (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Stloc, builder);
+ ec.Emit (OpCodes.Stloc, builder);
}
public void EmitAddressOf (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldloca, builder);
+ ec.Emit (OpCodes.Ldloca, builder);
}
public void EmitSymbolInfo (EmitContext ec)
ec.DefineLocalVariable (Name, builder);
}
- public bool IsThisAssigned (EmitContext ec)
+ //
+ // Hoisted local variable variant
+ //
+ public HoistedVariable HoistedVariant {
+ get {
+ return hoisted_variant;
+ }
+ set {
+ hoisted_variant = value;
+ }
+ }
+
+ public bool IsThisAssigned (BlockContext ec, Block block)
{
if (VariableInfo == null)
throw new Exception ();
if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
return true;
- return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc);
+ return VariableInfo.TypeInfo.IsFullyInitialized (ec, VariableInfo, block.StartLocation);
}
- public bool IsAssigned (EmitContext ec)
+ public bool IsAssigned (BlockContext ec)
{
if (VariableInfo == null)
throw new Exception ();
return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
}
- public bool Resolve (EmitContext ec)
+ public bool Resolve (ResolveContext ec)
{
if (VariableType != null)
return true;
VariableType = texpr.Type;
- if (TypeManager.IsGenericParameter (VariableType))
- return true;
-
- if (VariableType.IsAbstract && VariableType.IsSealed) {
- FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
+ if (VariableType.IsStatic) {
+ FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType, ec.Report);
return false;
}
- if (VariableType.IsPointer && !ec.InUnsafe)
- Expression.UnsafeError (Location);
+ if (VariableType.IsPointer && !ec.IsUnsafe)
+ Expression.UnsafeError (ec, Location);
return true;
}
// Variables in anonymous block are not resolved yet
//
if (VariableType == null)
- return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+ return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
//
// Variables in method block are resolved
public ToplevelBlock Toplevel; // TODO: Use Explicit
[Flags]
- public enum Flags : byte {
+ public enum Flags
+ {
Unchecked = 1,
BlockUsed = 2,
VariablesInitialized = 4,
HasRet = 8,
- IsDestructor = 16,
- Unsafe = 32,
- IsIterator = 64,
- HasStoreyAccess = 128
+ Unsafe = 16,
+ IsIterator = 32,
+ HasCapturedVariable = 64,
+ HasCapturedThis = 1 << 7,
+ IsExpressionTree = 1 << 8
}
+
protected Flags flags;
public bool Unchecked {
//
// The statements in this block
//
- protected ArrayList statements;
+ protected List<Statement> statements;
//
// An array of Blocks. We keep track of children just
// Statements and child statements are handled through the
// statements.
//
- ArrayList children;
+ List<Block> children;
//
// Labels. (label, block) pairs.
//
- protected HybridDictionary labels;
+ protected Dictionary<string, LabeledStatement> labels;
//
// Keeps track of (name, type) pairs
//
- IDictionary variables;
- protected IDictionary range_variables;
+ Dictionary<string, LocalInfo> variables;
//
// Keeps track of constants
- HybridDictionary constants;
+ Dictionary<string, Expression> constants;
//
// Temporary variables.
//
- ArrayList temporary_variables;
+ List<LocalInfo> temporary_variables;
//
// If this is a switch section, the enclosing switch block.
//
Block switch_block;
- ArrayList scope_initializers;
+ protected List<Statement> scope_initializers;
+
+ List<ToplevelBlock> anonymous_children;
- ArrayList anonymous_children;
+ int? resolving_init_idx;
protected static int id;
: this (parent, (Flags) 0, start, end)
{ }
+ //
+ // Useful when TopLevel block is downgraded to normal block
+ //
+ public Block (ToplevelBlock parent, ToplevelBlock source)
+ : this (parent, source.flags, source.StartLocation, source.EndLocation)
+ {
+ statements = source.statements;
+ children = source.children;
+ labels = source.labels;
+ variables = source.variables;
+ constants = source.constants;
+ switch_block = source.switch_block;
+ }
+
public Block (Block parent, Flags flags, Location start, Location end)
{
if (parent != null) {
this.EndLocation = end;
this.loc = start;
this_id = id++;
- statements = new ArrayList (4);
+ statements = new List<Statement> (4);
}
public Block CreateSwitchBlock (Location start)
get { return this_id; }
}
- public IDictionary Variables {
+ public IDictionary<string, LocalInfo> Variables {
get {
if (variables == null)
- variables = new ListDictionary ();
+ variables = new Dictionary<string, LocalInfo> ();
return variables;
}
}
void AddChild (Block b)
{
if (children == null)
- children = new ArrayList (1);
+ children = new List<Block> (1);
children.Add (b);
}
EndLocation = loc;
}
- protected static void Error_158 (string name, Location loc)
+ protected void Error_158 (string name, Location loc)
{
- Report.Error (158, loc, "The label `{0}' shadows another label " +
+ Toplevel.Report.Error (158, loc, "The label `{0}' shadows another label " +
"by the same name in a contained scope", name);
}
while (cur != null) {
LabeledStatement s = cur.DoLookupLabel (name);
if (s != null) {
- Report.SymbolRelatedToPreviousError (s.loc, s.Name);
- Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
+ Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
+ Toplevel.Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
return false;
}
if (s == null)
continue;
- Report.SymbolRelatedToPreviousError (s.loc, s.Name);
+ Toplevel.Report.SymbolRelatedToPreviousError (s.loc, s.Name);
Error_158 (name, target.loc);
return false;
}
Toplevel.CheckError158 (name, target.loc);
if (labels == null)
- labels = new HybridDictionary();
+ labels = new Dictionary<string, LabeledStatement> ();
labels.Add (name, target);
return true;
return switch_block.LookupLabel (name);
if (labels != null)
- if (labels.Contains (name))
- return ((LabeledStatement) labels [name]);
+ if (labels.ContainsKey (name))
+ return labels [name];
return null;
}
// block, we violate the invariant meaning in a block.
//
if (b == this) {
- Report.SymbolRelatedToPreviousError (kvi.Location, name);
- Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
+ Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ Toplevel.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
return false;
}
return true;
if (this is ToplevelBlock) {
- Report.SymbolRelatedToPreviousError (kvi.Location, name);
- e.Error_VariableIsUsedBeforeItIsDeclared (name);
+ Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ e.Error_VariableIsUsedBeforeItIsDeclared (Toplevel.Report, name);
return false;
}
// Even though we detected the error when the name is used, we
// treat it as if the variable declaration was in error.
//
- Report.SymbolRelatedToPreviousError (loc, name);
+ Toplevel.Report.SymbolRelatedToPreviousError (loc, name);
Error_AlreadyDeclared (kvi.Location, name, "parent or current");
return false;
}
- public LocalInfo AddVariable (Expression type, string name, Location l)
+ protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
{
LocalInfo vi = GetLocalInfo (name);
if (vi != null) {
- Report.SymbolRelatedToPreviousError (vi.Location, name);
+ block.Report.SymbolRelatedToPreviousError (vi.Location, name);
if (Explicit == vi.Block.Explicit) {
- if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type)
- Error_AlreadyDeclared (l, name);
- else
- Error_AlreadyDeclared (l, name, null);
+ Error_AlreadyDeclared (l, name, null);
} else {
- Error_AlreadyDeclared (l, name, "parent");
+ Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
+ "parent or current" : "parent");
}
- return null;
+ return false;
}
- ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name);
- if (pi != null) {
- Report.SymbolRelatedToPreviousError (pi.Location, name);
- Error_AlreadyDeclared (loc, name,
- pi.Block == Toplevel ? "method argument" : "parent or current");
- return null;
+ if (block != null) {
+ Expression e = block.GetParameterReference (name, Location.Null);
+ if (e != null) {
+ ParameterReference pr = e as ParameterReference;
+ if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
+ Error_AlreadyDeclared (loc, name);
+ else
+ Error_AlreadyDeclared (loc, name, "parent or current");
+ return false;
+ }
}
-
+
+ return true;
+ }
+
+ public LocalInfo AddVariable (Expression type, string name, Location l)
+ {
+ if (!CheckParentConflictName (Toplevel, name, l))
+ return null;
+
if (Toplevel.GenericMethod != null) {
foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
if (tp.Name == name) {
- Report.SymbolRelatedToPreviousError (tp);
- Error_AlreadyDeclaredTypeParameter (loc, name);
+ Toplevel.Report.SymbolRelatedToPreviousError (tp);
+ Error_AlreadyDeclaredTypeParameter (Toplevel.Report, loc, name, "local variable");
return null;
}
}
IKnownVariable kvi = Explicit.GetKnownVariable (name);
if (kvi != null) {
- Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ Toplevel.Report.SymbolRelatedToPreviousError (kvi.Location, name);
Error_AlreadyDeclared (l, name, "child");
return null;
}
- vi = new LocalInfo (type, name, this, l);
+ LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
AddVariable (vi);
if ((flags & Flags.VariablesInitialized) != 0)
return;
}
- Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
+ Toplevel.Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
"in this scope because it would give a different meaning " +
"to `{0}', which is already used in a `{1}' scope " +
"to denote something else", var, reason);
protected virtual void Error_AlreadyDeclared (Location loc, string name)
{
- Report.Error (128, loc,
+ Toplevel.Report.Error (128, loc,
"A local variable named `{0}' is already defined in this scope", name);
}
- protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
+ public virtual void Error_AlreadyDeclaredTypeParameter (Report r, Location loc, string name, string conflict)
{
- GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
- }
+ r.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
+ name, conflict);
+ }
public bool AddConstant (Expression type, string name, Expression value, Location l)
{
return false;
if (constants == null)
- constants = new HybridDictionary();
+ constants = new Dictionary<string, Expression> ();
constants.Add (name, value);
Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
if (temporary_variables == null)
- temporary_variables = new ArrayList ();
+ temporary_variables = new List<LocalInfo> ();
int id = ++next_temp_id;
string name = "$s_" + id.ToString ();
LocalInfo ret;
for (Block b = this; b != null; b = b.Parent) {
if (b.variables != null) {
- ret = (LocalInfo) b.variables [name];
- if (ret != null)
- return ret;
- }
-
- if (b.range_variables != null) {
- ret = (LocalInfo) b.range_variables [name];
- if (ret != null)
+ if (b.variables.TryGetValue (name, out ret))
return ret;
}
}
public Expression GetConstantExpression (string name)
{
+ Expression ret;
for (Block b = this; b != null; b = b.Parent) {
if (b.constants != null) {
- Expression ret = b.constants [name] as Expression;
- if (ret != null)
+ if (b.constants.TryGetValue (name, out ret))
return ret;
}
}
// It should be used by expressions which require to
// register a statement during resolve process.
//
- public void AddScopeStatement (StatementExpression s)
+ public void AddScopeStatement (Statement s)
{
if (scope_initializers == null)
- scope_initializers = new ArrayList ();
+ scope_initializers = new List<Statement> ();
- scope_initializers.Add (s);
+ //
+ // Simple recursive helper, when resolve scope initializer another
+ // new scope initializer can be added, this ensures it's initialized
+ // before existing one. For now this can happen with expression trees
+ // in base ctor initializer only
+ //
+ if (resolving_init_idx.HasValue) {
+ scope_initializers.Insert (resolving_init_idx.Value, s);
+ ++resolving_init_idx;
+ } else {
+ scope_initializers.Add (s);
+ }
}
public void AddStatement (Statement s)
get { return (flags & Flags.HasRet) != 0; }
}
- public bool IsDestructor {
- get { return (flags & Flags.IsDestructor) != 0; }
- }
-
- public void SetDestructor ()
- {
- flags |= Flags.IsDestructor;
- }
-
public int AssignableSlots {
get {
// TODO: Re-enable
}
}
- public ArrayList AnonymousChildren {
+ public IList<ToplevelBlock> AnonymousChildren {
get { return anonymous_children; }
}
public void AddAnonymousChild (ToplevelBlock b)
{
if (anonymous_children == null)
- anonymous_children = new ArrayList ();
+ anonymous_children = new List<ToplevelBlock> ();
anonymous_children.Add (b);
}
- void DoResolveConstants (EmitContext ec)
+ void DoResolveConstants (BlockContext ec)
{
if (constants == null)
return;
if (variables == null)
throw new InternalErrorException ("cannot happen");
- foreach (DictionaryEntry de in variables) {
- string name = (string) de.Key;
- LocalInfo vi = (LocalInfo) de.Value;
- Type variable_type = vi.VariableType;
+ foreach (var de in variables) {
+ string name = de.Key;
+ LocalInfo vi = de.Value;
+ TypeSpec variable_type = vi.VariableType;
if (variable_type == null) {
if (vi.Type is VarExpr)
- Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
+ ec.Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
continue;
}
- Expression cv = (Expression) constants [name];
- if (cv == null)
+ Expression cv;
+ if (!constants.TryGetValue (name, out cv))
continue;
// Don't let 'const int Foo = Foo;' succeed.
// which in turn causes the 'must be constant' error to be triggered.
constants.Remove (name);
- if (!Const.IsConstantTypeValid (variable_type)) {
- Const.Error_InvalidConstantType (variable_type, loc);
+ if (!variable_type.IsConstantCompatible) {
+ Const.Error_InvalidConstantType (variable_type, loc, ec.Report);
continue;
}
ec.CurrentBlock = this;
Expression e;
- using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
+ using (ec.With (ResolveContext.Options.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
e = cv.Resolve (ec);
}
if (e == null)
Constant ce = e as Constant;
if (ce == null) {
- Const.Error_ExpressionMustBeConstant (vi.Location, name);
+ e.Error_ExpressionMustBeConstant (ec, vi.Location, name);
continue;
}
- e = ce.ConvertImplicitly (variable_type);
+ e = ce.ConvertImplicitly (ec, variable_type);
if (e == null) {
if (TypeManager.IsReferenceType (variable_type))
- Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name);
+ ce.Error_ConstantCanBeInitializedWithNullOnly (ec, variable_type, vi.Location, vi.Name);
else
ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
continue;
}
}
- protected void ResolveMeta (EmitContext ec, int offset)
+ protected void ResolveMeta (BlockContext ec, int offset)
{
Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
// If some parent block was unsafe, we remain unsafe even if this block
// isn't explicitly marked as such.
- using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
+ using (ec.With (ResolveContext.Options.UnsafeScope, ec.IsUnsafe | Unsafe)) {
flags |= Flags.VariablesInitialized;
if (variables != null) {
}
}
- void UsageWarning ()
+ void UsageWarning (BlockContext ec)
{
- if (variables == null || Report.WarningLevel < 3)
+ if (variables == null || ec.Report.WarningLevel < 3)
return;
- foreach (DictionaryEntry de in variables) {
- LocalInfo vi = (LocalInfo) de.Value;
+ foreach (var de in variables) {
+ LocalInfo vi = de.Value;
if (!vi.Used) {
- string name = (string) de.Key;
+ string name = de.Key;
// vi.VariableInfo can be null for 'catch' variables
if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
- Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
+ ec.Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
else
- Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
+ ec.Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
}
}
}
- static void CheckPossibleMistakenEmptyStatement (Statement s)
+ static void CheckPossibleMistakenEmptyStatement (BlockContext ec, Statement s)
{
Statement body;
return;
if (body == null || body is EmptyStatement)
- Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
+ ec.Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
Block prev_block = ec.CurrentBlock;
bool ok = true;
- int errors = Report.Errors;
+ int errors = ec.Report.Errors;
ec.CurrentBlock = this;
ec.StartFlowBranching (this);
Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+ //
+ // Compiler generated scope statements
+ //
+ if (scope_initializers != null) {
+ for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
+ scope_initializers[resolving_init_idx.Value].Resolve (ec);
+ }
+
+ resolving_init_idx = null;
+ }
+
//
// This flag is used to notate nested statements as unreachable from the beginning of this block.
// For the purposes of this resolution, it doesn't matter that the whole block is unreachable
//
int statement_count = statements.Count;
for (int ix = 0; ix < statement_count; ix++){
- Statement s = (Statement) statements [ix];
+ Statement s = statements [ix];
// Check possible empty statement (CS0642)
- if (Report.WarningLevel >= 3 &&
- ix + 1 < statement_count &&
- statements [ix + 1] is ExplicitBlock)
- CheckPossibleMistakenEmptyStatement (s);
+ if (ix + 1 < statement_count && ec.Report.WarningLevel >= 3 &&
+ statements [ix + 1] is ExplicitBlock)
+ CheckPossibleMistakenEmptyStatement (ec, s);
//
// Warn if we detect unreachable code.
continue;
if (!unreachable_shown && !(s is LabeledStatement)) {
- Report.Warning (162, 2, s.loc, "Unreachable code detected");
+ ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
unreachable_shown = true;
}
if (ec.IsInProbingMode)
break;
- statements [ix] = EmptyStatement.Value;
+ statements [ix] = new EmptyStatement (s.loc);
continue;
}
if (unreachable && !(s is LabeledStatement) && !(s is Block))
- statements [ix] = EmptyStatement.Value;
+ statements [ix] = new EmptyStatement (s.loc);
unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
if (unreachable && s is LabeledStatement)
if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
ok = false;
- if ((labels != null) && (Report.WarningLevel >= 2)) {
+ if ((labels != null) && (ec.Report.WarningLevel >= 2)) {
foreach (LabeledStatement label in labels.Values)
if (!label.HasBeenReferenced)
- Report.Warning (164, 2, label.loc, "This label has not been referenced");
+ ec.Report.Warning (164, 2, label.loc, "This label has not been referenced");
}
- if (ok && errors == Report.Errors)
- UsageWarning ();
+ if (ok && errors == ec.Report.Errors)
+ UsageWarning (ec);
return ok;
}
- public override bool ResolveUnreachable (EmitContext ec, bool warn)
+ public override bool ResolveUnreachable (BlockContext ec, bool warn)
{
unreachable_shown = true;
unreachable = true;
if (warn)
- Report.Warning (162, 2, loc, "Unreachable code detected");
+ ec.Report.Warning (162, 2, loc, "Unreachable code detected");
ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
bool ok = Resolve (ec);
public override void Emit (EmitContext ec)
{
- Block prev_block = ec.CurrentBlock;
- ec.CurrentBlock = this;
-
- if (scope_initializers != null) {
- SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
-
- using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
- foreach (StatementExpression s in scope_initializers)
- s.Emit (ec);
- }
-
- SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
- }
+ if (scope_initializers != null)
+ EmitScopeInitializers (ec);
ec.Mark (StartLocation);
DoEmit (ec);
if (SymbolWriter.HasSymbolWriter)
EmitSymbolInfo (ec);
-
- ec.CurrentBlock = prev_block;
}
- protected virtual void EmitSymbolInfo (EmitContext ec)
+ protected void EmitScopeInitializers (EmitContext ec)
{
- if (variables != null) {
- foreach (LocalInfo vi in variables.Values) {
- vi.EmitSymbolInfo (ec);
- }
- }
- }
+ SymbolWriter.OpenCompilerGeneratedBlock (ec);
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- MutateVariables (storey);
-
- if (scope_initializers != null) {
+ using (ec.With (EmitContext.Options.OmitDebugInfo, true)) {
foreach (Statement s in scope_initializers)
- s.MutateHoistedGenericType (storey);
+ s.Emit (ec);
}
- foreach (Statement s in statements)
- s.MutateHoistedGenericType (storey);
+ SymbolWriter.CloseCompilerGeneratedBlock (ec);
}
- void MutateVariables (AnonymousMethodStorey storey)
+ protected virtual void EmitSymbolInfo (EmitContext ec)
{
if (variables != null) {
foreach (LocalInfo vi in variables.Values) {
- vi.VariableType = storey.MutateType (vi.VariableType);
+ vi.EmitSymbolInfo (ec);
}
}
-
- if (temporary_variables != null) {
- foreach (LocalInfo vi in temporary_variables)
- vi.VariableType = storey.MutateType (vi.VariableType);
- }
}
public override string ToString ()
target.Parent = clonectx.RemapBlockCopy (Parent);
if (variables != null){
- target.variables = new Hashtable ();
+ target.variables = new Dictionary<string, LocalInfo> ();
- foreach (DictionaryEntry de in variables){
- LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
+ foreach (var de in variables){
+ LocalInfo newlocal = de.Value.Clone (clonectx);
target.variables [de.Key] = newlocal;
- clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
+ clonectx.AddVariableMap (de.Value, newlocal);
}
}
- target.statements = new ArrayList (statements.Count);
+ target.statements = new List<Statement> (statements.Count);
foreach (Statement s in statements)
target.statements.Add (s.Clone (clonectx));
if (target.children != null){
- target.children = new ArrayList (children.Count);
+ target.children = new List<Block> (children.Count);
foreach (Block b in children){
target.children.Add (clonectx.LookupBlock (b));
}
}
}
- public class ExplicitBlock : Block {
- HybridDictionary known_variables;
+ public class ExplicitBlock : Block
+ {
+ Dictionary<string, IKnownVariable> known_variables;
protected AnonymousMethodStorey am_storey;
public ExplicitBlock (Block parent, Location start, Location end)
internal void AddKnownVariable (string name, IKnownVariable info)
{
if (known_variables == null)
- known_variables = new HybridDictionary();
+ known_variables = new Dictionary<string, IKnownVariable> ();
known_variables [name] = info;
//
// Creates anonymous method storey in current block
//
- public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
+ public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
{
//
// When referencing a variable in iterator storey from children anonymous method
//
if (Toplevel.am_storey is IteratorStorey) {
- ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
return Toplevel.am_storey;
}
return ec.CurrentIterator.Storey;
if (am_storey == null) {
- MemberBase mc = ec.ResolveContext as MemberBase;
+ MemberBase mc = ec.MemberContext as MemberBase;
GenericMethod gm = mc == null ? null : mc.GenericMethod;
//
- // Create anonymous method storey for this block
+ // Creates anonymous method storey for this block
//
- am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
+ am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, gm, "AnonStorey");
}
- //
- // Creates a link between this block and the anonymous method
- //
- // An anonymous method can reference variables from any outer block, but they are
- // hoisted in their own ExplicitBlock. When more than one block is referenced we
- // need to create another link between those variable storeys
- //
- ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
return am_storey;
}
public override void Emit (EmitContext ec)
{
if (am_storey != null)
- am_storey.EmitHoistedVariables (ec);
+ am_storey.EmitStoreyInstantiation (ec);
bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
if (emit_debug_info)
//
if (am_storey != null) {
if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
- am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
+ //
+ // Creates parent storey reference when hoisted this is accessible
+ //
+ if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
+ ExplicitBlock parent = Toplevel.Parent.Explicit;
+
+ //
+ // Hoisted this exists in top-level parent storey only
+ //
+ while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
+ parent = parent.Parent.Explicit;
+
+ am_storey.AddParentStoreyReference (ec, parent.am_storey);
+ }
+
+ am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
+
+ // TODO MemberCache: Review
+ am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
}
+ am_storey.CreateType ();
+ if (am_storey.Mutator == null && ec.CurrentTypeParameters != null)
+ am_storey.Mutator = new TypeParameterMutator (ec.CurrentTypeParameters, am_storey.CurrentTypeParameters);
+
am_storey.DefineType ();
- am_storey.ResolveType ();
+ am_storey.ResolveTypeParameters ();
am_storey.Define ();
am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+
+ var ref_blocks = am_storey.ReferencesFromChildrenBlock;
+ if (ref_blocks != null) {
+ foreach (ExplicitBlock ref_block in ref_blocks) {
+ for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) {
+ if (b.am_storey != null) {
+ b.am_storey.AddParentStoreyReference (ec, am_storey);
+
+ // Stop propagation inside same top block
+ if (b.Toplevel == Toplevel)
+ break;
+
+ b = b.Toplevel;
+ }
+ b.HasCapturedVariable = true;
+ }
+ }
+ }
}
base.EmitMeta (ec);
internal IKnownVariable GetKnownVariable (string name)
{
- return known_variables == null ? null : (IKnownVariable) known_variables [name];
- }
+ if (known_variables == null)
+ return null;
- public void PropagateStoreyReference (AnonymousMethodStorey s)
- {
- if (Parent != null && am_storey != s) {
- if (am_storey != null)
- am_storey.AddParentStoreyReference (s);
+ IKnownVariable kw;
+ if (!known_variables.TryGetValue (name, out kw))
+ return null;
- Parent.Explicit.PropagateStoreyReference (s);
- }
+ return kw;
}
- public override bool Resolve (EmitContext ec)
+ public bool HasCapturedThis
{
- bool ok = base.Resolve (ec);
-
- //
- // Discard an anonymous method storey when this block has no hoisted variables
- //
- if (am_storey != null && !am_storey.HasHoistedVariables) {
- am_storey.Undo ();
- am_storey = null;
- }
+ set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+ get { return (flags & Flags.HasCapturedThis) != 0; }
+ }
- return ok;
+ public bool HasCapturedVariable
+ {
+ set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+ get { return (flags & Flags.HasCapturedVariable) != 0; }
}
protected override void CloneTo (CloneContext clonectx, Statement t)
get { return Block.Parameters [Index]; }
}
- public Type ParameterType {
+ public TypeSpec ParameterType {
get { return Block.Parameters.Types [Index]; }
}
// In particular, this was introduced when the support for Anonymous
// Methods was implemented.
//
- public class ToplevelBlock : ExplicitBlock {
+ public class ToplevelBlock : ExplicitBlock
+ {
+ //
+ // Block is converted to an expression
+ //
+ sealed class BlockScopeExpression : Expression
+ {
+ Expression child;
+ readonly ToplevelBlock block;
+
+ public BlockScopeExpression (Expression child, ToplevelBlock block)
+ {
+ this.child = child;
+ this.block = block;
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ throw new NotSupportedException ();
+ }
+
+ protected override Expression DoResolve (ResolveContext ec)
+ {
+ if (child == null)
+ return null;
+
+ child = child.Resolve (ec);
+ if (child == null)
+ return null;
+
+ eclass = child.eclass;
+ type = child.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ block.EmitMeta (ec);
+ block.EmitScopeInitializers (ec);
+ child.Emit (ec);
+ }
+ }
+
GenericMethod generic;
- FlowBranchingToplevel top_level_branching;
- Parameters parameters;
+ protected ParametersCompiled parameters;
ToplevelParameterInfo[] parameter_info;
LocalInfo this_variable;
+ bool resolved;
+ bool unreachable;
+ CompilerContext compiler;
public HoistedVariable HoistedThisVariable;
+ public bool Resolved {
+ get {
+ return resolved;
+ }
+ }
+
//
// The parameters for the block.
//
- public Parameters Parameters {
+ public ParametersCompiled Parameters {
get { return parameters; }
}
- public GenericMethod GenericMethod {
- get { return generic; }
+ public Report Report {
+ get { return compiler.Report; }
}
- public bool HasStoreyAccess {
- set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; }
- get { return (flags & Flags.HasStoreyAccess) != 0; }
+ public GenericMethod GenericMethod {
+ get { return generic; }
}
public ToplevelBlock Container {
get { return Parent == null ? null : Parent.Toplevel; }
}
- public ToplevelBlock (Block parent, Parameters parameters, Location start) :
- this (parent, (Flags) 0, parameters, start)
+ public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, Location start) :
+ this (ctx, parent, (Flags) 0, parameters, start)
{
}
- public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
- this (parent, parameters, start)
+ public ToplevelBlock (CompilerContext ctx, Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) :
+ this (ctx, parent, parameters, start)
{
this.generic = generic;
}
-
- public ToplevelBlock (Parameters parameters, Location start) :
- this (null, (Flags) 0, parameters, start)
+
+ public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start) :
+ this (ctx, null, (Flags) 0, parameters, start)
{
}
- ToplevelBlock (Flags flags, Parameters parameters, Location start) :
- this (null, flags, parameters, start)
+ ToplevelBlock (CompilerContext ctx, Flags flags, ParametersCompiled parameters, Location start) :
+ this (ctx, null, flags, parameters, start)
{
}
// We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
// So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
- public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) :
+ public ToplevelBlock (CompilerContext ctx, Block parent, Flags flags, ParametersCompiled parameters, Location start) :
base (null, flags, start, Location.Null)
{
+ this.compiler = ctx;
this.Toplevel = this;
- this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+ this.parameters = parameters;
this.Parent = parent;
if (parent != null)
parent.AddAnonymousChild (this);
ProcessParameters ();
}
- public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+ public ToplevelBlock (CompilerContext ctx, Location loc)
+ : this (ctx, null, (Flags) 0, ParametersCompiled.EmptyReadOnlyParameters, loc)
{
}
return true;
}
- public virtual Expression GetTransparentIdentifier (string name)
- {
- return null;
- }
-
void ProcessParameters ()
{
int n = parameters.Count;
parameter_info = new ToplevelParameterInfo [n];
+ ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel;
for (int i = 0; i < n; ++i) {
parameter_info [i] = new ToplevelParameterInfo (this, i);
continue;
string name = p.Name;
- LocalInfo vi = GetLocalInfo (name);
- if (vi != null) {
- Report.SymbolRelatedToPreviousError (vi.Location, name);
- Error_AlreadyDeclared (loc, name, "parent or current");
- continue;
- }
-
- ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name);
- if (pi != null) {
- Report.SymbolRelatedToPreviousError (pi.Location, name);
- Error_AlreadyDeclared (loc, name, "parent or current");
- continue;
- }
-
- AddKnownVariable (name, parameter_info [i]);
+ if (CheckParentConflictName (top_parent, name, loc))
+ AddKnownVariable (name, parameter_info [i]);
}
// mark this block as "used" so that we create local declarations in a sub-block
return true;
}
- public override Expression CreateExpressionTree (EmitContext ec)
+ public override Expression CreateExpressionTree (ResolveContext ec)
{
- if (statements.Count == 1)
- return ((Statement) statements [0]).CreateExpressionTree (ec);
+ if (statements.Count == 1) {
+ Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
+ if (scope_initializers != null)
+ expr = new BlockScopeExpression (expr, this);
+
+ return expr;
+ }
return base.CreateExpressionTree (ec);
}
//
public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
{
- // Create block with original statements
- ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
IsIterator = true;
- // TODO: Change to iter_block.statements = statements;
- foreach (Statement stmt in source.statements)
- iter_block.AddStatement (stmt);
- labels = source.labels;
-
- AddStatement (new IteratorStatement (iterator, iter_block));
+ // Creates block with original statements
+ AddStatement (new IteratorStatement (iterator, new Block (this, source)));
- source.statements = new ArrayList (1);
+ source.statements = new List<Statement> (1);
source.AddStatement (new Return (iterator, iterator.Location));
source.IsIterator = false;
return iterator_storey;
}
- public FlowBranchingToplevel TopLevelBranching {
- get { return top_level_branching; }
- }
-
//
- // Returns a `ParameterReference' for the given name, or null if there
- // is no such parameter
+ // Returns a parameter reference expression for the given name,
+ // or null if there is no such parameter
//
- public ParameterReference GetParameterReference (string name, Location loc)
- {
- ToplevelParameterInfo p = GetParameterInfo (name);
- return p == null ? null : new ParameterReference (this, p, loc);
- }
-
- public ToplevelParameterInfo GetParameterInfo (string name)
+ public Expression GetParameterReference (string name, Location loc)
{
- int idx;
for (ToplevelBlock t = this; t != null; t = t.Container) {
- Parameter par = t.Parameters.GetParameterByName (name, out idx);
- if (par != null)
- return t.parameter_info [idx];
+ Expression expr = t.GetParameterReferenceExpression (name, loc);
+ if (expr != null)
+ return expr;
}
+
return null;
}
+ protected virtual Expression GetParameterReferenceExpression (string name, Location loc)
+ {
+ int idx = parameters.GetParameterIndexByName (name);
+ return idx < 0 ?
+ null : new ParameterReference (parameter_info [idx], loc);
+ }
+
// <summary>
// Returns the "this" instance variable of this block.
// See AddThisVariable() for more information.
// analysis code to ensure that it's been fully initialized before control
// leaves the constructor.
// </summary>
- public LocalInfo AddThisVariable (DeclSpace ds, Location l)
+ public LocalInfo AddThisVariable (TypeContainer ds, Location l)
{
if (this_variable == null) {
this_variable = new LocalInfo (ds, this, l);
set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
}
- public bool IsThisAssigned (EmitContext ec)
- {
- return this_variable == null || this_variable.IsThisAssigned (ec);
+ //
+ // Block has been converted to expression tree
+ //
+ public bool IsExpressionTree {
+ get { return (flags & Flags.IsExpressionTree) != 0; }
}
- public bool ResolveMeta (EmitContext ec, Parameters ip)
+ public bool IsThisAssigned (BlockContext ec)
{
- int errors = Report.Errors;
- int orig_count = parameters.Count;
+ return this_variable == null || this_variable.IsThisAssigned (ec, this);
+ }
- if (top_level_branching != null)
+ public bool Resolve (FlowBranching parent, BlockContext rc, ParametersCompiled ip, IMethodData md)
+ {
+ if (resolved)
return true;
+ resolved = true;
+
+ if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
+ flags |= Flags.IsExpressionTree;
+
+ try {
+ if (!ResolveMeta (rc, ip))
+ return false;
+
+ using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
+ FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
+
+ if (!Resolve (rc))
+ return false;
+
+ unreachable = top_level.End ();
+ }
+ } catch (Exception e) {
+ if (rc.CurrentBlock != null) {
+ rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
+ } else {
+ rc.Report.Error (587, "Internal compiler error: {0}", e.Message);
+ }
+
+ if (Report.DebugFlags > 0)
+ throw;
+ }
+
+ if (rc.ReturnType != TypeManager.void_type && !unreachable) {
+ if (rc.CurrentAnonymousMethod == null) {
+ rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
+ return false;
+ } else if (!rc.CurrentAnonymousMethod.IsIterator) {
+ rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
+ rc.CurrentAnonymousMethod.GetSignatureForError ());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool ResolveMeta (BlockContext ec, ParametersCompiled ip)
+ {
+ int errors = ec.Report.Errors;
+ int orig_count = parameters.Count;
+
if (ip != null)
parameters = ip;
ResolveMeta (ec, offset);
- top_level_branching = ec.StartFlowBranching (this);
-
- return Report.Errors == errors;
+ return ec.Report.Errors == errors;
}
// <summary>
}
}
- public override void EmitMeta (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
- parameters.ResolveVariable ();
+ if (Report.Errors > 0)
+ return;
+#if PRODUCTION
+ try {
+#endif
+ EmitMeta (ec);
+
+ if (ec.HasReturnLabel)
+ ec.ReturnLabel = ec.DefineLabel ();
+
+ base.Emit (ec);
+
+ ec.Mark (EndLocation);
+
+ if (ec.HasReturnLabel)
+ ec.MarkLabel (ec.ReturnLabel);
+
+ 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 != TypeManager.void_type)
+ ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
+ ec.Emit (OpCodes.Ret);
+ }
+ }
+
+#if PRODUCTION
+ } catch (Exception e){
+ Console.WriteLine ("Exception caught by the compiler while emitting:");
+ Console.WriteLine (" Block that caused the problem begin at: " + block.loc);
+
+ Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
+ throw;
+ }
+#endif
+ }
+
+ public override void EmitMeta (EmitContext ec)
+ {
// Avoid declaring an IL variable for this_variable since it is not accessed
// from the generated IL
if (this_variable != null)
if ((ae != null) && (ae.Storey != null))
SymbolWriter.DefineScopeVariable (ae.Storey.ID);
- base.EmitSymbolInfo (ec);
- }
-
- public override void Emit (EmitContext ec)
- {
- base.Emit (ec);
- ec.Mark (EndLocation);
+ base.EmitSymbolInfo (ec);
}
}
public Label GetILLabel (EmitContext ec)
{
if (!il_label_set){
- il_label = ec.ig.DefineLabel ();
+ il_label = ec.DefineLabel ();
il_label_set = true;
}
return il_label;
public Label GetILLabelCode (EmitContext ec)
{
if (!il_label_code_set){
- il_label_code = ec.ig.DefineLabel ();
+ il_label_code = ec.DefineLabel ();
il_label_code_set = true;
}
return il_label_code;
// Resolves the expression, reduces it to a literal if possible
// and then converts it to the requested type.
//
- public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
+ public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
{
Expression e = label.Resolve (ec);
Constant c = e as Constant;
if (c == null){
- Report.Error (150, loc, "A constant value is expected");
+ ec.Report.Error (150, loc, "A constant value is expected");
return false;
}
return true;
}
- public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
+ public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
{
string label;
if (converted == null)
else
label = converted.ToString ();
- Report.SymbolRelatedToPreviousError (collision_with.loc, null);
- Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
+ ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
+ ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
}
public SwitchLabel Clone (CloneContext clonectx)
public class SwitchSection {
// An array of SwitchLabels.
- public readonly ArrayList Labels;
+ public readonly List<SwitchLabel> Labels;
public readonly Block Block;
- public SwitchSection (ArrayList labels, Block block)
+ public SwitchSection (List<SwitchLabel> labels, Block block)
{
Labels = labels;
Block = block;
public SwitchSection Clone (CloneContext clonectx)
{
- ArrayList cloned_labels = new ArrayList ();
+ var cloned_labels = new List<SwitchLabel> ();
foreach (SwitchLabel sl in cloned_labels)
cloned_labels.Add (sl.Clone (clonectx));
}
public class Switch : Statement {
- public ArrayList Sections;
+ public List<SwitchSection> Sections;
public Expression Expr;
/// <summary>
/// Maps constants whose type type SwitchType to their SwitchLabels.
/// </summary>
- public IDictionary Elements;
+ public IDictionary<object, SwitchLabel> Elements;
/// <summary>
/// The governing switch type
/// </summary>
- public Type SwitchType;
+ public TypeSpec SwitchType;
//
// Computed
FieldExpr switch_cache_field;
static int unique_counter;
-#if GMCS_SOURCE
//
- // Nullable Types support for GMCS.
+ // Nullable Types support
//
Nullable.Unwrap unwrap;
protected bool HaveUnwrap {
get { return unwrap != null; }
}
-#else
- protected bool HaveUnwrap {
- get { return false; }
- }
-#endif
//
// The types allowed to be implicitly cast from
// on the governing type
//
- static Type [] allowed_types;
-
- public Switch (Expression e, ArrayList sects, Location l)
+ static TypeSpec [] allowed_types;
+
+ public Switch (Expression e, List<SwitchSection> sects, Location l)
{
Expr = e;
Sections = sects;
// expression that includes any potential conversions to the
// integral types or to string.
//
- Expression SwitchGoverningType (EmitContext ec, Expression expr)
+ Expression SwitchGoverningType (ResolveContext ec, Expression expr)
{
- Type t = expr.Type;
+ TypeSpec t = expr.Type;
if (t == TypeManager.byte_type ||
t == TypeManager.sbyte_type ||
return expr;
if (allowed_types == null){
- allowed_types = new Type [] {
+ allowed_types = new TypeSpec [] {
TypeManager.sbyte_type,
TypeManager.byte_type,
TypeManager.short_type,
// conversions, we have to report an error
//
Expression converted = null;
- foreach (Type tt in allowed_types){
+ foreach (TypeSpec tt in allowed_types){
Expression e;
e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
continue;
if (converted != null){
- Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
+ ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
return null;
}
// It also returns a hashtable with the keys that we will later
// use to compute the switch tables
//
- bool CheckSwitch (EmitContext ec)
+ bool CheckSwitch (ResolveContext ec)
{
bool error = false;
- Elements = Sections.Count > 10 ?
- (IDictionary)new Hashtable () :
- (IDictionary)new ListDictionary ();
+ Elements = new Dictionary<object, SwitchLabel> ();
foreach (SwitchSection ss in Sections){
foreach (SwitchLabel sl in ss.Labels){
if (sl.Label == null){
if (default_section != null){
- sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
+ sl.Error_AlreadyOccurs (ec, SwitchType, (SwitchLabel)default_section.Labels [0]);
error = true;
}
default_section = ss;
try {
Elements.Add (key, sl);
} catch (ArgumentException) {
- sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
+ sl.Error_AlreadyOccurs (ec, SwitchType, Elements [key]);
error = true;
}
}
return !error;
}
- void EmitObjectInteger (ILGenerator ig, object k)
+ void EmitObjectInteger (EmitContext ec, object k)
{
if (k is int)
- IntConstant.EmitInt (ig, (int) k);
+ ec.EmitInt ((int) k);
else if (k is Constant) {
- EmitObjectInteger (ig, ((Constant) k).GetValue ());
+ EmitObjectInteger (ec, ((Constant) k).GetValue ());
}
else if (k is uint)
- IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
+ ec.EmitInt (unchecked ((int) (uint) k));
else if (k is long)
{
if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
{
- IntConstant.EmitInt (ig, (int) (long) k);
- ig.Emit (OpCodes.Conv_I8);
+ ec.EmitInt ((int) (long) k);
+ ec.Emit (OpCodes.Conv_I8);
}
else
- LongConstant.EmitLong (ig, (long) k);
+ ec.EmitLong ((long) k);
}
else if (k is ulong)
{
ulong ul = (ulong) k;
if (ul < (1L<<32))
{
- IntConstant.EmitInt (ig, unchecked ((int) ul));
- ig.Emit (OpCodes.Conv_U8);
+ ec.EmitInt (unchecked ((int) ul));
+ ec.Emit (OpCodes.Conv_U8);
}
else
{
- LongConstant.EmitLong (ig, unchecked ((long) ul));
+ ec.EmitLong (unchecked ((long) ul));
}
}
else if (k is char)
- IntConstant.EmitInt (ig, (int) ((char) k));
+ ec.EmitInt ((int) ((char) k));
else if (k is sbyte)
- IntConstant.EmitInt (ig, (int) ((sbyte) k));
+ ec.EmitInt ((int) ((sbyte) k));
else if (k is byte)
- IntConstant.EmitInt (ig, (int) ((byte) k));
+ ec.EmitInt ((int) ((byte) k));
else if (k is short)
- IntConstant.EmitInt (ig, (int) ((short) k));
+ ec.EmitInt ((int) ((short) k));
else if (k is ushort)
- IntConstant.EmitInt (ig, (int) ((ushort) k));
+ ec.EmitInt ((int) ((ushort) k));
else if (k is bool)
- IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
+ ec.EmitInt (((bool) k) ? 1 : 0);
else
throw new Exception ("Unhandled case");
}
}
public long first;
public long last;
- public ArrayList element_keys = null;
+ public List<object> element_keys;
// how many items are in the bucket
public int Size = 1;
public int Length
Array.Sort (element_keys);
// initialize the block list with one element per key
- ArrayList key_blocks = new ArrayList (element_count);
+ var key_blocks = new List<KeyBlock> (element_count);
foreach (object key in element_keys)
key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
// there's probably a really cool way to do this with a tree...
while (key_blocks.Count > 1)
{
- ArrayList key_blocks_new = new ArrayList ();
+ var key_blocks_new = new List<KeyBlock> ();
current_kb = (KeyBlock) key_blocks [0];
for (int ikb = 1; ikb < key_blocks.Count; ikb++)
{
// initialize the key lists
foreach (KeyBlock kb in key_blocks)
- kb.element_keys = new ArrayList ();
+ kb.element_keys = new List<object> ();
// fill the key lists
int iBlockCurr = 0;
key_blocks.Sort ();
// okay now we can start...
- ILGenerator ig = ec.ig;
- Label lbl_end = ig.DefineLabel (); // at the end ;-)
+ Label lbl_end = ec.DefineLabel (); // at the end ;-)
Label lbl_default = default_target;
Type type_keys = null;
if (element_keys.Length > 0)
type_keys = element_keys [0].GetType (); // used for conversions
- Type compare_type;
+ TypeSpec compare_type;
if (TypeManager.IsEnumType (SwitchType))
- compare_type = TypeManager.GetEnumUnderlyingType (SwitchType);
+ compare_type = EnumSpec.GetUnderlyingType (SwitchType);
else
compare_type = SwitchType;
for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
{
KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
- lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel ();
+ lbl_default = (iBlock == 0) ? default_target : ec.DefineLabel ();
if (kb.Length <= 2)
{
foreach (object key in kb.element_keys) {
val.EmitBranchable (ec, sl.GetILLabel (ec), false);
} else {
val.Emit (ec);
- EmitObjectInteger (ig, key);
- ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+ EmitObjectInteger (ec, key);
+ ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
}
}
}
// check block range (could be > 2^31)
val.Emit (ec);
- EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
- ig.Emit (OpCodes.Blt, lbl_default);
+ EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
+ ec.Emit (OpCodes.Blt, lbl_default);
val.Emit (ec);
- EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
- ig.Emit (OpCodes.Bgt, lbl_default);
+ EmitObjectInteger (ec, System.Convert.ChangeType (kb.last, type_keys));
+ ec.Emit (OpCodes.Bgt, lbl_default);
// normalize range
val.Emit (ec);
if (kb.first != 0)
{
- EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
- ig.Emit (OpCodes.Sub);
+ EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
+ ec.Emit (OpCodes.Sub);
}
- ig.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels!
+ ec.Emit (OpCodes.Conv_I4); // assumes < 2^31 labels!
}
else
{
int first = (int) kb.first;
if (first > 0)
{
- IntConstant.EmitInt (ig, first);
- ig.Emit (OpCodes.Sub);
+ ec.EmitInt (first);
+ ec.Emit (OpCodes.Sub);
}
else if (first < 0)
{
- IntConstant.EmitInt (ig, -first);
- ig.Emit (OpCodes.Add);
+ ec.EmitInt (-first);
+ ec.Emit (OpCodes.Add);
}
}
switch_labels [iJump] = lbl_default;
}
// emit the switch opcode
- ig.Emit (OpCodes.Switch, switch_labels);
+ ec.Emit (OpCodes.Switch, switch_labels);
}
// mark the default for this block
if (iBlock != 0)
- ig.MarkLabel (lbl_default);
+ ec.MarkLabel (lbl_default);
}
// TODO: find the default case and emit it here,
// the last default just goes to the end
if (element_keys.Length > 0)
- ig.Emit (OpCodes.Br, lbl_default);
+ ec.Emit (OpCodes.Br, lbl_default);
// now emit the code for the sections
bool found_default = false;
foreach (SwitchSection ss in Sections) {
foreach (SwitchLabel sl in ss.Labels) {
if (sl.Converted == SwitchLabel.NullStringCase) {
- ig.MarkLabel (null_target);
+ ec.MarkLabel (null_target);
} else if (sl.Label == null) {
- ig.MarkLabel (lbl_default);
+ ec.MarkLabel (lbl_default);
found_default = true;
if (!has_null_case)
- ig.MarkLabel (null_target);
+ ec.MarkLabel (null_target);
}
- ig.MarkLabel (sl.GetILLabel (ec));
- ig.MarkLabel (sl.GetILLabelCode (ec));
+ ec.MarkLabel (sl.GetILLabel (ec));
+ ec.MarkLabel (sl.GetILLabelCode (ec));
}
ss.Block.Emit (ec);
}
if (!found_default) {
- ig.MarkLabel (lbl_default);
+ ec.MarkLabel (lbl_default);
if (!has_null_case) {
- ig.MarkLabel (null_target);
+ ec.MarkLabel (null_target);
}
}
- ig.MarkLabel (lbl_end);
+ ec.MarkLabel (lbl_end);
}
SwitchSection FindSection (SwitchLabel label)
return null;
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- foreach (SwitchSection ss in Sections)
- ss.Block.MutateHoistedGenericType (storey);
- }
-
public static void Reset ()
{
unique_counter = 0;
+ allowed_types = null;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
Expr = Expr.Resolve (ec);
if (Expr == null)
new_expr = SwitchGoverningType (ec, Expr);
-#if GMCS_SOURCE
if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
- unwrap = Nullable.Unwrap.Create (Expr, ec);
+ unwrap = Nullable.Unwrap.Create (Expr, false);
if (unwrap == null)
return false;
new_expr = SwitchGoverningType (ec, unwrap);
}
-#endif
if (new_expr == null){
- Report.Error (151, loc, "A value of an integral type or string expected for switch");
+ ec.Report.Error (151, loc,
+ "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
+ TypeManager.CSharpName (Expr.Type));
return false;
}
SwitchType = new_expr.Type;
if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
- Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
+ ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
return false;
}
Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
- is_constant = new_expr is Constant;
- if (is_constant) {
- object key = ((Constant) new_expr).GetValue ();
- SwitchLabel label = (SwitchLabel) Elements [key];
+ var constant = new_expr as Constant;
+ if (constant != null) {
+ is_constant = true;
+ object key = constant.GetValue ();
+ SwitchLabel label;
+ if (Elements.TryGetValue (key, out label))
+ constant_section = FindSection (label);
- constant_section = FindSection (label);
if (constant_section == null)
constant_section = default_section;
}
return true;
}
- void ResolveStringSwitchMap (EmitContext ec)
+ void ResolveStringSwitchMap (ResolveContext ec)
{
FullNamedExpression string_dictionary_type;
-#if GMCS_SOURCE
- MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
- new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
-
- string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
- new TypeArguments (loc,
- new TypeExpression (TypeManager.string_type, loc),
- new TypeExpression (TypeManager.int32_type, loc)), loc);
-#else
- MemberAccess system_collections_generic = new MemberAccess (
- new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
-
- string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
-#endif
- Field field = new Field (ec.TypeContainer, string_dictionary_type,
+ if (TypeManager.generic_ienumerable_type != null) {
+ MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
+ new TypeArguments (
+ new TypeExpression (TypeManager.string_type, loc),
+ new TypeExpression (TypeManager.int32_type, loc)), loc);
+ } else {
+ MemberAccess system_collections_generic = new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
+ }
+
+ 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);
if (!field.Define ())
return;
- ec.TypeContainer.PartialContainer.AddField (field);
+ ctype.AddField (field);
- ArrayList init = new ArrayList ();
+ var init = new List<Expression> ();
int counter = 0;
Elements.Clear ();
string value = null;
foreach (SwitchSection section in Sections) {
+ int last_count = init.Count;
foreach (SwitchLabel sl in section.Labels) {
- if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
- value = null;
+ if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase)
continue;
- }
value = (string) sl.Converted;
- ArrayList init_args = new ArrayList (2);
+ var init_args = new List<Expression> (2);
init_args.Add (new StringLiteral (value, sl.Location));
init_args.Add (new IntConstant (counter, loc));
init.Add (new CollectionElementInitializer (init_args, loc));
}
- if (value == null)
+ //
+ // Don't add empty sections
+ //
+ if (last_count == init.Count)
continue;
Elements.Add (counter, section.Labels [0]);
++counter;
}
- ArrayList args = new ArrayList (1);
- args.Add (new Argument (new IntConstant (Sections.Count, loc)));
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (new IntConstant (init.Count, loc)));
Expression initializer = new NewInitialize (string_dictionary_type, args,
new CollectionOrObjectInitializers (init, loc), loc);
- switch_cache_field = new FieldExpr (field.FieldBuilder, loc);
+ switch_cache_field = new FieldExpr (field, loc);
string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
}
void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
{
- ILGenerator ig = ec.ig;
- Label l_initialized = ig.DefineLabel ();
+ Label l_initialized = ec.DefineLabel ();
//
// Skip initialization when value is null
//
switch_cache_field.EmitBranchable (ec, l_initialized, true);
string_dictionary.EmitStatement (ec);
- ig.MarkLabel (l_initialized);
+ ec.MarkLabel (l_initialized);
LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
-#if GMCS_SOURCE
- ArrayList get_value_args = new ArrayList (2);
- get_value_args.Add (new Argument (value));
- get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
- Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
- if (get_item == null)
- return;
+ ResolveContext rc = new ResolveContext (ec.MemberContext);
- //
- // A value was not found, go to default case
- //
- get_item.EmitBranchable (ec, default_target, false);
-#else
- ArrayList get_value_args = new ArrayList (1);
- get_value_args.Add (value);
+ if (TypeManager.generic_ienumerable_type != null) {
+ Arguments get_value_args = new Arguments (2);
+ get_value_args.Add (new Argument (value));
+ get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
+ Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
+ if (get_item == null)
+ return;
- Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
- if (get_item == null)
- return;
+ //
+ // A value was not found, go to default case
+ //
+ get_item.EmitBranchable (ec, default_target, false);
+ } else {
+ Arguments get_value_args = new Arguments (1);
+ get_value_args.Add (new Argument (value));
+
+ Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (rc);
+ if (get_item == null)
+ return;
- LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
- get_item_object.EmitAssign (ec, get_item, true, false);
- ec.ig.Emit (OpCodes.Brfalse, default_target);
+ LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
+ get_item_object.EmitAssign (ec, get_item, true, false);
+ ec.Emit (OpCodes.Brfalse, default_target);
- ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
- new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
+ ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
+ new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc);
+
+ get_item_int.EmitStatement (ec);
+ get_item_object.Release (ec);
+ }
- get_item_int.EmitStatement (ec);
- get_item_object.Release (ec);
-#endif
TableSwitchEmit (ec, string_switch_variable);
string_switch_variable.Release (ec);
}
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
- default_target = ig.DefineLabel ();
- null_target = ig.DefineLabel ();
+ default_target = ec.DefineLabel ();
+ null_target = ec.DefineLabel ();
// Store variable for comparission purposes
// TODO: Don't duplicate non-captured VariableReference
LocalTemporary value;
if (HaveUnwrap) {
value = new LocalTemporary (SwitchType);
-#if GMCS_SOURCE
unwrap.EmitCheck (ec);
- ig.Emit (OpCodes.Brfalse, null_target);
+ ec.Emit (OpCodes.Brfalse, null_target);
new_expr.Emit (ec);
value.Store (ec);
-#endif
} else if (!is_constant) {
value = new LocalTemporary (SwitchType);
new_expr.Emit (ec);
Label old_end = ec.LoopEnd;
Switch old_switch = ec.Switch;
- ec.LoopEnd = ig.DefineLabel ();
+ ec.LoopEnd = ec.DefineLabel ();
ec.Switch = this;
// Emit Code.
value.Release (ec);
// Restore context state.
- ig.MarkLabel (ec.LoopEnd);
+ ec.MarkLabel (ec.LoopEnd);
//
// Restore the previous context
Switch target = (Switch) t;
target.Expr = Expr.Clone (clonectx);
- target.Sections = new ArrayList ();
+ target.Sections = new List<SwitchSection> ();
foreach (SwitchSection ss in Sections){
target.Sections.Add (ss.Clone (clonectx));
}
{
if (!prepared) {
prepared = true;
- resume_point = ec.ig.DefineLabel ();
+ resume_point = ec.DefineLabel ();
}
return resume_point;
}
public abstract class ExceptionStatement : ResumableStatement
{
bool code_follows;
+ Iterator iter;
+ List<ResumableStatement> resume_points;
+ int first_resume_pc;
protected abstract void EmitPreTryBody (EmitContext ec);
protected abstract void EmitTryBody (EmitContext ec);
protected sealed override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
EmitPreTryBody (ec);
if (resume_points != null) {
- IntConstant.EmitInt (ig, (int) Iterator.State.Running);
- ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
+ ec.EmitInt ((int) Iterator.State.Running);
+ ec.Emit (OpCodes.Stloc, iter.CurrentPC);
}
- ig.BeginExceptionBlock ();
+ ec.BeginExceptionBlock ();
if (resume_points != null) {
- ig.MarkLabel (resume_point);
+ ec.MarkLabel (resume_point);
// For normal control flow, we want to fall-through the Switch
// So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
- ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
- IntConstant.EmitInt (ig, first_resume_pc);
- ig.Emit (OpCodes.Sub);
+ ec.Emit (OpCodes.Ldloc, iter.CurrentPC);
+ ec.EmitInt (first_resume_pc);
+ ec.Emit (OpCodes.Sub);
Label [] labels = new Label [resume_points.Count];
for (int i = 0; i < resume_points.Count; ++i)
labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
- ig.Emit (OpCodes.Switch, labels);
+ ec.Emit (OpCodes.Switch, labels);
}
EmitTryBody (ec);
- ig.BeginFinallyBlock ();
+ ec.BeginFinallyBlock ();
- Label start_finally = ec.ig.DefineLabel ();
+ Label start_finally = ec.DefineLabel ();
if (resume_points != null) {
- ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
- ig.Emit (OpCodes.Brfalse_S, start_finally);
- ig.Emit (OpCodes.Endfinally);
+ ec.Emit (OpCodes.Ldloc, iter.SkipFinally);
+ ec.Emit (OpCodes.Brfalse_S, start_finally);
+ ec.Emit (OpCodes.Endfinally);
}
- ig.MarkLabel (start_finally);
+ ec.MarkLabel (start_finally);
EmitFinallyBody (ec);
- ig.EndExceptionBlock ();
+ ec.EndExceptionBlock ();
}
public void SomeCodeFollows ()
code_follows = true;
}
- protected void ResolveReachability (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
// System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
// So, ensure there's some IL code after this statement.
if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
ec.NeedReturnLabel ();
+ iter = ec.CurrentIterator;
+ return true;
}
- ArrayList resume_points;
- int first_resume_pc;
public void AddResumePoint (ResumableStatement stmt, int pc)
{
if (resume_points == null) {
- resume_points = new ArrayList ();
+ resume_points = new List<ResumableStatement> ();
first_resume_pc = pc;
}
{
if (!prepared_for_dispose) {
prepared_for_dispose = true;
- dispose_try_block = ec.ig.DefineLabel ();
+ dispose_try_block = ec.DefineLabel ();
}
return dispose_try_block;
}
emitted_dispose = true;
- ILGenerator ig = ec.ig;
-
- Label end_of_try = ig.DefineLabel ();
+ Label end_of_try = ec.DefineLabel ();
// Ensure that the only way we can get into this code is through a dispatcher
if (have_dispatcher)
- ig.Emit (OpCodes.Br, end);
+ ec.Emit (OpCodes.Br, end);
- ig.BeginExceptionBlock ();
+ ec.BeginExceptionBlock ();
- ig.MarkLabel (dispose_try_block);
+ ec.MarkLabel (dispose_try_block);
Label [] labels = null;
for (int i = 0; i < resume_points.Count; ++i) {
if (emit_dispatcher) {
//SymbolWriter.StartIteratorDispatcher (ec.ig);
- ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
- IntConstant.EmitInt (ig, first_resume_pc);
- ig.Emit (OpCodes.Sub);
- ig.Emit (OpCodes.Switch, labels);
+ ec.Emit (OpCodes.Ldloc, iterator.CurrentPC);
+ ec.EmitInt (first_resume_pc);
+ ec.Emit (OpCodes.Sub);
+ ec.Emit (OpCodes.Switch, labels);
//SymbolWriter.EndIteratorDispatcher (ec.ig);
}
s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
}
- ig.MarkLabel (end_of_try);
+ ec.MarkLabel (end_of_try);
- ig.BeginFinallyBlock ();
+ ec.BeginFinallyBlock ();
EmitFinallyBody (ec);
- ig.EndExceptionBlock ();
+ ec.EndExceptionBlock ();
}
}
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
expr = expr.Resolve (ec);
if (expr == null)
return false;
- if (expr.Type.IsValueType){
- Report.Error (185, loc,
+ if (!TypeManager.IsReferenceType (expr.Type)){
+ ec.Report.Error (185, loc,
"`{0}' is not a reference type as required by the lock statement",
TypeManager.CSharpName (expr.Type));
return false;
bool ok = Statement.Resolve (ec);
ec.EndFlowBranching ();
- ResolveReachability (ec);
+ ok &= base.Resolve (ec);
// Avoid creating libraries that reference the internal
// mcs NullType:
- Type t = expr.Type;
+ TypeSpec t = expr.Type;
if (t == TypeManager.null_type)
t = TypeManager.object_type;
temp.Resolve (ec);
if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
- Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
+ TypeSpec monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
monitor_type, "Enter", loc, TypeManager.object_type);
TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
protected override void EmitPreTryBody (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
temp.EmitAssign (ec, expr);
temp.Emit (ec);
- ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+ ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
}
protected override void EmitTryBody (EmitContext ec)
protected override void EmitFinallyBody (EmitContext ec)
{
temp.Emit (ec);
- ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
+ ec.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr.MutateHoistedGenericType (storey);
- temp.MutateHoistedGenericType (storey);
- Statement.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Lock target = (Lock) t;
b.Unchecked = true;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
Block.Emit (ec);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- Block.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Unchecked target = (Unchecked) t;
b.Unchecked = false;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
- return Block.Resolve (ec);
+ using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
+ return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
Block.Emit (ec);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- Block.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Checked target = (Checked) t;
{
Block = b;
Block.Unsafe = true;
+ loc = b.StartLocation;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- using (ec.With (EmitContext.Flags.InUnsafe, true))
+ if (ec.CurrentIterator != null)
+ ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
+
+ using (ec.Set (ResolveContext.Options.UnsafeScope))
return Block.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
{
- using (ec.With (EmitContext.Flags.InUnsafe, true))
- Block.Emit (ec);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- Block.MutateHoistedGenericType (storey);
+ Block.Emit (ec);
}
protected override void CloneTo (CloneContext clonectx, Statement t)
//
public class Fixed : Statement {
Expression type;
- ArrayList declarators;
+ List<KeyValuePair<LocalInfo, Expression>> declarators;
Statement statement;
- Type expr_type;
+ TypeSpec expr_type;
Emitter[] data;
bool has_ret;
public override void EmitExit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldc_I4_0);
- ec.ig.Emit (OpCodes.Conv_U);
+ ec.Emit (OpCodes.Ldc_I4_0);
+ ec.Emit (OpCodes.Conv_U);
vi.EmitAssign (ec);
}
}
- class StringEmitter : Emitter {
- class StringPtr : Expression
- {
- LocalBuilder b;
-
- public StringPtr (LocalBuilder b, Location l)
- {
- this.b = b;
- eclass = ExprClass.Value;
- type = TypeManager.char_ptr_type;
- loc = l;
- }
-
- public override Expression CreateExpressionTree (EmitContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- // This should never be invoked, we are born in fully
- // initialized state.
-
- return this;
- }
+ class StringEmitter : Emitter
+ {
+ LocalInfo pinned_string;
- public override void Emit (EmitContext ec)
- {
- if (TypeManager.int_get_offset_to_string_data == null) {
- // TODO: Move to resolve !!
- TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
- TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
- }
+ public StringEmitter (Expression expr, LocalInfo li, Location loc):
+ base (expr, li)
+ {
+ pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
+ pinned_string.Pinned = true;
+ }
- ILGenerator ig = ec.ig;
+ public StringEmitter Resolve (ResolveContext rc)
+ {
+ pinned_string.Resolve (rc);
- ig.Emit (OpCodes.Ldloc, b);
- ig.Emit (OpCodes.Conv_I);
- ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
- ig.Emit (OpCodes.Add);
+ if (TypeManager.int_get_offset_to_string_data == null) {
+ TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
+ TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
}
- }
-
- LocalBuilder pinned_string;
- Location loc;
- public StringEmitter (Expression expr, LocalInfo li, Location loc):
- base (expr, li)
- {
- this.loc = loc;
+ return this;
}
public override void Emit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
-
+ pinned_string.ResolveVariable (ec);
+
converted.Emit (ec);
- ig.Emit (OpCodes.Stloc, pinned_string);
+ pinned_string.EmitAssign (ec);
- Expression sptr = new StringPtr (pinned_string, loc);
- converted = Convert.ImplicitConversionRequired (
- ec, sptr, vi.VariableType, loc);
-
- if (converted == null)
- return;
+ // TODO: Should use Binary::Add
+ pinned_string.Emit (ec);
+ ec.Emit (OpCodes.Conv_I);
- converted.Emit (ec);
+ PropertyExpr pe = new PropertyExpr (TypeManager.int_get_offset_to_string_data, pinned_string.Location);
+ //pe.InstanceExpression = pinned_string;
+ pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
+
+ ec.Emit (OpCodes.Add);
vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldnull);
- ec.ig.Emit (OpCodes.Stloc, pinned_string);
+ ec.Emit (OpCodes.Ldnull);
+ pinned_string.EmitAssign (ec);
}
}
- public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
+ public Fixed (Expression type, List<KeyValuePair<LocalInfo, Expression>> decls, Statement stmt, Location l)
{
this.type = type;
declarators = decls;
get { return statement; }
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- if (!ec.InUnsafe){
- Expression.UnsafeError (loc);
+ if (!ec.IsUnsafe){
+ Expression.UnsafeError (ec, loc);
return false;
}
TypeExpr texpr = type.ResolveAsContextualType (ec, false);
if (texpr == null) {
if (type is VarExpr)
- Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
+ ec.Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
return false;
}
data = new Emitter [declarators.Count];
if (!expr_type.IsPointer){
- Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
+ ec.Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
return false;
}
int i = 0;
- foreach (Pair p in declarators){
- LocalInfo vi = (LocalInfo) p.First;
- Expression e = (Expression) p.Second;
+ foreach (var p in declarators){
+ LocalInfo vi = p.Key;
+ Expression e = p.Value;
vi.VariableInfo.SetAssigned (ec);
vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
//
if (e is Cast){
- Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
+ ec.Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
return false;
}
- ec.InFixedInitializer = true;
- e = e.Resolve (ec);
- ec.InFixedInitializer = false;
+ using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
+ e = e.Resolve (ec);
+ }
+
if (e == null)
return false;
// Case 2: Array
//
if (e.Type.IsArray){
- Type array_type = TypeManager.GetElementType (e.Type);
+ TypeSpec array_type = TypeManager.GetElementType (e.Type);
//
// Provided that array_type is unmanaged,
//
- if (!TypeManager.VerifyUnManaged (array_type, loc))
+ if (!TypeManager.VerifyUnmanaged (ec.Compiler, array_type, loc))
return false;
//
//
// fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
//
- converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
- new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
- new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
+ converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
+ new Binary (Binary.Operator.Equality, e, new NullLiteral (loc), loc),
+ new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc), loc), loc)),
new NullPointer (loc),
converted);
// Case 3: string
//
if (e.Type == TypeManager.string_type){
- data [i] = new StringEmitter (e, vi, loc);
+ data [i] = new StringEmitter (e, vi, loc).Resolve (ec);
i++;
continue;
}
}
if (data [i++] == null)
- Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
+ ec.Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
}
}
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- // Fixed statement cannot be used inside anonymous methods or lambdas
- throw new NotSupportedException ();
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Fixed target = (Fixed) t;
target.type = type.Clone (clonectx);
- target.declarators = new ArrayList (declarators.Count);
- foreach (Pair p in declarators) {
- LocalInfo vi = (LocalInfo) p.First;
- Expression e = (Expression) p.Second;
-
- target.declarators.Add (
- new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));
+ target.declarators = new List<KeyValuePair<LocalInfo, Expression>> (declarators.Count);
+ foreach (var p in declarators) {
+ target.declarators.Add (new KeyValuePair<LocalInfo, Expression> (
+ clonectx.LookupVariable (p.Key), p.Value.Clone (clonectx)));
}
target.statement = statement.Clone (clonectx);
public Block VarBlock;
Expression type_expr;
- Type type;
+ TypeSpec type;
public Catch (Expression type, string name, Block block, Block var_block, Location l)
{
loc = l;
}
- public Type CatchType {
+ public TypeSpec CatchType {
get {
return type;
}
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
if (CatchType != null)
- ig.BeginCatchBlock (CatchType);
+ ec.BeginCatchBlock (CatchType);
else
- ig.BeginCatchBlock (TypeManager.object_type);
+ ec.BeginCatchBlock (TypeManager.object_type);
if (VarBlock != null)
VarBlock.Emit (ec);
if (Name != null) {
// TODO: Move to resolve
LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
- lvr.Resolve (ec);
+ lvr.Resolve (new ResolveContext (ec.MemberContext));
+
+ // Only to make verifier happy
+ if (TypeManager.IsGenericParameter (lvr.Type))
+ ec.Emit (OpCodes.Unbox_Any, lvr.Type);
Expression source;
if (lvr.IsHoisted) {
lvr.EmitAssign (ec, source, false, false);
} else
- ig.Emit (OpCodes.Pop);
+ ec.Emit (OpCodes.Pop);
Block.Emit (ec);
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
- using (ec.With (EmitContext.Flags.InCatch, true)) {
+ using (ec.With (ResolveContext.Options.CatchScope, true)) {
if (type_expr != null) {
TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
if (te == null)
type = te.Type;
if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
- Error (155, "The type caught or thrown must be derived from System.Exception");
+ ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
return false;
}
} else
}
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- if (type != null)
- type = storey.MutateType (type);
- if (VarBlock != null)
- VarBlock.MutateHoistedGenericType (storey);
- Block.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Catch target = (Catch) t;
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
if (ok)
ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
- using (ec.With (EmitContext.Flags.InFinally, true)) {
+ using (ec.With (ResolveContext.Options.FinallyScope, true)) {
if (!fini.Resolve (ec))
ok = false;
}
ec.EndFlowBranching ();
- ResolveReachability (ec);
+ ok &= base.Resolve (ec);
return ok;
}
fini.Emit (ec);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- stmt.MutateHoistedGenericType (storey);
- fini.MutateHoistedGenericType (storey);
- }
-
protected override void CloneTo (CloneContext clonectx, Statement t)
{
TryFinally target = (TryFinally) t;
public class TryCatch : Statement {
public Block Block;
- public ArrayList Specific;
+ public List<Catch> Specific;
public Catch General;
bool inside_try_finally, code_follows;
- public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
+ public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
{
this.Block = block;
this.Specific = catch_clauses;
- this.General = null;
this.inside_try_finally = inside_try_finally;
- for (int i = 0; i < catch_clauses.Count; ++i) {
- Catch c = (Catch) catch_clauses [i];
- if (c.IsGeneral) {
- if (i != catch_clauses.Count - 1)
- Report.Error (1017, c.loc, "Try statement already has an empty catch block");
- this.General = c;
- catch_clauses.RemoveAt (i);
- i--;
- }
+ Catch c = catch_clauses [0];
+ if (c.IsGeneral) {
+ this.General = c;
+ catch_clauses.RemoveAt (0);
}
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
if (!Block.Resolve (ec))
ok = false;
- Type[] prev_catches = new Type [Specific.Count];
+ TypeSpec[] prev_catches = new TypeSpec [Specific.Count];
int last_index = 0;
foreach (Catch c in Specific){
ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
vi.VariableInfo = null;
}
- if (!c.Resolve (ec))
+ if (!c.Resolve (ec)) {
ok = false;
+ continue;
+ }
- Type resolved_type = c.CatchType;
+ TypeSpec resolved_type = c.CatchType;
for (int ii = 0; ii < last_index; ++ii) {
if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
- Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
+ 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;
}
}
if (General != null) {
if (CodeGen.Assembly.WrapNonExceptionThrows) {
foreach (Catch c in Specific){
- if (c.CatchType == TypeManager.exception_type) {
- 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 (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
+ 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'");
}
}
}
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
if (!inside_try_finally)
- ig.BeginExceptionBlock ();
+ ec.BeginExceptionBlock ();
Block.Emit (ec);
General.Emit (ec);
if (!inside_try_finally)
- ig.EndExceptionBlock ();
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- Block.MutateHoistedGenericType (storey);
-
- if (General != null)
- General.MutateHoistedGenericType (storey);
- if (Specific != null) {
- foreach (Catch c in Specific)
- c.MutateHoistedGenericType (storey);
- }
+ ec.EndExceptionBlock ();
}
protected override void CloneTo (CloneContext clonectx, Statement t)
if (General != null)
target.General = (Catch) General.Clone (clonectx);
if (Specific != null){
- target.Specific = new ArrayList ();
+ target.Specific = new List<Catch> ();
foreach (Catch c in Specific)
- target.Specific.Add (c.Clone (clonectx));
+ target.Specific.Add ((Catch) c.Clone (clonectx));
}
}
}
+ // FIXME: Why is it almost exact copy of Using ??
public class UsingTemporary : ExceptionStatement {
TemporaryVariable local_copy;
public Statement Statement;
Expression expr;
- Type expr_type;
+ TypeSpec expr_type;
public UsingTemporary (Expression expr, Statement stmt, Location l)
{
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
expr = expr.Resolve (ec);
if (expr == null)
expr_type = expr.Type;
- if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
- if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
- Using.Error_IsNotConvertibleToIDisposable (expr);
+ if (!expr_type.ImplementsInterface (TypeManager.idisposable_type) &&
+ Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
+ if (expr_type != InternalType.Dynamic) {
+ Using.Error_IsNotConvertibleToIDisposable (ec, expr);
return false;
}
+
+ expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.idisposable_type, loc);
+ expr_type = expr.Type;
}
local_copy = new TemporaryVariable (expr_type, loc);
ec.EndFlowBranching ();
- ResolveReachability (ec);
+ ok &= base.Resolve (ec);
if (TypeManager.void_dispose_void == null) {
TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
- TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+ TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
}
return ok;
protected override void EmitFinallyBody (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- if (!expr_type.IsValueType) {
- Label skip = ig.DefineLabel ();
+ if (!TypeManager.IsStruct (expr_type)) {
+ Label skip = ec.DefineLabel ();
local_copy.Emit (ec);
- ig.Emit (OpCodes.Brfalse, skip);
+ ec.Emit (OpCodes.Brfalse, skip);
local_copy.Emit (ec);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- ig.MarkLabel (skip);
+ ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
+ ec.MarkLabel (skip);
return;
}
- Expression ml = Expression.MemberLookup (
- ec.ContainerType, TypeManager.idisposable_type, expr_type,
- "Dispose", Location.Null);
+ MethodSpec ms = MemberCache.FindMember (expr_type,
+ MemberFilter.Method ("Dispose", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.void_type),
+ BindingRestriction.InstanceOnly) as MethodSpec;
- if (!(ml is MethodGroupExpr)) {
+ if (ms == null) {
local_copy.Emit (ec);
- ig.Emit (OpCodes.Box, expr_type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- return;
- }
-
- MethodInfo mi = null;
-
- foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
- if (TypeManager.GetParameterData (mk).Count == 0) {
- mi = mk;
- break;
- }
- }
-
- if (mi == null) {
- Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
+ ec.Emit (OpCodes.Box, expr_type);
+ ec.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
return;
}
local_copy.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- expr_type = storey.MutateType (expr_type);
- local_copy.MutateHoistedGenericType (storey);
- Statement.MutateHoistedGenericType (storey);
+ ec.Emit (OpCodes.Call, ms);
}
protected override void CloneTo (CloneContext clonectx, Statement t)
Expression var;
Expression init;
- Expression converted_var;
ExpressionStatement assign;
public Using (Expression var, Expression init, Statement stmt, Location l)
loc = l;
}
- bool ResolveVariable (EmitContext ec)
- {
- ExpressionStatement a = new SimpleAssign (var, init, loc);
- a = a.ResolveStatement (ec);
- if (a == null)
- return false;
-
- assign = a;
-
- if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
- converted_var = var;
- return true;
- }
-
- Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
- if (e == null) {
- Error_IsNotConvertibleToIDisposable (var);
- return false;
- }
-
- converted_var = e;
-
- return true;
- }
-
- static public void Error_IsNotConvertibleToIDisposable (Expression expr)
+ static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, Expression expr)
{
- Report.SymbolRelatedToPreviousError (expr.Type);
- Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
- expr.GetSignatureForError ());
+ ec.Report.SymbolRelatedToPreviousError (expr.Type);
+ ec.Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+ TypeManager.CSharpName (expr.Type));
}
protected override void EmitPreTryBody (EmitContext ec)
protected override void EmitFinallyBody (EmitContext ec)
{
- ILGenerator ig = ec.ig;
+ Label skip = ec.DefineLabel ();
- if (!var.Type.IsValueType) {
- Label skip = ig.DefineLabel ();
+ bool emit_null_check = !TypeManager.IsValueType (var.Type);
+ if (emit_null_check) {
var.Emit (ec);
- ig.Emit (OpCodes.Brfalse, skip);
- converted_var.Emit (ec);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- ig.MarkLabel (skip);
- } else {
- Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
-
- if (!(ml is MethodGroupExpr)) {
- var.Emit (ec);
- ig.Emit (OpCodes.Box, var.Type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- } else {
- MethodInfo mi = null;
-
- foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
- if (TypeManager.GetParameterData (mk).Count == 0) {
- mi = mk;
- break;
- }
- }
-
- if (mi == null) {
- Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
- return;
- }
-
- IMemoryLocation mloc = (IMemoryLocation) var;
-
- mloc.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- }
+ ec.Emit (OpCodes.Brfalse, skip);
}
- }
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- assign.MutateHoistedGenericType (storey);
- var.MutateHoistedGenericType (storey);
- stmt.MutateHoistedGenericType (storey);
+ Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc);
+
+ if (emit_null_check)
+ ec.MarkLabel (skip);
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
if (!ResolveVariable (ec))
return false;
ec.EndFlowBranching ();
- ResolveReachability (ec);
+ ok &= base.Resolve (ec);
if (TypeManager.void_dispose_void == null) {
TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
- TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+ TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
}
return ok;
}
+ bool ResolveVariable (BlockContext ec)
+ {
+ assign = new SimpleAssign (var, init, loc);
+ assign = assign.ResolveStatement (ec);
+ if (assign == null)
+ return false;
+
+ if (assign.Type == TypeManager.idisposable_type || assign.Type.ImplementsInterface (TypeManager.idisposable_type)) {
+ return true;
+ }
+
+ Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
+ if (e == null) {
+ if (assign.Type == InternalType.Dynamic) {
+ e = Convert.ImplicitConversionRequired (ec, assign, TypeManager.idisposable_type, loc);
+ var = new TemporaryVariable (e.Type, loc);
+ assign = new SimpleAssign (var, e, loc).ResolveStatement (ec);
+ return true;
+ }
+
+ Error_IsNotConvertibleToIDisposable (ec, var);
+ return false;
+ }
+
+ throw new NotImplementedException ("covariance?");
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Using target = (Using) t;
{
}
- public void ResolveIncrement (EmitContext ec)
+ public void ResolveIncrement (BlockContext ec)
{
increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
increment.Resolve (ec);
throw new NotImplementedException ();
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
copy = new TemporaryVariable (for_each.expr.Type, loc);
copy.Resolve (ec);
int rank = length_exprs.Length;
- ArrayList list = new ArrayList (rank);
+ Arguments list = new Arguments (rank);
for (int i = 0; i < rank; i++) {
counter [i] = new ArrayCounter (loc);
counter [i].ResolveIncrement (ec);
lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
lengths [i].Resolve (ec);
- ArrayList args = new ArrayList (1);
+ Arguments args = new Arguments (1);
args.Add (new Argument (new IntConstant (i, loc)));
length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
}
- list.Add (counter [i]);
+ list.Add (new Argument (counter [i]));
}
access = new ElementAccess (copy, list).Resolve (ec);
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling ();
- for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
+ for_each.variable = for_each.variable.ResolveLValue (ec, conv);
if (for_each.variable == null)
ok = false;
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
copy.EmitAssign (ec, for_each.expr);
int rank = length_exprs.Length;
Label[] loop = new Label [rank];
for (int i = 0; i < rank; i++) {
- test [i] = ig.DefineLabel ();
- loop [i] = ig.DefineLabel ();
+ test [i] = ec.DefineLabel ();
+ loop [i] = ec.DefineLabel ();
if (lengths != null)
lengths [i].EmitAssign (ec, length_exprs [i]);
for (int i = 0; i < rank; i++) {
counter [i].EmitAssign (ec, zero);
- ig.Emit (OpCodes.Br, test [i]);
- ig.MarkLabel (loop [i]);
+ ec.Emit (OpCodes.Br, test [i]);
+ ec.MarkLabel (loop [i]);
}
((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
statement.Emit (ec);
- ig.MarkLabel (ec.LoopBegin);
+ ec.MarkLabel (ec.LoopBegin);
for (int i = rank - 1; i >= 0; i--){
counter [i].EmitIncrement (ec);
- ig.MarkLabel (test [i]);
+ ec.MarkLabel (test [i]);
counter [i].Emit (ec);
if (lengths != null)
else
length_exprs [i].Emit (ec);
- ig.Emit (OpCodes.Blt, loop [i]);
+ ec.Emit (OpCodes.Blt, loop [i]);
}
- ig.MarkLabel (ec.LoopEnd);
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- for_each.expr.MutateHoistedGenericType (storey);
-
- copy.MutateHoistedGenericType (storey);
- conv.MutateHoistedGenericType (storey);
- statement.MutateHoistedGenericType (storey);
-
- for (int i = 0; i < counter.Length; i++) {
- counter [i].MutateHoistedGenericType (storey);
- if (lengths != null)
- lengths [i].MutateHoistedGenericType (storey);
- }
+ ec.MarkLabel (ec.LoopEnd);
}
}
{
class CollectionForeachStatement : Statement
{
- Type type;
+ TypeSpec type;
Expression variable, current, conv;
Statement statement;
Assign assign;
- public CollectionForeachStatement (Type type, Expression variable,
+ public CollectionForeachStatement (TypeSpec type, Expression variable,
Expression current, Statement statement,
Location loc)
{
throw new NotImplementedException ();
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
current = current.Resolve (ec);
if (current == null)
assign.EmitStatement (ec);
statement.Emit (ec);
}
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- assign.MutateHoistedGenericType (storey);
- statement.MutateHoistedGenericType (storey);
- }
}
Expression variable, expr;
MethodGroupExpr get_enumerator;
PropertyExpr get_current;
- MethodInfo move_next;
+ MethodSpec move_next;
Expression var_type;
- Type enumerator_type;
+ TypeSpec enumerator_type;
bool enumerator_found;
public CollectionForeach (Expression var_type, Expression var,
throw new NotImplementedException ();
}
- bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
+ bool GetEnumeratorFilter (ResolveContext ec, MethodSpec mi)
{
- Type return_type = mi.ReturnType;
+ TypeSpec return_type = mi.ReturnType;
//
// Ok, we can access it, now make sure that we can do something
//
if (return_type == TypeManager.ienumerator_type ||
- TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
- (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+ return_type.ImplementsInterface (TypeManager.ienumerator_type)) {
//
// If it is not an interface, lets try to find the methods ourselves.
// For example, if we have:
if (TypeManager.bool_movenext_void == null) {
TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
- TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
+ TypeManager.ienumerator_type, "MoveNext", loc, TypeSpec.EmptyTypes);
}
if (TypeManager.ienumerator_getcurrent == null) {
TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
}
-#if GMCS_SOURCE
//
// Prefer a generic enumerator over a non-generic one.
//
- if (return_type.IsInterface && return_type.IsGenericType) {
+ if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
enumerator_type = return_type;
if (!FetchGetCurrent (ec, return_type))
- get_current = new PropertyExpr (
- ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+ get_current = new PropertyExpr (TypeManager.ienumerator_getcurrent, loc);
if (!FetchMoveNext (return_type))
move_next = TypeManager.bool_movenext_void;
return true;
}
-#endif
if (return_type.IsInterface ||
!FetchMoveNext (return_type) ||
!FetchGetCurrent (ec, return_type)) {
enumerator_type = return_type;
move_next = TypeManager.bool_movenext_void;
- get_current = new PropertyExpr (
- ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
+ get_current = new PropertyExpr (TypeManager.ienumerator_getcurrent, loc);
return true;
}
} else {
//
if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
- Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
+ ec.Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
return false;
}
//
// Retrieves a `public bool MoveNext ()' method from the Type `t'
//
- bool FetchMoveNext (Type t)
+ bool FetchMoveNext (TypeSpec t)
{
- MemberList move_next_list;
-
- move_next_list = TypeContainer.FindMembers (
- t, MemberTypes.Method,
- BindingFlags.Public | BindingFlags.Instance,
- Type.FilterName, "MoveNext");
- if (move_next_list.Count == 0)
- return false;
-
- foreach (MemberInfo m in move_next_list){
- MethodInfo mi = (MethodInfo) m;
-
- if ((TypeManager.GetParameterData (mi).Count == 0) &&
- TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) {
- move_next = mi;
- return true;
- }
- }
+ move_next = MemberCache.FindMember (t,
+ MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.bool_type),
+ BindingRestriction.InstanceOnly) as MethodSpec;
- return false;
+ return move_next != null && (move_next.Modifiers & Modifiers.PUBLIC) != 0;
}
//
// Retrieves a `public T get_Current ()' method from the Type `t'
//
- bool FetchGetCurrent (EmitContext ec, Type t)
+ bool FetchGetCurrent (ResolveContext ec, TypeSpec t)
{
- PropertyExpr pe = Expression.MemberLookup (
- ec.ContainerType, t, "Current", MemberTypes.Property,
- Expression.AllBindingFlags, loc) as PropertyExpr;
+ PropertyExpr pe = Expression.MemberLookup (ec.Compiler,
+ ec.CurrentType, t, "Current", 0, MemberKind.Property,
+ BindingRestriction.AccessibleOnly, loc) as PropertyExpr;
if (pe == null)
return false;
return true;
}
- //
- // Retrieves a `public void Dispose ()' method from the Type `t'
- //
- static MethodInfo FetchMethodDispose (Type t)
- {
- MemberList dispose_list;
-
- dispose_list = TypeContainer.FindMembers (
- t, MemberTypes.Method,
- BindingFlags.Public | BindingFlags.Instance,
- Type.FilterName, "Dispose");
- if (dispose_list.Count == 0)
- return null;
-
- foreach (MemberInfo m in dispose_list){
- MethodInfo mi = (MethodInfo) m;
-
- if (TypeManager.GetParameterData (mi).Count == 0){
- if (mi.ReturnType == TypeManager.void_type)
- return mi;
- }
- }
- return null;
- }
-
- void Error_Enumerator ()
+ void Error_Enumerator (BlockContext ec)
{
if (enumerator_found) {
return;
}
- Report.Error (1579, loc,
+ ec.Report.Error (1579, loc,
"foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
TypeManager.CSharpName (expr.Type));
}
- bool IsOverride (MethodInfo m)
+ bool TryType (ResolveContext ec, TypeSpec t)
{
- m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
-
- if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0))
- return false;
- if (m is MethodBuilder)
- return true;
+ var mg = Expression.MemberLookup (ec.Compiler, ec.CurrentType, null, t, "GetEnumerator", 0,
+ MemberKind.Method, BindingRestriction.NoOverrides | BindingRestriction.InstanceOnly, loc) as MethodGroupExpr;
- MethodInfo base_method = m.GetBaseDefinition ();
- return base_method != m;
- }
-
- bool TryType (EmitContext ec, Type t)
- {
- MethodGroupExpr mg = Expression.MemberLookup (
- ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
- Expression.AllBindingFlags, loc) as MethodGroupExpr;
if (mg == null)
return false;
- MethodInfo result = null;
- MethodInfo tmp_move_next = null;
+ MethodSpec result = null;
+ MethodSpec tmp_move_next = null;
PropertyExpr tmp_get_cur = null;
- Type tmp_enumerator_type = enumerator_type;
- foreach (MethodInfo mi in mg.Methods) {
- if (TypeManager.GetParameterData (mi).Count != 0)
+ TypeSpec tmp_enumerator_type = enumerator_type;
+ foreach (MethodSpec mi in mg.Methods) {
+ if (!mi.Parameters.IsEmpty)
continue;
// Check whether GetEnumerator is public
- if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
- continue;
-
- if (IsOverride (mi))
+ if ((mi.Modifiers & Modifiers.AccessibilityMask) != Modifiers.PUBLIC)
continue;
enumerator_found = true;
if (!TypeManager.IsGenericType (mi.ReturnType))
continue;
- MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
- Report.SymbolRelatedToPreviousError (t);
- Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
- "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
- TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
+ ec.Report.SymbolRelatedToPreviousError (t);
+ ec.Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
+ "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+ TypeManager.CSharpName (t), TypeManager.generic_ienumerable_type.GetSignatureForError ());
return false;
}
// Always prefer generics enumerators
if (!TypeManager.IsGenericType (mi.ReturnType)) {
- if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
- TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
+ if (mi.DeclaringType.ImplementsInterface (result.DeclaringType) ||
+ result.DeclaringType.ImplementsInterface (mi.DeclaringType))
continue;
- Report.SymbolRelatedToPreviousError (result);
- Report.SymbolRelatedToPreviousError (mi);
- Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
- TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
+ ec.Report.SymbolRelatedToPreviousError (result);
+ ec.Report.SymbolRelatedToPreviousError (mi);
+ ec.Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
+ TypeManager.CSharpName (t), "enumerable", result.GetSignatureForError (), mi.GetSignatureForError ());
return false;
}
}
move_next = tmp_move_next;
get_current = tmp_get_cur;
enumerator_type = tmp_enumerator_type;
- MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
- get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);
+ get_enumerator = new MethodGroupExpr (result, enumerator_type, loc);
if (t != expr.Type) {
expr = Convert.ExplicitConversion (
}
return false;
- }
+ }
- bool ProbeCollectionType (EmitContext ec, Type t)
+ bool ProbeCollectionType (ResolveContext ec, TypeSpec t)
{
- int errors = Report.Errors;
- for (Type tt = t; tt != null && tt != TypeManager.object_type;){
+ int errors = ec.Report.Errors;
+ for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type;){
if (TryType (ec, tt))
return true;
tt = tt.BaseType;
}
- if (Report.Errors > errors)
+ if (ec.Report.Errors > errors)
return false;
//
// Now try to find the method in the interfaces
//
- Type [] ifaces = TypeManager.GetInterfaces (t);
- foreach (Type i in ifaces){
- if (TryType (ec, i))
- return true;
+ for (TypeSpec tt = t; tt != null && tt != TypeManager.object_type; ) {
+ if (tt.Interfaces != null) {
+ foreach (TypeSpec i in tt.Interfaces) {
+ if (TryType (ec, i))
+ return true;
+ }
+ }
+ tt = tt.BaseType;
}
return false;
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
enumerator_type = TypeManager.ienumerator_type;
+ bool is_dynamic = expr.Type == InternalType.Dynamic;
+ if (is_dynamic)
+ expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
+
if (!ProbeCollectionType (ec, expr.Type)) {
- Error_Enumerator ();
+ Error_Enumerator (ec);
return false;
}
- bool is_disposable = !enumerator_type.IsSealed ||
- TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
-
VarExpr ve = var_type as VarExpr;
if (ve != null) {
// Infer implicitly typed local variable from foreach enumerable type
- var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
+ var_type = new TypeExpression (
+ is_dynamic ? InternalType.Dynamic : get_current.Type,
+ var_type.Location);
}
var_type = var_type.ResolveAsTypeTerminal (ec, false);
Expression move_next_expr;
{
- MemberInfo[] mi = new MemberInfo[] { move_next };
+ var mi = new List<MemberSpec> (1) { move_next };
MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
mg.InstanceExpression = enumerator;
Statement block = new CollectionForeachStatement (
var_type.Type, variable, get_current, statement, loc);
- loop = new While (move_next_expr, block, loc);
+ loop = new While (new BooleanExpression (move_next_expr), block, loc);
+
+
+ bool implements_idisposable = enumerator_type.ImplementsInterface (TypeManager.idisposable_type);
+ if (implements_idisposable || !enumerator_type.IsSealed) {
+ wrapper = new DisposableWrapper (this, implements_idisposable);
+ } else {
+ wrapper = new NonDisposableWrapper (this);
+ }
- wrapper = is_disposable ?
- (Statement) new DisposableWrapper (this) :
- (Statement) new NonDisposableWrapper (this);
return wrapper.Resolve (ec);
}
throw new NotSupportedException ();
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
return parent.ResolveLoop (ec);
}
parent.EmitLoopInit (ec);
parent.EmitLoopBody (ec);
}
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- throw new NotSupportedException ();
- }
}
- class DisposableWrapper : ExceptionStatement {
+ sealed class DisposableWrapper : ExceptionStatement
+ {
CollectionForeach parent;
+ bool implements_idisposable;
- internal DisposableWrapper (CollectionForeach parent)
+ internal DisposableWrapper (CollectionForeach parent, bool implements)
{
this.parent = parent;
+ this.implements_idisposable = implements;
}
protected override void CloneTo (CloneContext clonectx, Statement target)
throw new NotSupportedException ();
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
bool ok = true;
ec.EndFlowBranching ();
- ResolveReachability (ec);
+ ok &= base.Resolve (ec);
if (TypeManager.void_dispose_void == null) {
TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
- TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
+ TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
}
return ok;
}
protected override void EmitFinallyBody (EmitContext ec)
{
- parent.EmitFinallyBody (ec);
- }
+ Expression instance = parent.enumerator;
+ if (!TypeManager.IsValueType (parent.enumerator_type)) {
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- throw new NotSupportedException ();
+ parent.enumerator.Emit (ec);
+
+ Label call_dispose = ec.DefineLabel ();
+
+ if (!implements_idisposable) {
+ ec.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+ LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
+ temp.Store (ec);
+ temp.Emit (ec);
+ instance = temp;
+ }
+
+ ec.Emit (OpCodes.Brtrue_S, call_dispose);
+
+ // using 'endfinally' to empty the evaluation stack
+ ec.Emit (OpCodes.Endfinally);
+ ec.MarkLabel (call_dispose);
+ }
+
+ Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc);
}
}
- bool ResolveLoop (EmitContext ec)
+ bool ResolveLoop (BlockContext ec)
{
return loop.Resolve (ec);
}
{
loop.Emit (ec);
}
-
- void EmitFinallyBody (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- if (enumerator_type.IsValueType) {
- MethodInfo mi = FetchMethodDispose (enumerator_type);
- if (mi != null) {
- enumerator.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- } else {
- enumerator.Emit (ec);
- ig.Emit (OpCodes.Box, enumerator_type);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- }
- } else {
- Label call_dispose = ig.DefineLabel ();
-
- enumerator.Emit (ec);
- ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
- ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Brtrue_S, call_dispose);
-
- // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
- // (Partition III, Section 3.35)
- ig.Emit (OpCodes.Endfinally);
-
- ig.MarkLabel (call_dispose);
- ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- }
- }
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- enumerator_type = storey.MutateType (enumerator_type);
- init.MutateHoistedGenericType (storey);
- loop.MutateHoistedGenericType (storey);
- }
}
Expression type;
get { return statement; }
}
- public override bool Resolve (EmitContext ec)
+ public override bool Resolve (BlockContext ec)
{
expr = expr.Resolve (ec);
if (expr == null)
return false;
if (expr.IsNull) {
- Report.Error (186, loc, "Use of null is not valid in this context");
+ ec.Report.Error (186, loc, "Use of null is not valid in this context");
return false;
}
if (expr.Type == TypeManager.string_type) {
statement = new ArrayForeach (this, 1);
- } else if (expr.Type.IsArray) {
- statement = new ArrayForeach (this, expr.Type.GetArrayRank ());
+ } else if (expr.Type is ArrayContainer) {
+ statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
} else {
if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
- Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
+ ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
expr.ExprClassName);
return false;
}
protected override void DoEmit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
-
Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
- ec.LoopBegin = ig.DefineLabel ();
- ec.LoopEnd = ig.DefineLabel ();
+ ec.LoopBegin = ec.DefineLabel ();
+ ec.LoopEnd = ec.DefineLabel ();
statement.Emit (ec);
target.expr = expr.Clone (clonectx);
target.statement = statement.Clone (clonectx);
}
-
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- statement.MutateHoistedGenericType (storey);
- }
}
}