// 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)
{
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 ec.CurrentBranching.CheckRethrow (loc);
}
- expr = expr.Resolve (ec);
+ expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
ec.CurrentBranching.CurrentUsageVector.Goto ();
if (expr == null)
return false;
- ExprClass eclass = expr.eclass;
-
- 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);
- return false;
- }
-
Type t = expr.Type;
if ((t != TypeManager.exception_type) &&
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 ();
}
/// </remarks>
public class Block : Statement {
public Block Parent;
- public readonly Location StartLocation;
+ public Location StartLocation;
public Location EndLocation = Location.Null;
public ExplicitBlock Explicit;
HasRet = 8,
IsDestructor = 16,
Unsafe = 32,
- IsIterator = 64
+ IsIterator = 64,
+ HasStoreyAccess = 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 {
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;
}
// 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 (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;
+ using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
+ foreach (StatementExpression s in scope_initializers)
+ s.Emit (ec);
+ }
SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
}
{
MutateVariables (storey);
+ if (scope_initializers != null) {
+ foreach (Statement s in scope_initializers)
+ s.MutateHoistedGenericType (storey);
+ }
+
foreach (Statement s in statements)
s.MutateHoistedGenericType (storey);
}
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) {
+ am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
+ }
- protected override void EmitSymbolInfo (EmitContext ec)
- {
- if (am_storey != null)
- SymbolWriter.DefineScopeVariable (am_storey.ID);
+ am_storey.DefineType ();
+ am_storey.ResolveType ();
+ am_storey.Define ();
+ am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+ }
- base.EmitSymbolInfo (ec);
+ base.EmitMeta (ec);
}
internal IKnownVariable GetKnownVariable (string name)
bool ok = base.Resolve (ec);
//
- // Define an anonymous method storey when this block has hoisted variables
- // otherwise the storey can be discarded
+ // Discard an anonymous method storey when this block has no hoisted variables
//
- if (am_storey != null) {
- if (am_storey.HasHoistedVariables) {
- am_storey.DefineType ();
- am_storey.DefineMembers ();
- am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
- } else {
- am_storey.Undo ();
- am_storey = null;
- }
+ if (am_storey != null && !am_storey.HasHoistedVariables) {
+ am_storey.Undo ();
+ am_storey = null;
}
return ok;
public Parameter Parameter {
get { return Block.Parameters [Index]; }
}
+
+ public Type ParameterType {
+ get { return Block.Parameters.Types [Index]; }
+ }
+
public Location Location {
get { return Parameter.Location; }
}
get { return generic; }
}
+ public bool HasStoreyAccess {
+ set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; }
+ get { return (flags & Flags.HasStoreyAccess) != 0; }
+ }
+
public ToplevelBlock Container {
get { return Parent == null ? null : Parent.Toplevel; }
}
if (parent != null)
parent.AddAnonymousChild (this);
- if (!this.parameters.Empty)
+ if (!this.parameters.IsEmpty)
ProcessParameters ();
}
public override Expression CreateExpressionTree (EmitContext ec)
{
- return ((Statement) statements [0]).CreateExpressionTree (ec);
+ if (statements.Count == 1)
+ return ((Statement) statements [0]).CreateExpressionTree (ec);
+
+ return base.CreateExpressionTree (ec);
}
//
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);
}
}
+ 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;
+ }
+
public override bool Resolve (EmitContext ec)
{
Expr = Expr.Resolve (ec);
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)
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);
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);
/// 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'
this.parent = parent;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
return parent.ResolveLoop (ec);
this.parent = parent;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
bool ok = true;
}
}
- 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)