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;
}
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;
// 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
BlockUsed = 2,
VariablesInitialized = 4,
HasRet = 8,
- IsDestructor = 16,
- Unsafe = 32,
- IsIterator = 64,
- HasStoreyAccess = 128
+ Unsafe = 16,
+ IsIterator = 32,
+ HasCapturedVariable = 64,
+ HasCapturedThis = 128
}
protected Flags flags;
// Keeps track of (name, type) pairs
//
IDictionary variables;
- protected IDictionary range_variables;
//
// Keeps track of constants
//
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) {
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 (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type)
- Error_AlreadyDeclared (l, name);
- else
- Error_AlreadyDeclared (l, name, null);
+ Error_AlreadyDeclared (l, name, null);
} else {
- Error_AlreadyDeclared (l, name, "parent");
+ Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
+ "parent or current" : "parent");
}
- return null;
+ return false;
}
- ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name);
- if (pi != null) {
- Report.SymbolRelatedToPreviousError (pi.Location, name);
- Error_AlreadyDeclared (loc, name,
- pi.Block == Toplevel ? "method argument" : "parent or current");
- return null;
+ if (block != null) {
+ Expression e = block.GetParameterReference (name, Location.Null);
+ if (e != null) {
+ ParameterReference pr = e as ParameterReference;
+ if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
+ Error_AlreadyDeclared (loc, name);
+ else
+ Error_AlreadyDeclared (loc, name, "parent or current");
+ return false;
+ }
}
-
+
+ return true;
+ }
+
+ public LocalInfo AddVariable (Expression type, string name, Location l)
+ {
+ if (!CheckParentConflictName (Toplevel, name, l))
+ return null;
+
if (Toplevel.GenericMethod != null) {
foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
if (tp.Name == name) {
Report.SymbolRelatedToPreviousError (tp);
- Error_AlreadyDeclaredTypeParameter (loc, name);
+ 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)
{
if (ret != null)
return ret;
}
-
- if (b.range_variables != null) {
- ret = (LocalInfo) b.range_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 {
// TODO: Re-enable
Block prev_block = ec.CurrentBlock;
ec.CurrentBlock = this;
- if (scope_initializers != null) {
- SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
-
- using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
- foreach (StatementExpression s in scope_initializers)
- s.Emit (ec);
- }
-
- SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
- }
+ if (scope_initializers != null)
+ EmitScopeInitializers (ec);
ec.Mark (StartLocation);
DoEmit (ec);
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) {
// 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 && Parent != null && !(am_storey is IteratorStorey);
if (emit_debug_info)
//
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;
+
+ //
+ // Hoisted this exists in top-level parent storey only
+ //
+ while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
+ parent = parent.Parent.Explicit;
+
+ am_storey.AddParentStoreyReference (parent.am_storey);
+ }
+
am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
}
am_storey.DefineType ();
- am_storey.ResolveType ();
+ 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);
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);
-
- //
- // Discard an anonymous method storey when this block has no hoisted variables
- //
- if (am_storey != null && !am_storey.HasHoistedVariables) {
- am_storey.Undo ();
- am_storey = null;
- }
-
- 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)
// 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 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; }
}
- 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);
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)
{
- if (statements.Count == 1)
- return ((Statement) statements [0]).CreateExpressionTree (ec);
+ if (statements.Count == 1) {
+ Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
+ if (scope_initializers != null)
+ expr = new BlockScopeExpression (expr, this);
+
+ return expr;
+ }
return base.CreateExpressionTree (ec);
}
//
public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
{
- // Create block with original statements
- ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
IsIterator = true;
- // TODO: Change to iter_block.statements = statements;
- foreach (Statement stmt in source.statements)
- iter_block.AddStatement (stmt);
- labels = source.labels;
-
- AddStatement (new IteratorStatement (iterator, iter_block));
+ // Creates block with original statements
+ AddStatement (new IteratorStatement (iterator, new Block (this, source)));
source.statements = new ArrayList (1);
source.AddStatement (new Return (iterator, iterator.Location));
}
//
- // 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)
+ public Expression GetParameterReference (string name, Location loc)
{
- ToplevelParameterInfo p = GetParameterInfo (name);
- return p == null ? null : new ParameterReference (this, p, loc);
- }
-
- public ToplevelParameterInfo GetParameterInfo (string name)
- {
- 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 == 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;
FieldExpr switch_cache_field;
static int unique_counter;
-#if GMCS_SOURCE
//
- // Nullable Types support for GMCS.
+ // Nullable Types support
//
Nullable.Unwrap unwrap;
protected bool HaveUnwrap {
get { return unwrap != null; }
}
-#else
- protected bool HaveUnwrap {
- get { return false; }
- }
-#endif
//
// The types allowed to be implicitly cast from
public static void Reset ()
{
unique_counter = 0;
+ allowed_types = null;
}
public override bool Resolve (EmitContext ec)
new_expr = SwitchGoverningType (ec, Expr);
-#if GMCS_SOURCE
if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
- unwrap = Nullable.Unwrap.Create (Expr, ec);
+ unwrap = Nullable.Unwrap.Create (Expr, false);
if (unwrap == null)
return false;
new_expr = SwitchGoverningType (ec, unwrap);
}
-#endif
if (new_expr == null){
- Report.Error (151, loc, "A value of an integral type or string expected for switch");
+ Report.Error (151, loc,
+ "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
+ TypeManager.CSharpName (Expr.Type));
return false;
}
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 (loc,
- new TypeExpression (TypeManager.string_type, loc),
- new TypeExpression (TypeManager.int32_type, loc)), loc);
-#else
- MemberAccess system_collections_generic = new MemberAccess (
- new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
-
- string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
-#endif
+ if (TypeManager.generic_ienumerable_type != null) {
+ MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
+ new TypeArguments (
+ new TypeExpression (TypeManager.string_type, loc),
+ new TypeExpression (TypeManager.int32_type, loc)), loc);
+ } else {
+ MemberAccess system_collections_generic = new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
+ }
+
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);
Elements.Clear ();
string value = null;
foreach (SwitchSection section in Sections) {
+ int last_count = init.Count;
foreach (SwitchLabel sl in section.Labels) {
- if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
- value = null;
+ if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase)
continue;
- }
value = (string) sl.Converted;
ArrayList init_args = new ArrayList (2);
init.Add (new CollectionElementInitializer (init_args, loc));
}
- if (value == null)
+ //
+ // Don't add empty sections
+ //
+ if (last_count == init.Count)
continue;
Elements.Add (counter, section.Labels [0]);
++counter;
}
- ArrayList args = new ArrayList (1);
- args.Add (new Argument (new IntConstant (Sections.Count, loc)));
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (new IntConstant (init.Count, loc)));
Expression initializer = new NewInitialize (string_dictionary_type, args,
new CollectionOrObjectInitializers (init, loc), loc);
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;
+ if (TypeManager.generic_ienumerable_type != null) {
+ Arguments get_value_args = new Arguments (2);
+ get_value_args.Add (new Argument (value));
+ get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
+ Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (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);
+ //
+ // A value was not found, go to default case
+ //
+ get_item.EmitBranchable (ec, default_target, false);
+ } else {
+ Arguments get_value_args = new Arguments (1);
+ get_value_args.Add (new Argument (value));
- Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
- if (get_item == null)
- return;
+ Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
+ if (get_item == null)
+ return;
- LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
- get_item_object.EmitAssign (ec, get_item, true, false);
- ec.ig.Emit (OpCodes.Brfalse, default_target);
+ LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
+ get_item_object.EmitAssign (ec, get_item, true, false);
+ ec.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);
+ 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);
+ }
- get_item_int.EmitStatement (ec);
- get_item_object.Release (ec);
-#endif
TableSwitchEmit (ec, string_switch_variable);
string_switch_variable.Release (ec);
}
LocalTemporary value;
if (HaveUnwrap) {
value = new LocalTemporary (SwitchType);
-#if GMCS_SOURCE
unwrap.EmitCheck (ec);
ig.Emit (OpCodes.Brfalse, null_target);
new_expr.Emit (ec);
value.Store (ec);
-#endif
} else if (!is_constant) {
value = new LocalTemporary (SwitchType);
new_expr.Emit (ec);
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);
}
}
// TODO: Move to resolve
LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
lvr.Resolve (ec);
+
+#if GMCS_SOURCE
+ // Only to make verifier happy
+ if (TypeManager.IsGenericParameter (lvr.Type))
+ ig.Emit (OpCodes.Unbox_Any, lvr.Type);
+#endif
Expression source;
if (lvr.IsHoisted) {
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;
}
}
if (General != null) {
if (CodeGen.Assembly.WrapNonExceptionThrows) {
foreach (Catch c in Specific){
- if (c.CatchType == TypeManager.exception_type) {
+ if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
}
}
}
}
+ // 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, null, 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;
copy.Resolve (ec);
int rank = length_exprs.Length;
- ArrayList list = new ArrayList (rank);
+ Arguments list = new Arguments (rank);
for (int i = 0; i < rank; i++) {
counter [i] = new ArrayCounter (loc);
counter [i].ResolveIncrement (ec);
lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
lengths [i].Resolve (ec);
- ArrayList args = new ArrayList (1);
+ Arguments args = new Arguments (1);
args.Add (new Argument (new IntConstant (i, loc)));
length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
}
- list.Add (counter [i]);
+ list.Add (new Argument (counter [i]));
}
access = new ElementAccess (copy, list).Resolve (ec);
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling ();
- for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
+ for_each.variable = for_each.variable.ResolveLValue (ec, conv);
if (for_each.variable == null)
ok = false;
//
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:
TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
}
-#if GMCS_SOURCE
//
// Prefer a generic enumerator over a non-generic one.
//
- if (return_type.IsInterface && return_type.IsGenericType) {
+ if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
enumerator_type = return_type;
if (!FetchGetCurrent (ec, return_type))
get_current = new PropertyExpr (
move_next = TypeManager.bool_movenext_void;
return true;
}
-#endif
if (return_type.IsInterface ||
!FetchMoveNext (return_type) ||
//
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);
}
}
}
- 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)
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, null, 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);