/// </summary>
public virtual void Emit (EmitContext ec)
{
- ec.Mark (loc, true);
+ ec.Mark (loc);
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 InternalErrorException ("{0} does not implement Statement.CloneTo", this.GetType ());
- }
+ protected abstract void CloneTo (CloneContext clonectx, Statement target);
public Statement Clone (CloneContext clonectx)
{
Statement.Emit (ec);
ig.MarkLabel (ec.LoopBegin);
- ec.Mark (loc, true);
+ ec.Mark (loc);
expr.EmitBranchable (ec, while_loop, true);
return false;
}
- AnonymousExpression am = ec.CurrentAnonymousMethod;
- if ((am != null) && am.IsIterator && ec.InIterator) {
+ if (ec.CurrentBlock.Toplevel.IsIterator) {
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",
label.AddReference ();
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // Nothing to clone
+ }
+
protected override void DoEmit (EmitContext ec)
{
if (label == null)
vectors = vector;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // nothing to clone
+ }
+
public override bool Resolve (EmitContext ec)
{
// this flow-branching will be terminated when the surrounding block ends
loc = l;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // nothing to clone
+ }
+
public override bool Resolve (EmitContext ec)
{
ec.CurrentBranching.CurrentUsageVector.Goto ();
return false;
}
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
+
expr = expr.Resolve (ec);
if (expr == null)
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));
+ 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))
+ 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;
return false;
}
- ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Goto ();
-
- if (expr == null)
+ if (expr == null) {
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return ec.CurrentBranching.CheckRethrow (loc);
+ }
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
-
- ExprClass eclass = expr.eclass;
+ expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
- if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
- eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
- expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
+ if (expr == null)
return false;
- }
Type t = expr.Type;
if ((t != TypeManager.exception_type) &&
!TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
- !(expr is NullLiteral)) {
+ t != TypeManager.null_type) {
Error (155, "The type caught or thrown must be derived from System.Exception");
return false;
}
// 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 readonly string Name;
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;
ec.ig.Emit (OpCodes.Ldloca, builder);
}
- public void EmitSymbolInfo (EmitContext ec, string name)
+ public void EmitSymbolInfo (EmitContext ec)
{
if (builder != null)
ec.DefineLocalVariable (Name, builder);
if (TypeManager.IsGenericParameter (VariableType))
return true;
- if (VariableType == TypeManager.void_type) {
- Expression.Error_VoidInvalidInTheContext (Location);
- return false;
- }
-
if (VariableType.IsAbstract && VariableType.IsSealed) {
FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
return false;
throw new InternalErrorException ("Variable is not readonly");
switch (ro_context) {
- case ReadOnlyContext.Fixed:
- return "fixed variable";
- case ReadOnlyContext.Foreach:
- return "foreach iteration variable";
- case ReadOnlyContext.Using:
- return "using variable";
+ case ReadOnlyContext.Fixed:
+ return "fixed variable";
+ case ReadOnlyContext.Foreach:
+ return "foreach iteration variable";
+ case ReadOnlyContext.Using:
+ return "using variable";
}
throw new NotImplementedException ();
}
// 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
/// </remarks>
public class Block : Statement {
public Block Parent;
- public readonly Location StartLocation;
+ public Location StartLocation;
public Location EndLocation = Location.Null;
public ExplicitBlock Explicit;
BlockUsed = 2,
VariablesInitialized = 4,
HasRet = 8,
- IsDestructor = 16,
- Unsafe = 32
+ Unsafe = 16,
+ IsIterator = 32,
+ HasCapturedVariable = 64,
+ HasCapturedThis = 128
}
protected Flags flags;
public bool Unchecked {
get { return (flags & Flags.Unchecked) != 0; }
- set { flags |= Flags.Unchecked; }
+ set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
}
public bool Unsafe {
//
Block switch_block;
- ArrayList scope_initializers;
+ protected ArrayList scope_initializers;
ArrayList anonymous_children;
: 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) {
if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
return true;
+ if (this is ToplevelBlock) {
+ Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ e.Error_VariableIsUsedBeforeItIsDeclared (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.
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);
- if (Explicit == vi.Block.Explicit)
+ if (Explicit == vi.Block.Explicit) {
Error_AlreadyDeclared (l, name, null);
- else
- Error_AlreadyDeclared (l, name, "parent");
- return null;
+ } else {
+ Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
+ "parent or current" : "parent");
+ }
+ 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);
+ Error_AlreadyDeclaredTypeParameter (loc, name, "local variable");
return null;
}
}
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)
"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 (Location loc, string name, string conflict)
{
- GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
- }
+ Report.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)
{
public LocalInfo GetLocalInfo (string name)
{
+ LocalInfo ret;
for (Block b = this; b != null; b = b.Parent) {
if (b.variables != null) {
- LocalInfo ret = b.variables [name] as LocalInfo;
+ ret = (LocalInfo) b.variables [name];
if (ret != null)
return ret;
}
}
+
return null;
}
// 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 ();
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 {
- if ((flags & Flags.VariablesInitialized) == 0)
- throw new Exception ("Variables have not been initialized yet");
+// TODO: Re-enable
+// if ((flags & Flags.VariablesInitialized) == 0)
+// throw new Exception ("Variables have not been initialized yet");
return assignable_slots;
}
}
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);
+ if (TypeManager.IsReferenceType (variable_type))
+ Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name);
else
- ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false);
+ ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
continue;
}
}
}
- private void CheckPossibleMistakenEmptyStatement (Statement s)
+ static void CheckPossibleMistakenEmptyStatement (Statement s)
{
Statement body;
// Check possible empty statement (CS0642)
if (Report.WarningLevel >= 3 &&
ix + 1 < statement_count &&
- statements [ix + 1] is Block)
+ statements [ix + 1] is ExplicitBlock)
CheckPossibleMistakenEmptyStatement (s);
//
if (s is EmptyStatement)
continue;
- if (s is Block)
- ((Block) s).unreachable = true;
-
if (!unreachable_shown && !(s is LabeledStatement)) {
Report.Warning (162, 2, s.loc, "Unreachable code detected");
unreachable_shown = true;
}
+
+ Block c_block = s as Block;
+ if (c_block != null)
+ c_block.unreachable = c_block.unreachable_shown = true;
}
//
Block prev_block = ec.CurrentBlock;
ec.CurrentBlock = this;
- if (scope_initializers != null) {
- SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
-
- bool omit_debug_info = ec.OmitDebuggingInfo;
- ec.OmitDebuggingInfo = true;
- foreach (StatementExpression s in scope_initializers)
- s.Emit (ec);
- ec.OmitDebuggingInfo = omit_debug_info;
-
- SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
- }
+ if (scope_initializers != null)
+ EmitScopeInitializers (ec);
- ec.Mark (StartLocation, true);
+ ec.Mark (StartLocation);
DoEmit (ec);
+ if (SymbolWriter.HasSymbolWriter)
+ EmitSymbolInfo (ec);
+
ec.CurrentBlock = prev_block;
}
+ protected void EmitScopeInitializers (EmitContext ec)
+ {
+ SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
+
+ using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
+ foreach (Statement s in scope_initializers)
+ s.Emit (ec);
+ }
+
+ SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+ }
+
protected virtual void EmitSymbolInfo (EmitContext ec)
{
if (variables != null) {
- foreach (DictionaryEntry de in variables) {
- string name = (string) de.Key;
- LocalInfo vi = (LocalInfo) de.Value;
-
- vi.EmitSymbolInfo (ec, name);
+ foreach (LocalInfo vi in variables.Values) {
+ vi.EmitSymbolInfo (ec);
}
}
}
{
MutateVariables (storey);
+ if (scope_initializers != null) {
+ foreach (Statement s in scope_initializers)
+ s.MutateHoistedGenericType (storey);
+ }
+
foreach (Statement s in statements)
s.MutateHoistedGenericType (storey);
}
// 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;
}
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");
}
- //
- // 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;
- bool is_lexical_block = Parent != null && !(am_storey is IteratorStorey);
- if (emit_debug_info && is_lexical_block)
+ bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
+ if (emit_debug_info)
ec.BeginScope ();
base.Emit (ec);
- if (emit_debug_info) {
- EmitSymbolInfo (ec);
- if (is_lexical_block)
- ec.EndScope ();
- }
+ if (emit_debug_info)
+ ec.EndScope ();
}
public override void EmitMeta (EmitContext ec)
{
- base.EmitMeta (ec);
-
//
- // It has to be done when all storey references are resolved
+ // Creates anonymous method storey
//
- if (am_storey != null && am_storey.HasHoistedVariables)
- am_storey.DefineMembers ();
- }
+ if (am_storey != null) {
+ if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+ //
+ // Creates parent storey reference when hoisted this is accessible
+ //
+ if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
+ ExplicitBlock parent = Toplevel.Parent.Explicit;
- protected override void EmitSymbolInfo (EmitContext ec)
- {
- if (am_storey != null)
- SymbolWriter.DefineScopeVariable (am_storey.ID);
+ //
+ // Hoisted this exists in top-level parent storey only
+ //
+ while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
+ parent = parent.Parent.Explicit;
- base.EmitSymbolInfo (ec);
+ am_storey.AddParentStoreyReference (parent.am_storey);
+ }
+
+ am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
+ }
+
+ am_storey.DefineType ();
+ am_storey.ResolveType ();
+ am_storey.Define ();
+ am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+
+ ArrayList 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 (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];
}
- public void PropagateStoreyReference (AnonymousMethodStorey s)
+ public bool HasCapturedThis
{
- if (Parent != null && am_storey != s) {
- if (am_storey != null)
- am_storey.AddParentStoreyReference (s);
-
- Parent.Explicit.PropagateStoreyReference (s);
- }
+ set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
+ get { return (flags & Flags.HasCapturedThis) != 0; }
}
- public override bool Resolve (EmitContext ec)
+ public bool HasCapturedVariable
{
- bool ok = base.Resolve (ec);
-
- //
- // Define an anonymous method storey when this block has hoisted variables
- //
- if (am_storey != null && am_storey.HasHoistedVariables) {
- am_storey.DefineType ();
- am_storey.DefineMembers ();
- }
-
- return ok;
+ set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
+ get { return (flags & Flags.HasCapturedVariable) != 0; }
}
protected override void CloneTo (CloneContext clonectx, Statement t)
public Parameter Parameter {
get { return Block.Parameters [Index]; }
}
+
+ public Type ParameterType {
+ get { return Block.Parameters.Types [Index]; }
+ }
+
public Location Location {
get { return Parameter.Location; }
}
// 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 (EmitContext ec)
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (child == null)
+ return null;
+
+ block.ResolveMeta (ec, ParametersCompiled.EmptyReadOnlyParameters);
+ 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);
+ }
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ type = storey.MutateType (type);
+ child.MutateHoistedGenericType (storey);
+ block.MutateHoistedGenericType (storey);
+ }
+ }
+
GenericMethod generic;
FlowBranchingToplevel top_level_branching;
- Parameters parameters;
+ protected ParametersCompiled parameters;
ToplevelParameterInfo[] parameter_info;
LocalInfo this_variable;
//
// The parameters for the block.
//
- public Parameters Parameters {
+ public ParametersCompiled Parameters {
get { return parameters; }
}
get { return Parent == null ? null : Parent.Toplevel; }
}
- public ToplevelBlock (Block parent, Parameters parameters, Location start) :
+ public ToplevelBlock (Block parent, ParametersCompiled parameters, Location start) :
this (parent, (Flags) 0, parameters, start)
{
}
- public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
+ public ToplevelBlock (Block parent, ParametersCompiled parameters, GenericMethod generic, Location start) :
this (parent, parameters, start)
{
this.generic = generic;
}
- public ToplevelBlock (Parameters parameters, Location start) :
+ public ToplevelBlock (ParametersCompiled parameters, Location start) :
this (null, (Flags) 0, parameters, start)
{
}
- ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ ToplevelBlock (Flags flags, ParametersCompiled parameters, Location start) :
this (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 (Block parent, Flags flags, ParametersCompiled parameters, Location start) :
base (null, flags, start, Location.Null)
{
this.Toplevel = this;
- this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+ this.parameters = parameters;
this.Parent = parent;
if (parent != null)
parent.AddAnonymousChild (this);
- if (this.parameters.Count != 0)
+ if (!this.parameters.IsEmpty)
ProcessParameters ();
}
- public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+ public ToplevelBlock (Location loc)
+ : this (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
public override Expression CreateExpressionTree (EmitContext ec)
{
- 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.AddStatement (new Return (iterator, iterator.Location));
+ source.IsIterator = false;
IteratorStorey iterator_storey = new IteratorStorey (iterator);
source.am_storey = iterator_storey;
}
//
- // 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.
return this_variable;
}
+ public bool IsIterator {
+ get { return (flags & Flags.IsIterator) != 0; }
+ set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
+ }
+
public bool IsThisAssigned (EmitContext ec)
{
return this_variable == null || this_variable.IsThisAssigned (ec);
}
- public bool ResolveMeta (EmitContext ec, Parameters ip)
+ public bool ResolveMeta (EmitContext ec, ParametersCompiled ip)
{
int errors = Report.Errors;
int orig_count = parameters.Count;
int offset = Parent == null ? 0 : Parent.AssignableSlots;
for (int i = 0; i < orig_count; ++i) {
- Parameter.Modifier mod = parameters.ParameterModifier (i);
+ Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
continue;
base.EmitMeta (ec);
}
+ protected override void EmitSymbolInfo (EmitContext ec)
+ {
+ AnonymousExpression ae = ec.CurrentAnonymousMethod;
+ if ((ae != null) && (ae.Storey != null))
+ SymbolWriter.DefineScopeVariable (ae.Storey.ID);
+
+ base.EmitSymbolInfo (ec);
+ }
+
public override void Emit (EmitContext ec)
{
base.Emit (ec);
- ec.Mark (EndLocation, true);
+ ec.Mark (EndLocation);
}
}
}
}
+ public Location Location {
+ get { return loc; }
+ }
+
public object Converted {
get {
return converted;
return true;
}
- c = c.ImplicitConversionRequired (required_type, loc);
+ c = c.ImplicitConversionRequired (ec, required_type, loc);
if (c == null)
return false;
label = "default";
else if (converted == NullStringCase)
label = "null";
- else if (TypeManager.IsEnumType (switch_type))
- label = TypeManager.CSharpEnumValue (switch_type, converted);
else
label = converted.ToString ();
Label null_target;
Expression new_expr;
bool is_constant;
+ bool has_null_case;
SwitchSection constant_section;
SwitchSection default_section;
+ ExpressionStatement string_dictionary;
+ FieldExpr switch_cache_field;
+ static int unique_counter;
+
#if GMCS_SOURCE
//
// Nullable Types support for GMCS.
TypeManager.int64_type,
TypeManager.uint64_type,
TypeManager.char_type,
- TypeManager.string_type,
- TypeManager.bool_type
+ TypeManager.string_type
};
}
continue;
if (converted != null){
- Report.ExtraInformation (
- loc,
- String.Format ("reason: more than one conversion to an integral type exist for type {0}",
- TypeManager.CSharpName (expr.Type)));
+ Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
return null;
}
}
object key = sl.Converted;
+ if (key == SwitchLabel.NullStringCase)
+ has_null_case = true;
+
try {
Elements.Add (key, sl);
} catch (ArgumentException) {
/// <param name="ec"></param>
/// <param name="val"></param>
/// <returns></returns>
- void TableSwitchEmit (EmitContext ec, LocalBuilder val)
+ void TableSwitchEmit (EmitContext ec, Expression val)
{
int element_count = Elements.Count;
object [] element_keys = new object [element_count];
Array.Sort (element_keys);
// initialize the block list with one element per key
- ArrayList key_blocks = new ArrayList ();
+ ArrayList key_blocks = new ArrayList (element_count);
foreach (object key in element_keys)
key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
// okay now we can start...
ILGenerator ig = ec.ig;
Label lbl_end = ig.DefineLabel (); // at the end ;-)
- Label lbl_default = ig.DefineLabel ();
+ Label lbl_default = default_target;
Type type_keys = null;
if (element_keys.Length > 0)
for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
{
KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
- lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+ lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel ();
if (kb.Length <= 2)
{
- foreach (object key in kb.element_keys)
- {
- ig.Emit (OpCodes.Ldloc, val);
- EmitObjectInteger (ig, key);
+ foreach (object key in kb.element_keys) {
SwitchLabel sl = (SwitchLabel) Elements [key];
- ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+ if (key is int && (int) key == 0) {
+ val.EmitBranchable (ec, sl.GetILLabel (ec), false);
+ } else {
+ val.Emit (ec);
+ EmitObjectInteger (ig, key);
+ ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+ }
}
}
else
// TODO: optimize constant/I4 cases
// check block range (could be > 2^31)
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
ig.Emit (OpCodes.Blt, lbl_default);
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
ig.Emit (OpCodes.Bgt, lbl_default);
// normalize range
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
if (kb.first != 0)
{
EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
else
{
// normalize range
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
int first = (int) kb.first;
if (first > 0)
{
// make sure to mark other labels in the default section
// the last default just goes to the end
- ig.Emit (OpCodes.Br, lbl_default);
+ if (element_keys.Length > 0)
+ ig.Emit (OpCodes.Br, lbl_default);
// now emit the code for the sections
bool found_default = false;
- bool found_null = false;
- foreach (SwitchSection ss in Sections)
- {
- foreach (SwitchLabel sl in ss.Labels)
- if (sl.Converted == SwitchLabel.NullStringCase)
- found_null = true;
- }
- foreach (SwitchSection ss in Sections)
- {
- foreach (SwitchLabel sl in ss.Labels)
- {
- ig.MarkLabel (sl.GetILLabel (ec));
- ig.MarkLabel (sl.GetILLabelCode (ec));
- if (sl.Converted == SwitchLabel.NullStringCase)
+ foreach (SwitchSection ss in Sections) {
+ foreach (SwitchLabel sl in ss.Labels) {
+ if (sl.Converted == SwitchLabel.NullStringCase) {
ig.MarkLabel (null_target);
- else if (sl.Label == null) {
+ } else if (sl.Label == null) {
ig.MarkLabel (lbl_default);
found_default = true;
- if (!found_null)
+ if (!has_null_case)
ig.MarkLabel (null_target);
}
+ ig.MarkLabel (sl.GetILLabel (ec));
+ ig.MarkLabel (sl.GetILLabelCode (ec));
}
ss.Block.Emit (ec);
}
if (!found_default) {
ig.MarkLabel (lbl_default);
- if (HaveUnwrap && !found_null) {
+ if (!has_null_case) {
ig.MarkLabel (null_target);
}
}
ig.MarkLabel (lbl_end);
}
- //
- // This simple emit switch works, but does not take advantage of the
- // `switch' opcode.
- // TODO: remove non-string logic from here
- // TODO: binary search strings?
- //
- void SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
- {
- ILGenerator ig = ec.ig;
- Label end_of_switch = ig.DefineLabel ();
- Label next_test = ig.DefineLabel ();
- bool first_test = 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);
-
- if (Elements.Contains (SwitchLabel.NullStringCase)){
- ig.Emit (OpCodes.Brfalse, null_target);
- } else
- ig.Emit (OpCodes.Brfalse, default_target);
-
- ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string);
- ig.Emit (OpCodes.Stloc, val);
-
- for (int section = 0; section < section_count; section++){
- SwitchSection ss = (SwitchSection) Sections [section];
-
- if (ss == default_section)
- continue;
-
- Label sec_begin = ig.DefineLabel ();
-
- ig.Emit (OpCodes.Nop);
-
- if (pending_goto_end)
- ig.Emit (OpCodes.Br, end_of_switch);
-
- int label_count = ss.Labels.Count;
- null_found = false;
- for (int label = 0; label < label_count; label++){
- SwitchLabel sl = (SwitchLabel) ss.Labels [label];
- ig.MarkLabel (sl.GetILLabel (ec));
-
- if (!first_test){
- ig.MarkLabel (next_test);
- next_test = ig.DefineLabel ();
- }
- //
- // If we are the default target
- //
- if (sl.Label != null){
- object lit = sl.Converted;
-
- if (lit == SwitchLabel.NullStringCase){
- null_found = true;
- if (label + 1 == label_count)
- ig.Emit (OpCodes.Br, next_test);
- continue;
- }
-
- ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Ldstr, (string)lit);
- if (label_count == 1)
- ig.Emit (OpCodes.Bne_Un, next_test);
- else {
- if (label+1 == label_count)
- ig.Emit (OpCodes.Bne_Un, next_test);
- else
- ig.Emit (OpCodes.Beq, sec_begin);
- }
- }
- }
- if (null_found) {
- ig.MarkLabel (null_target);
- null_marked = true;
- }
- ig.MarkLabel (sec_begin);
- foreach (SwitchLabel sl in ss.Labels)
- ig.MarkLabel (sl.GetILLabelCode (ec));
-
- ss.Block.Emit (ec);
- pending_goto_end = !ss.Block.HasRet;
- first_test = false;
- }
- ig.MarkLabel (next_test);
- ig.MarkLabel (default_target);
- if (!null_marked)
- ig.MarkLabel (null_target);
- if (default_section != null)
- default_section.Block.Emit (ec);
- ig.MarkLabel (end_of_switch);
- }
SwitchSection FindSection (SwitchLabel label)
{
ss.Block.MutateHoistedGenericType (storey);
}
+ public static void Reset ()
+ {
+ unique_counter = 0;
+ allowed_types = null;
+ }
+
public override bool Resolve (EmitContext ec)
{
Expr = Expr.Resolve (ec);
#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;
Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
- if (TypeManager.string_isinterned_string == null) {
- TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type,
- "IsInterned", loc, TypeManager.string_type);
+ if (!ok)
+ return false;
+
+ if (SwitchType == TypeManager.string_type && !is_constant) {
+ // TODO: Optimize single case, and single+default case
+ ResolveStringSwitchMap (ec);
}
- return ok;
+ return true;
}
-
+
+ void ResolveStringSwitchMap (EmitContext 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 (
+ 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,
+ 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);
+
+ ArrayList init = new ArrayList ();
+ int counter = 0;
+ Elements.Clear ();
+ string value = null;
+ foreach (SwitchSection section in Sections) {
+ foreach (SwitchLabel sl in section.Labels) {
+ if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
+ value = null;
+ continue;
+ }
+
+ value = (string) sl.Converted;
+ ArrayList init_args = new ArrayList (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)
+ continue;
+
+ Elements.Add (counter, section.Labels [0]);
+ ++counter;
+ }
+
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (new IntConstant (Sections.Count, loc)));
+ Expression initializer = new NewInitialize (string_dictionary_type, args,
+ new CollectionOrObjectInitializers (init, loc), loc);
+
+ switch_cache_field = new FieldExpr (field.FieldBuilder, 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 ();
+
+ //
+ // Skip initialization when value is null
+ //
+ value.EmitBranchable (ec, null_target, false);
+
+ //
+ // Check if string dictionary is initialized and initialize
+ //
+ switch_cache_field.EmitBranchable (ec, l_initialized, true);
+ string_dictionary.EmitStatement (ec);
+ ig.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;
+
+ //
+ // 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);
+
+ Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
+ 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);
+
+ ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
+ new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (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;
null_target = ig.DefineLabel ();
// Store variable for comparission purposes
- LocalBuilder value;
+ // TODO: Don't duplicate non-captured VariableReference
+ LocalTemporary value;
if (HaveUnwrap) {
- value = ig.DeclareLocal (SwitchType);
+ value = new LocalTemporary (SwitchType);
#if GMCS_SOURCE
unwrap.EmitCheck (ec);
ig.Emit (OpCodes.Brfalse, null_target);
new_expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, value);
+ value.Store (ec);
#endif
} else if (!is_constant) {
- value = ig.DeclareLocal (SwitchType);
+ value = new LocalTemporary (SwitchType);
new_expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, value);
+ value.Store (ec);
} else
value = null;
if (is_constant) {
if (constant_section != null)
constant_section.Block.Emit (ec);
- } else if (SwitchType == TypeManager.string_type)
- SimpleSwitchEmit (ec, value);
- else
+ } else if (string_dictionary != null) {
+ DoEmitStringSwitch (value, ec);
+ } else {
TableSwitchEmit (ec, value);
+ }
+
+ if (value != null)
+ value.Release (ec);
// Restore context state.
ig.MarkLabel (ec.LoopEnd);
ArrayList resume_points;
int first_resume_pc;
- public void AddResumePoint (ResumableStatement stmt, Location loc, int pc)
+ public void AddResumePoint (ResumableStatement stmt, int pc)
{
if (resume_points == null) {
resume_points = new ArrayList ();
if (expr == null)
return false;
- if (expr.Type.IsValueType){
+ if (!TypeManager.IsReferenceType (expr.Type)){
Report.Error (185, loc,
"`{0}' is not a reference type as required by the lock statement",
TypeManager.CSharpName (expr.Type));
}
}
- 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;
- }
-
- 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);
- }
-
- ILGenerator ig = ec.ig;
-
- 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);
- }
- }
-
- LocalBuilder pinned_string;
- Location loc;
+ class StringEmitter : Emitter
+ {
+ LocalInfo pinned_string;
public StringEmitter (Expression expr, LocalInfo li, Location loc):
base (expr, li)
{
- this.loc = loc;
+ pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
+ pinned_string.Pinned = true;
}
public override void Emit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
-
+ pinned_string.Resolve (ec);
+ 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;
+ PropertyInfo p = TypeManager.int_get_offset_to_string_data;
+ if (p == null) {
+ // TODO: Move to resolve
+ p = TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
+ TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
- converted.Emit (ec);
+ if (p == null)
+ return;
+ }
+
+ // TODO: Should use Binary::Add
+ pinned_string.Emit (ec);
+ ec.ig.Emit (OpCodes.Conv_I);
+
+ PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, p, pinned_string.Location);
+ //pe.InstanceExpression = pinned_string;
+ pe.Resolve (ec).Emit (ec);
+
+ ec.ig.Emit (OpCodes.Add);
vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Ldnull);
- ec.ig.Emit (OpCodes.Stloc, pinned_string);
+ pinned_string.EmitAssign (ec);
}
}
Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
return false;
}
-
- //
- // Case 1: & object.
- //
- if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
- Expression child = ((Unary) e).Expr;
-
- if (child is ParameterReference || child is LocalVariableReference){
- Report.Error (
- 213, loc,
- "No need to use fixed statement for parameters or " +
- "local variable declarations (address is already " +
- "fixed)");
- return false;
- }
-
- ec.InFixedInitializer = true;
- e = e.Resolve (ec);
- ec.InFixedInitializer = false;
- if (e == null)
- return false;
-
- child = ((Unary) e).Expr;
-
- if (!TypeManager.VerifyUnManaged (child.Type, loc))
- return false;
-
- if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
- e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
- return false;
- }
-
- data [i] = new ExpressionEmitter (e, vi);
- i++;
-
- continue;
- }
ec.InFixedInitializer = true;
e = e.Resolve (ec);
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))),
- NullPointer.Null,
+ new NullPointer (loc),
converted);
converted = converted.Resolve (ec);
}
// Case 4: fixed buffer
- FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr;
- if (fixed_buffer_ptr != null) {
- data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi);
+ if (e is FixedBufferPtr) {
+ data [i++] = new ExpressionEmitter (e, vi);
continue;
}
//
- // For other cases, flag a `this is already fixed expression'
+ // Case 1: & object.
//
- if (e is LocalVariableReference || e is ParameterReference ||
- Convert.ImplicitConversionExists (ec, e, vi.VariableType)){
-
- Report.Error (245, loc, "right hand expression is already fixed, no need to use fixed statement ");
- return false;
+ Unary u = e as Unary;
+ if (u != null && u.Oper == Unary.Operator.AddressOf) {
+ IVariableReference vr = u.Expr as IVariableReference;
+ if (vr == null || !vr.IsFixed) {
+ data [i] = new ExpressionEmitter (e, vi);
+ }
}
- Report.Error (245, loc, "Fixed statement only allowed on strings, arrays or address-of expressions");
- return false;
+ if (data [i++] == null)
+ 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);
}
ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
Type 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);
+ 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;
}
}
}
}
+ // FIXME: Why is it almost exact copy of Using ??
public class UsingTemporary : ExceptionStatement {
TemporaryVariable local_copy;
public Statement Statement;
protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
- if (!expr_type.IsValueType) {
+ if (!TypeManager.IsStruct (expr_type)) {
Label skip = ig.DefineLabel ();
local_copy.Emit (ec);
ig.Emit (OpCodes.Brfalse, skip);
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)
{
Report.SymbolRelatedToPreviousError (expr.Type);
protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
+ Label skip = ig.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;
+ Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, new ArrayList (0), loc);
- mloc.AddressOf (ec, AddressOp.Load);
- ig.Emit (OpCodes.Call, mi);
- }
- }
+ if (emit_null_check)
+ ig.MarkLabel (skip);
}
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
return ok;
}
+ bool ResolveVariable (EmitContext ec)
+ {
+ assign = new SimpleAssign (var, init, loc);
+ assign = assign.ResolveStatement (ec);
+ if (assign == null)
+ return false;
+
+ if (assign.Type == TypeManager.idisposable_type ||
+ TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) {
+ return true;
+ }
+
+ Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
+ if (e == null) {
+ Error_IsNotConvertibleToIDisposable (var);
+ return false;
+ }
+
+ throw new NotImplementedException ("covariance?");
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Using target = (Using) t;
/// Implementation of the foreach C# statement
/// </summary>
public class Foreach : Statement {
- Expression type;
- Expression variable;
- Expression expr;
- Statement statement;
-
- public Foreach (Expression type, LocalVariableReference var, Expression expr,
- Statement stmt, Location l)
- {
- this.type = type;
- this.variable = var;
- this.expr = expr;
- statement = stmt;
- loc = l;
- }
-
- public Statement Statement {
- get { return statement; }
- }
- public override bool Resolve (EmitContext ec)
+ sealed class ArrayForeach : Statement
{
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
+ class ArrayCounter : TemporaryVariable
+ {
+ StatementExpression increment;
- if (expr.IsNull) {
- Report.Error (186, loc, "Use of null is not valid in this context");
- return false;
- }
+ public ArrayCounter (Location loc)
+ : base (TypeManager.int32_type, loc)
+ {
+ }
- if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
- Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
- expr.ExprClassName);
- return false;
- }
+ public void ResolveIncrement (EmitContext ec)
+ {
+ increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this));
+ increment.Resolve (ec);
+ }
- if (expr.Type.IsArray) {
- statement = new ArrayForeach (type, variable, expr, statement, loc);
- } else {
- statement = new CollectionForeach (type, variable, expr, statement, loc);
+ public void EmitIncrement (EmitContext ec)
+ {
+ increment.Emit (ec);
+ }
}
-
- return statement.Resolve (ec);
- }
- 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 ();
+ readonly Foreach for_each;
+ readonly Statement statement;
- statement.Emit (ec);
-
- ec.LoopBegin = old_begin;
- ec.LoopEnd = old_end;
- }
+ Expression conv;
+ TemporaryVariable[] lengths;
+ Expression [] length_exprs;
+ ArrayCounter[] counter;
- protected class ArrayCounter : TemporaryVariable
- {
- StatementExpression increment;
+ TemporaryVariable copy;
+ Expression access;
- public ArrayCounter (Location loc)
- : base (TypeManager.int32_type, loc)
+ public ArrayForeach (Foreach @foreach, int rank)
{
- }
+ for_each = @foreach;
+ statement = for_each.statement;
+ loc = @foreach.loc;
- public void ResolveIncrement (EmitContext ec)
- {
- increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
- increment.Resolve (ec);
- }
+ counter = new ArrayCounter [rank];
+ length_exprs = new Expression [rank];
- public void EmitIncrement (EmitContext ec)
- {
- increment.Emit (ec);
+ //
+ // Only use temporary length variables when dealing with
+ // multi-dimensional arrays
+ //
+ if (rank > 1)
+ lengths = new TemporaryVariable [rank];
}
- }
- protected class ArrayForeach : Statement
- {
- Expression variable, expr, conv;
- Statement statement;
- Type array_type;
- Expression var_type;
- TemporaryVariable[] lengths;
- ArrayCounter[] counter;
- int rank;
-
- TemporaryVariable copy;
- Expression access;
- Expression[] length_exprs;
-
- public ArrayForeach (Expression var_type, Expression var,
- Expression expr, Statement stmt, Location l)
+ protected override void CloneTo (CloneContext clonectx, Statement target)
{
- this.var_type = var_type;
- this.variable = var;
- this.expr = expr;
- statement = stmt;
- loc = l;
+ throw new NotImplementedException ();
}
public override bool Resolve (EmitContext ec)
{
- array_type = expr.Type;
- rank = array_type.GetArrayRank ();
-
- copy = new TemporaryVariable (array_type, loc);
+ copy = new TemporaryVariable (for_each.expr.Type, loc);
copy.Resolve (ec);
- counter = new ArrayCounter [rank];
- lengths = new TemporaryVariable [rank];
- length_exprs = new Expression [rank];
-
+ int rank = length_exprs.Length;
ArrayList list = new ArrayList (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);
-
if (rank == 1) {
length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
} else {
+ lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
+ lengths [i].Resolve (ec);
+
ArrayList args = new ArrayList (1);
args.Add (new Argument (new IntConstant (i, loc)));
length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
if (access == null)
return false;
+ Expression var_type = for_each.type;
VarExpr ve = var_type as VarExpr;
if (ve != null) {
// Infer implicitly typed local variable from foreach array type
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling ();
- variable = variable.ResolveLValue (ec, conv, loc);
- if (variable == null)
+ for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
+ if (for_each.variable == null)
ok = false;
ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
{
ILGenerator ig = ec.ig;
- copy.EmitAssign (ec, expr);
+ copy.EmitAssign (ec, for_each.expr);
+ int rank = length_exprs.Length;
Label[] test = new Label [rank];
Label[] loop = new Label [rank];
test [i] = ig.DefineLabel ();
loop [i] = ig.DefineLabel ();
- lengths [i].EmitAssign (ec, length_exprs [i]);
+ if (lengths != null)
+ lengths [i].EmitAssign (ec, length_exprs [i]);
}
IntConstant zero = new IntConstant (0, loc);
ig.MarkLabel (loop [i]);
}
- ((IAssignMethod) variable).EmitAssign (ec, conv, false, false);
+ ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
statement.Emit (ec);
ig.MarkLabel (test [i]);
counter [i].Emit (ec);
- lengths [i].Emit (ec);
+
+ if (lengths != null)
+ lengths [i].Emit (ec);
+ else
+ length_exprs [i].Emit (ec);
+
ig.Emit (OpCodes.Blt, loop [i]);
}
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
+ for_each.expr.MutateHoistedGenericType (storey);
+
copy.MutateHoistedGenericType (storey);
conv.MutateHoistedGenericType (storey);
- variable.MutateHoistedGenericType (storey);
statement.MutateHoistedGenericType (storey);
- for (int i = 0; i < rank; i++) {
+ for (int i = 0; i < counter.Length; i++) {
counter [i].MutateHoistedGenericType (storey);
- lengths [i].MutateHoistedGenericType (storey);
+ if (lengths != null)
+ lengths [i].MutateHoistedGenericType (storey);
}
}
}
- protected class CollectionForeach : Statement
+ sealed class CollectionForeach : Statement
{
+ class CollectionForeachStatement : Statement
+ {
+ Type type;
+ Expression variable, current, conv;
+ Statement statement;
+ Assign assign;
+
+ public CollectionForeachStatement (Type type, Expression variable,
+ Expression current, Statement statement,
+ Location loc)
+ {
+ this.type = type;
+ this.variable = variable;
+ this.current = current;
+ this.statement = statement;
+ this.loc = loc;
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ current = current.Resolve (ec);
+ if (current == null)
+ return false;
+
+ conv = Convert.ExplicitConversion (ec, current, type, loc);
+ if (conv == null)
+ return false;
+
+ assign = new SimpleAssign (variable, conv, loc);
+ if (assign.Resolve (ec) == null)
+ return false;
+
+ if (!statement.Resolve (ec))
+ return false;
+
+ return true;
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ assign.EmitStatement (ec);
+ statement.Emit (ec);
+ }
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ assign.MutateHoistedGenericType (storey);
+ statement.MutateHoistedGenericType (storey);
+ }
+ }
+
Expression variable, expr;
Statement statement;
loc = l;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
{
Type return_type = mi.ReturnType;
- if ((return_type == TypeManager.ienumerator_type) && (mi.DeclaringType == TypeManager.string_type))
- //
- // Apply the same optimization as MS: skip the GetEnumerator
- // returning an IEnumerator, and use the one returning a
- // CharEnumerator instead. This allows us to avoid the
- // try-finally block and the boxing.
- //
- return false;
-
//
// Ok, we can access it, now make sure that we can do something
// with this `GetEnumerator'
//
if (return_type == TypeManager.ienumerator_type ||
- TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
- (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+ TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) {
//
// If it is not an interface, lets try to find the methods ourselves.
// For example, if we have:
//
bool FetchMoveNext (Type t)
{
- MemberList move_next_list;
-
- move_next_list = TypeContainer.FindMembers (
- t, MemberTypes.Method,
+ MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t,
+ MemberTypes.Method,
BindingFlags.Public | BindingFlags.Instance,
- Type.FilterName, "MoveNext");
- if (move_next_list.Count == 0)
- return false;
+ "MoveNext", null);
foreach (MemberInfo m in move_next_list){
MethodInfo mi = (MethodInfo) m;
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 ()
{
if (enumerator_found) {
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
loop = new While (move_next_expr, block, loc);
- wrapper = is_disposable ?
- (Statement) new DisposableWrapper (this) :
- (Statement) new NonDisposableWrapper (this);
+
+ bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
+ if (implements_idisposable || !enumerator_type.IsSealed) {
+ wrapper = new DisposableWrapper (this, implements_idisposable);
+ } else {
+ wrapper = new NonDisposableWrapper (this);
+ }
+
return wrapper.Resolve (ec);
}
this.parent = parent;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
return parent.ResolveLoop (ec);
}
}
- 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)
protected override void EmitFinallyBody (EmitContext ec)
{
- parent.EmitFinallyBody (ec);
+ Expression instance = parent.enumerator;
+ if (!TypeManager.IsValueType (parent.enumerator_type)) {
+ ILGenerator ig = ec.ig;
+
+ parent.enumerator.Emit (ec);
+
+ Label call_dispose = ig.DefineLabel ();
+
+ if (!implements_idisposable) {
+ ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
+ LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
+ temp.Store (ec);
+ temp.Emit (ec);
+ instance = temp;
+ }
+
+ ig.Emit (OpCodes.Brtrue_S, call_dispose);
+
+ // using 'endfinally' to empty the evaluation stack
+ ig.Emit (OpCodes.Endfinally);
+ ig.MarkLabel (call_dispose);
+ }
+
+ Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, new ArrayList (0), loc);
}
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
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);
}
}
- protected class CollectionForeachStatement : Statement
+ Expression type;
+ Expression variable;
+ Expression expr;
+ Statement statement;
+
+ public Foreach (Expression type, LocalVariableReference var, Expression expr,
+ Statement stmt, Location l)
{
- Type type;
- Expression variable, current, conv;
- Statement statement;
- Assign assign;
+ this.type = type;
+ this.variable = var;
+ this.expr = expr;
+ statement = stmt;
+ loc = l;
+ }
- public CollectionForeachStatement (Type type, Expression variable,
- Expression current, Statement statement,
- Location loc)
- {
- this.type = type;
- this.variable = variable;
- this.current = current;
- this.statement = statement;
- this.loc = loc;
+ public Statement Statement {
+ get { return statement; }
+ }
+
+ public override bool Resolve (EmitContext 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");
+ return false;
}
- public override bool Resolve (EmitContext ec)
- {
- current = current.Resolve (ec);
- if (current == null)
+ 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.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
+ Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
+ expr.ExprClassName);
return false;
+ }
- conv = Convert.ExplicitConversion (ec, current, type, loc);
- if (conv == null)
- return false;
+ statement = new CollectionForeach (type, variable, expr, statement, loc);
+ }
- assign = new SimpleAssign (variable, conv, loc);
- if (assign.Resolve (ec) == null)
- return false;
+ return statement.Resolve (ec);
+ }
- if (!statement.Resolve (ec))
- return false;
+ protected override void DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
- return true;
- }
+ Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
- protected override void DoEmit (EmitContext ec)
- {
- assign.EmitStatement (ec);
- statement.Emit (ec);
- }
+ statement.Emit (ec);
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- assign.MutateHoistedGenericType (storey);
- statement.MutateHoistedGenericType (storey);
- }
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
}
protected override void CloneTo (CloneContext clonectx, Statement t)