{
ec.Mark (loc, true);
DoEmit (ec);
- }
+ }
+
+ //
+ // This routine must be overrided in derived classes and make copies
+ // of all the data that might be modified if resolved
+ //
+ protected virtual void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new Exception (String.Format ("Statement.CloneTo not implemented for {0}", this.GetType ()));
+ }
+
+ public Statement Clone (CloneContext clonectx)
+ {
+ Statement s = (Statement) this.MemberwiseClone ();
+ if (s is Block)
+ clonectx.AddBlockMap ((Block) this, (Block) s);
+
+ CloneTo (clonectx, s);
+ return s;
+ }
+
+ public Statement PerformClone ()
+ {
+ CloneContext clonectx = new CloneContext ();
+
+ return Clone (clonectx);
+ }
+
}
+ //
+ // 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;
+ }
+
+ 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)
+ {
+ 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;
+ }
+ }
+
public sealed class EmptyStatement : Statement {
private EmptyStatement () {}
ig.MarkLabel (false_target);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ If target = (If) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.TrueStatement = TrueStatement.Clone (clonectx);
+ target.FalseStatement = FalseStatement.Clone (clonectx);
+ }
}
public class Do : Statement {
public Expression expr;
- public readonly Statement EmbeddedStatement;
+ public Statement EmbeddedStatement;
bool infinite;
public Do (Statement statement, Expression boolExpr, Location l)
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Do target = (Do) t;
+
+ target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
+ target.expr = expr.Clone (clonectx);
+ }
}
public class While : Statement {
public Expression expr;
- public readonly Statement Statement;
+ public Statement Statement;
bool infinite, empty;
public While (Expression boolExpr, Statement statement, Location l)
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ While target = (While) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class For : Statement {
Expression Test;
- readonly Statement InitStatement;
- readonly Statement Increment;
- public readonly Statement Statement;
+ Statement InitStatement;
+ Statement Increment;
+ public Statement Statement;
bool infinite, empty;
public For (Statement initStatement,
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ For target = (For) t;
+
+ if (InitStatement != null)
+ target.InitStatement = InitStatement.Clone (clonectx);
+ if (Test != null)
+ target.Test = Test.Clone (clonectx);
+ if (Increment != null)
+ target.Increment = Increment.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class StatementExpression : Statement {
{
return "StatementExpression (" + expr + ")";
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ StatementExpression target = (StatementExpression) t;
+
+ target.expr = (ExpressionStatement) expr.Clone (clonectx);
+ }
}
/// <summary>
unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
if (unwind_protect)
ec.NeedReturnLabel ();
- ec.CurrentBranching.CurrentUsageVector.Return ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return errors == Report.Errors;
}
else
ec.ig.Emit (OpCodes.Ret);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Return target = (Return) t;
+
+ target.Expr = Expr.Clone (clonectx);
+ }
}
public class Goto : Statement {
{
ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ GotoCase target = (GotoCase) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.sl = sl.Clone (clonectx);
+ }
}
public class Throw : Statement {
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Throw ();
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
if (expr != null){
expr = expr.Resolve (ec);
ec.ig.Emit (OpCodes.Throw);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Throw target = (Throw) t;
+
+ target.expr = expr.Clone (clonectx);
+ }
}
public class Break : Statement {
Flags flags;
ReadOnlyContext ro_context;
+ LocalBuilder builder;
public LocalInfo (Expression type, string name, Block block, Location l)
{
public LocalInfo (DeclSpace ds, Block block, Location l)
{
- VariableType = ds.TypeBuilder;
+ VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
Block = block;
Location = l;
}
var = theblock.ScopeInfo.GetCapturedVariable (this);
if (var == null) {
- LocalBuilder builder;
if (Pinned)
//
// This is needed to compile on both .NET 1.x and .NET 2.x
}
}
- public bool IsThisAssigned (EmitContext ec, Location loc)
+ public void EmitSymbolInfo (EmitContext ec, string name)
+ {
+ if (builder != null)
+ ec.DefineLocalVariable (name, builder);
+ }
+
+ public bool IsThisAssigned (EmitContext ec)
{
if (VariableInfo == null)
throw new Exception ();
if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
return true;
- return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, loc);
+ return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc);
}
public bool IsAssigned (EmitContext ec)
}
if (VariableType.IsAbstract && VariableType.IsSealed) {
- FieldMember.Error_VariableOfStaticClass (Location, Name, VariableType);
+ FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
return false;
}
ec.ig.Emit (OpCodes.Ldloca, builder);
}
}
+
+ public LocalInfo Clone (CloneContext clonectx)
+ {
+ // Only this kind is created by the parser.
+ return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
+ }
}
-
+
/// <summary>
/// Block represents a C# block.
/// </summary>
public VariableMap ParameterMap {
get {
- if ((flags & Flags.VariablesInitialized) == 0)
+ if ((flags & Flags.VariablesInitialized) == 0){
throw new Exception ("Variables have not been initialized yet");
+ }
return param_map;
}
continue;
}
- e = ce.ImplicitConversionRequired (variable_type, vi.Location);
- if (e == null)
- continue;
-
- if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue) {
- Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
+ e = ce.ConvertImplicitly (variable_type);
+ if (e == null) {
+ if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue)
+ Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
+ else
+ ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false);
continue;
}
Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
ec.CurrentBranching, statement_count, num_statements);
+ if (!ok)
+ return false;
+
while (ec.CurrentBranching is FlowBranchingLabeled)
ec.EndFlowBranching ();
// initializer, then we must initialize all of the struct's fields.
if ((flags & Flags.IsToplevel) != 0 &&
!Toplevel.IsThisAssigned (ec) &&
- !vector.Reachability.AlwaysThrows)
+ !vector.Reachability.IsUnreachable)
ok = false;
if ((labels != null) && (RootContext.WarningLevel >= 2)) {
DoEmit (ec);
ec.Mark (EndLocation, true);
- if (emit_debug_info && is_lexical_block)
- ec.EndScope ();
+ if (emit_debug_info) {
+ if (is_lexical_block)
+ ec.EndScope ();
+
+ if (variables != null) {
+ foreach (DictionaryEntry de in variables) {
+ string name = (string) de.Key;
+ LocalInfo vi = (LocalInfo) de.Value;
+
+ vi.EmitSymbolInfo (ec, name);
+ }
+ }
+ }
ec.CurrentBlock = prev_block;
}
{
return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Block target = (Block) t;
+
+ if (Parent != null)
+ target.Parent = clonectx.LookupBlock (Parent);
+
+ target.statements = new ArrayList ();
+ if (target.children != null){
+ target.children = new ArrayList ();
+ foreach (Block b in children){
+ Block newblock = (Block) b.Clone (clonectx);
+
+ target.children.Add (newblock);
+ }
+
+ }
+
+ foreach (Statement s in statements)
+ target.statements.Add (s.Clone (clonectx));
+
+ if (variables != null){
+ target.variables = new Hashtable ();
+
+ foreach (DictionaryEntry de in variables){
+ LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
+ target.variables [de.Key] = newlocal;
+ clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
+ }
+ }
+
+ //
+ // TODO: labels, switch_block, constants (?), anonymous_children
+ //
+ }
}
//
}
}
- public void EmitScopeInstance (EmitContext ec, ScopeInfo scope)
- {
- ScopeInfo.EmitScopeInstance (ec, scope, this);
- }
-
public FlowBranchingToplevel TopLevelBranching {
get { return top_level_branching; }
}
public bool IsThisAssigned (EmitContext ec)
{
- return this_variable == null || this_variable.IsThisAssigned (ec, loc);
+ return this_variable == null || this_variable.IsThisAssigned (ec);
}
public bool ResolveMeta (EmitContext ec, Parameters ip)
return true;
}
- public void Erorr_AlreadyOccurs ()
+ public void Erorr_AlreadyOccurs (Type switchType, SwitchLabel collisionWith)
{
string label;
if (converted == null)
label = "default";
else if (converted == NullStringCase)
label = "null";
+ else if (TypeManager.IsEnumType (switchType))
+ label = TypeManager.CSharpEnumValue (switchType, converted);
else
label = converted.ToString ();
-
+
+ Report.SymbolRelatedToPreviousError (collisionWith.loc, null);
Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
}
+
+ public SwitchLabel Clone (CloneContext clonectx)
+ {
+ return new SwitchLabel (label.Clone (clonectx), loc);
+ }
}
public class SwitchSection {
Labels = labels;
Block = block;
}
+
+ public SwitchSection Clone (CloneContext clonectx)
+ {
+ ArrayList cloned_labels = new ArrayList ();
+
+ foreach (SwitchLabel sl in cloned_labels)
+ cloned_labels.Add (sl.Clone (clonectx));
+
+ return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
+ }
}
public class Switch : Statement {
- public readonly ArrayList Sections;
+ public ArrayList Sections;
public Expression Expr;
/// <summary>
//
Expression SwitchGoverningType (EmitContext ec, Expression expr)
{
- Type t = expr.Type;
+ Type t = TypeManager.DropGenericTypeArguments (expr.Type);
if (t == TypeManager.byte_type ||
t == TypeManager.sbyte_type ||
foreach (SwitchLabel sl in ss.Labels){
if (sl.Label == null){
if (default_section != null){
- sl.Erorr_AlreadyOccurs ();
+ sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
error = true;
}
default_section = ss;
try {
Elements.Add (key, sl);
} catch (ArgumentException) {
- sl.Erorr_AlreadyOccurs ();
+ sl.Erorr_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
error = true;
}
}
bool pending_goto_end = false;
bool null_marked = false;
bool null_found;
+ int section_count = Sections.Count;
+
+ // TODO: implement switch optimization for string by using Hashtable
+ //if (SwitchType == TypeManager.string_type && section_count > 7)
+ // Console.WriteLine ("Switch optimization possible " + loc);
ig.Emit (OpCodes.Ldloc, val);
ig.Emit (OpCodes.Brfalse, default_target);
ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
+ ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string);
ig.Emit (OpCodes.Stloc, val);
- int section_count = Sections.Count;
for (int section = 0; section < section_count; section++){
SwitchSection ss = (SwitchSection) Sections [section];
// Validate switch.
SwitchType = new_expr.Type;
+ if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
+ Report.FeatureIsNotISO1 (loc, "switch expression of boolean type");
+ return false;
+ }
+
if (!CheckSwitch (ec))
return false;
ec.LoopEnd = old_end;
ec.Switch = old_switch;
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Switch target = (Switch) t;
+
+ target.Expr = Expr.Clone (clonectx);
+ target.Sections = new ArrayList ();
+ foreach (SwitchSection ss in Sections){
+ target.Sections.Add (ss.Clone (clonectx));
+ }
+ }
}
public abstract class ExceptionStatement : Statement
ResolveFinally (branching);
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
- if (!reachability.AlwaysReturns) {
- // Unfortunately, System.Reflection.Emit automatically emits
- // a leave to the end of the finally block.
- // This is a problem if `returns' is true since we may jump
- // to a point after the end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ ec.EndFlowBranching ();
+
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
// Avoid creating libraries that reference the internal
// mcs NullType:
temp.Emit (ec);
ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Lock target = (Lock) t;
+
+ target.expr = expr.Clone (clonectx);
+ target.Statement = Statement.Clone (clonectx);
+ }
}
public class Unchecked : Statement {
- public readonly Block Block;
+ public Block Block;
public Unchecked (Block b)
{
using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
Block.Emit (ec);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Unchecked target = (Unchecked) t;
+
+ target.Block = clonectx.LookupBlock (Block);
+ }
}
public class Checked : Statement {
- public readonly Block Block;
+ public Block Block;
public Checked (Block b)
{
using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
Block.Emit (ec);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Checked target = (Checked) t;
+
+ target.Block = clonectx.LookupBlock (Block);
+ }
}
public class Unsafe : Statement {
- public readonly Block Block;
+ public Block Block;
public Unsafe (Block b)
{
using (ec.With (EmitContext.Flags.InUnsafe, true))
Block.Emit (ec);
}
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Unsafe target = (Unsafe) t;
+
+ target.Block = clonectx.LookupBlock (Block);
+ }
}
//
return false;
if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
- e.Error_ValueCannotBeConverted (e.Location, expr_type, false);
+ e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
return false;
}
data [i].EmitExit (ec);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Fixed target = (Fixed) t;
+
+ target.type = type.Clone (clonectx);
+ target.declarators = new ArrayList ();
+ foreach (LocalInfo var in declarators)
+ target.declarators.Add (clonectx.LookupVariable (var));
+ target.statement = statement.Clone (clonectx);
+ }
}
public class Catch : Statement {
public readonly string Name;
- public readonly Block Block;
- public readonly Block VarBlock;
+ public Block Block;
+ public Block VarBlock;
Expression type_expr;
Type type;
return true;
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Catch target = (Catch) t;
+
+ target.type_expr = type_expr.Clone (clonectx);
+ target.Block = clonectx.LookupBlock (Block);
+ target.VarBlock = clonectx.LookupBlock (VarBlock);
+ }
}
public class Try : ExceptionStatement {
- public readonly Block Fini, Block;
- public readonly ArrayList Specific;
- public readonly Catch General;
+ public Block Fini, Block;
+ public ArrayList Specific;
+ public Catch General;
bool need_exc_block;
} else
emit_finally = Fini != null;
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
+ ec.EndFlowBranching ();
- FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
- Report.Debug (1, "END OF TRY", ec.CurrentBranching, reachability, vector, f_vector);
+ FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
- if (!reachability.AlwaysReturns) {
- // Unfortunately, System.Reflection.Emit automatically emits
- // a leave to the end of the finally block. This is a problem
- // if `returns' is true since we may jump to a point after the
- // end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ Report.Debug (1, "END OF TRY", ec.CurrentBranching, vector, f_vector);
return ok;
}
return General != null || Specific.Count > 0;
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Try target = (Try) t;
+
+ target.Block = clonectx.LookupBlock (Block);
+ if (Fini != null)
+ target.Fini = clonectx.LookupBlock (Fini);
+ if (General != null)
+ target.General = (Catch) General.Clone (clonectx);
+ if (Specific != null){
+ target.Specific = new ArrayList ();
+ foreach (Catch c in Specific)
+ target.Specific.Add (c.Clone (clonectx));
+ }
+ }
}
public class Using : ExceptionStatement {
}
ResolveFinally (branching);
- FlowBranching.Reachability reachability = ec.EndFlowBranching ();
- if (!reachability.AlwaysReturns) {
- // Unfortunately, System.Reflection.Emit automatically emits a leave
- // to the end of the finally block. This is a problem if `returns'
- // is true since we may jump to a point after the end of the method.
- // As a workaround, emit an explicit ret here.
- ec.NeedReturnLabel ();
- }
+ ec.EndFlowBranching ();
+
+ // System.Reflection.Emit automatically emits a 'leave' to the end of the finally block.
+ // So, ensure there's some IL code after the finally block.
+ ec.NeedReturnLabel ();
return true;
}
else if (expression_or_block is Expression)
EmitExpressionFinally (ec);
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Using target = (Using) t;
+
+ if (expression_or_block is Expression)
+ target.expression_or_block = ((Expression) expression_or_block).Clone (clonectx);
+ else
+ target.expression_or_block = ((Statement) expression_or_block).Clone (clonectx);
+
+ target.Statement = Statement.Clone (clonectx);
+ }
}
/// <summary>
if (!TypeManager.IsGenericType (mi.ReturnType))
continue;
- Report.SymbolRelatedToPreviousError(t);
+ 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 (mi));
+ "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
+ TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
+ return false;
+ }
+
+ // Always prefer generics enumerators
+ if (!TypeManager.IsGenericType (mi.ReturnType)) {
+ if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
+ TypeManager.ImplementsInterface (result.DeclaringType, 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));
return false;
}
- 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));
}
result = mi;
tmp_move_next = move_next;
statement.Emit (ec);
}
}
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ Foreach target = (Foreach) t;
+
+ target.type = type.Clone (clonectx);
+ target.variable = variable.Clone (clonectx);
+ target.expr = expr.Clone (clonectx);
+ target.statement = statement.Clone (clonectx);
+ }
}
}