public Statement Clone (CloneContext clonectx)
{
Statement s = (Statement) this.MemberwiseClone ();
- if (s is Block)
- clonectx.AddBlockMap ((Block) this, (Block) s);
-
CloneTo (clonectx, s);
return s;
}
public abstract void EmitAddressOf (EmitContext ec);
}
+ public interface IKnownVariable {
+ Block Block { get; }
+ Location Location { get; }
+ }
+
//
// The information about a user-perceived local variable
//
- public class LocalInfo {
+ public class LocalInfo : IKnownVariable {
public Expression Type;
public Type VariableType;
public bool Resolve (EmitContext ec)
{
if (VariableType == null) {
- TypeExpr texpr = Type.ResolveAsTypeTerminal (ec, false);
+ TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
if (texpr == null)
return false;
}
public bool IsCaptured {
- get {
- return (flags & Flags.Captured) != 0;
- }
-
- set {
- flags |= Flags.Captured;
- }
+ get { return (flags & Flags.Captured) != 0; }
+ set { flags |= Flags.Captured; }
}
public bool IsConstant {
- get {
- return (flags & Flags.IsConstant) != 0;
- }
- set {
- flags |= Flags.IsConstant;
- }
+ get { return (flags & Flags.IsConstant) != 0; }
+ set { flags |= Flags.IsConstant; }
}
public bool AddressTaken {
- get {
- return (flags & Flags.AddressTaken) != 0;
- }
-
- set {
- flags |= Flags.AddressTaken;
- }
+ get { return (flags & Flags.AddressTaken) != 0; }
+ set { flags |= Flags.AddressTaken; }
}
public bool CompilerGenerated {
- get {
- return (flags & Flags.CompilerGenerated) != 0;
- }
-
- set {
- flags |= Flags.CompilerGenerated;
- }
+ get { return (flags & Flags.CompilerGenerated) != 0; }
+ set { flags |= Flags.CompilerGenerated; }
}
public override string ToString ()
}
public bool Used {
- get {
- return (flags & Flags.Used) != 0;
- }
- set {
- flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used));
- }
+ get { return (flags & Flags.Used) != 0; }
+ set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
}
public bool ReadOnly {
- get {
- return (flags & Flags.ReadOnly) != 0;
- }
+ get { return (flags & Flags.ReadOnly) != 0; }
}
public void SetReadOnlyContext (ReadOnlyContext context)
// allocated in a pinned slot with DeclareLocal.
//
public bool Pinned {
- get {
- return (flags & Flags.Pinned) != 0;
- }
- set {
- flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned);
- }
+ get { return (flags & Flags.Pinned) != 0; }
+ set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
}
public bool IsThis {
- get {
- return (flags & Flags.IsThis) != 0;
- }
- set {
- flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis);
- }
+ get { return (flags & Flags.IsThis) != 0; }
+ set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
+ }
+
+ Block IKnownVariable.Block {
+ get { return Block; }
+ }
+
+ Location IKnownVariable.Location {
+ get { return Location; }
}
protected class LocalVariable : Variable
public ToplevelBlock Toplevel;
[Flags]
- public enum Flags : ushort {
- IsExplicit = 1,
- Unchecked = 2,
- BlockUsed = 4,
- VariablesInitialized = 8,
- HasRet = 16,
- IsDestructor = 32,
- IsToplevel = 64,
- Unsafe = 128,
- HasVarargs = 256, // Used in ToplevelBlock
- IsIterator = 512
-
+ public enum Flags : byte {
+ Unchecked = 1,
+ BlockUsed = 2,
+ VariablesInitialized = 4,
+ HasRet = 8,
+ IsDestructor = 16,
+ Unsafe = 32,
+ HasVarargs = 64, // Used in ToplevelBlock
+ IsIterator = 128
}
protected Flags flags;
- public bool Implicit {
- get { return (flags & Flags.IsExplicit) == 0; }
- }
-
public bool Unchecked {
get { return (flags & Flags.Unchecked) != 0; }
set { flags |= Flags.Unchecked; }
public Block (Block parent, Flags flags, Location start, Location end)
{
- if (parent != null)
+ if (parent != null) {
parent.AddChild (this);
+
+ // the appropriate constructors will fixup these fields
+ Toplevel = parent.Toplevel;
+ Explicit = parent.Explicit;
+ }
this.Parent = parent;
this.flags = flags;
this.loc = start;
this_id = id++;
statements = new ArrayList ();
-
- if ((flags & Flags.IsToplevel) != 0)
- Toplevel = (ToplevelBlock) this;
- else
- Toplevel = parent.Toplevel;
-
- if ((flags & Flags.IsExplicit) != 0)
- Explicit = (ExplicitBlock) this;
- else
- Explicit = parent.Explicit;
}
public Block CreateSwitchBlock (Location start)
return false;
}
- if (!Implicit)
+ if (this == Explicit)
break;
cur = cur.Parent;
return null;
foreach (Block child in children) {
- if (!child.Implicit)
+ if (Explicit != child.Explicit)
continue;
s = child.LookupLabel (name);
public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
{
Block b = this;
- LocalInfo kvi = b.Explicit.GetKnownVariableInfo (name, true);
+ IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
while (kvi == null) {
b = b.Explicit.Parent;
if (b == null)
return true;
- kvi = b.Explicit.GetKnownVariableInfo (name, true);
+ kvi = b.Explicit.GetKnownVariable (name);
}
if (kvi.Block == b)
// an indirect check that depends on AddVariable doing its
// part in maintaining the invariant-meaning-in-block property.
//
- if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null))
+ if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
return true;
//
return false;
}
- public bool CheckError136_InParents (string name, Location loc)
- {
- for (Block b = Parent; b != null; b = b.Parent) {
- if (!b.DoCheckError136 (name, "parent or current", loc))
- return false;
- }
-
- for (Block b = Toplevel.ContainerBlock; b != null; b = b.Toplevel.ContainerBlock) {
- if (!b.CheckError136_InParents (name, loc))
- return false;
- }
-
- return true;
- }
-
- public bool CheckError136_InChildren (string name, Location loc)
- {
- if (!DoCheckError136_InChildren (name, loc))
- return false;
-
- Block b = this;
- while (b.Implicit) {
- if (!b.Parent.DoCheckError136_InChildren (name, loc))
- return false;
- b = b.Parent;
- }
-
- return true;
- }
-
- protected bool DoCheckError136_InChildren (string name, Location loc)
- {
- if (!DoCheckError136 (name, "child", loc))
- return false;
-
- if (AnonymousChildren != null) {
- foreach (ToplevelBlock child in AnonymousChildren) {
- if (!child.DoCheckError136_InChildren (name, loc))
- return false;
- }
- }
-
- if (children != null) {
- foreach (Block child in children) {
- if (!child.DoCheckError136_InChildren (name, loc))
- return false;
- }
- }
-
- return true;
- }
-
- public bool CheckError136 (string name, string scope, bool check_parents,
- bool check_children, Location loc)
- {
- if (!DoCheckError136 (name, scope, loc))
- return false;
-
- if (check_parents) {
- if (!CheckError136_InParents (name, loc))
- return false;
- }
-
- if (check_children) {
- if (!CheckError136_InChildren (name, loc))
- return false;
- }
-
- for (Block c = Toplevel.ContainerBlock; c != null; c = c.Toplevel.ContainerBlock) {
- if (!c.DoCheckError136 (name, "parent or current", loc))
- return false;
- }
-
- return true;
- }
-
- protected bool DoCheckError136 (string name, string scope, Location loc)
- {
- LocalInfo vi = Explicit.GetKnownVariableInfo (name, false);
- if (vi != null) {
- Report.SymbolRelatedToPreviousError (vi.Location, name);
- Error_AlreadyDeclared (loc, name, scope != null ? scope : "child");
- return false;
- }
-
- int idx;
- Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx);
- if (p != null) {
- Report.SymbolRelatedToPreviousError (p.Location, name);
- Error_AlreadyDeclared (
- loc, name, scope != null ? scope : "method argument");
- return false;
- }
-
- return true;
- }
-
public LocalInfo AddVariable (Expression type, string name, Location l)
{
LocalInfo vi = GetLocalInfo (name);
return null;
}
- if (!CheckError136 (name, null, true, true, l))
+ 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");
+ }
+
+ IKnownVariable kvi = Explicit.GetKnownVariable (name);
+ if (kvi != null) {
+ Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ Error_AlreadyDeclared (l, name, "child");
return null;
+ }
vi = new LocalInfo (type, name, this, l);
Variables.Add (name, vi);
return vi;
}
- void Error_AlreadyDeclared (Location loc, string var, string reason)
+ protected static void Error_AlreadyDeclared (Location loc, string var, string reason)
{
Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
"in this scope because it would give a different meaning " +
// If we're a non-static `struct' constructor which doesn't have an
// initializer, then we must initialize all of the struct's fields.
- if ((flags & Flags.IsToplevel) != 0 &&
- !Toplevel.IsThisAssigned (ec) &&
- !vector.IsUnreachable)
+ if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !vector.IsUnreachable)
ok = false;
if ((labels != null) && (RootContext.WarningLevel >= 2)) {
ec.CurrentBlock = this;
bool emit_debug_info = (CodeGen.SymbolWriter != null);
- bool is_lexical_block = !Implicit && (Parent != null);
+ bool is_lexical_block = this == Explicit && Parent != null;
if (emit_debug_info) {
if (is_lexical_block)
ec.CurrentBlock = prev_block;
}
- //
- // Returns true if we ar ea child of `b'.
- //
- public bool IsChildOf (Block b)
- {
- Block current = this;
-
- do {
- if (current.Parent == b)
- return true;
- current = current.Parent;
- } while (current != null);
- return false;
- }
-
public override string ToString ()
{
return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
{
Block target = (Block) t;
+ clonectx.AddBlockMap (this, target);
+
target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
+ target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
if (Parent != null)
target.Parent = clonectx.LookupBlock (Parent);
}
public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
- : base (parent, flags | Flags.IsExplicit, start, end)
+ : base (parent, flags, start, end)
{
+ this.Explicit = this;
}
Hashtable known_variables;
// If a variable name has been used in a child block, it's illegal to
// declare a variable with the same name in the current block.
// </summary>
- internal void AddKnownVariable (string name, LocalInfo info)
+ internal void AddKnownVariable (string name, IKnownVariable info)
{
if (known_variables == null)
known_variables = new Hashtable ();
Parent.Explicit.AddKnownVariable (name, info);
}
- internal LocalInfo GetKnownVariableInfo (string name, bool recurse)
+ internal IKnownVariable GetKnownVariable (string name)
{
- if (known_variables == null)
- return null;
- LocalInfo vi = (LocalInfo) known_variables [name];
- if (vi == null)
- return null;
- if (!recurse && vi.Block.Explicit != this)
- return null;
- return vi;
+ return known_variables == null ? null : (IKnownVariable) known_variables [name];
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ ExplicitBlock target = (ExplicitBlock) t;
+ target.known_variables = null;
+ base.CloneTo (clonectx, t);
+ }
+ }
+
+ public class ToplevelParameterInfo : IKnownVariable {
+ public readonly ToplevelBlock Block;
+ public readonly int Index;
+ public VariableInfo VariableInfo;
+
+ Block IKnownVariable.Block {
+ get { return Block; }
+ }
+ public Parameter Parameter {
+ get { return Block.Parameters [Index]; }
+ }
+ public Location Location {
+ get { return Parameter.Location; }
+ }
+
+ public ToplevelParameterInfo (ToplevelBlock block, int idx)
+ {
+ this.Block = block;
+ this.Index = idx;
}
}
// Methods was implemented.
//
public class ToplevelBlock : ExplicitBlock {
- //
- // Pointer to the host of this anonymous method, or null
- // if we are the topmost block
- //
- Block container;
GenericMethod generic;
FlowBranchingToplevel top_level_branching;
AnonymousContainer anonymous_container;
public bool CompleteContexts (EmitContext ec)
{
- Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this,
- container, root_scope);
+ Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope);
if (root_scope != null)
root_scope.LinkScopes ();
- if ((container == null) && (root_scope != null)) {
- Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this,
- root_scope);
+ if (Parent == null && root_scope != null) {
+ Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope);
if (root_scope.DefineType () == null)
return false;
}
public ToplevelBlock Container {
- get { return container != null ? container.Toplevel : null; }
- }
-
- public Block ContainerBlock {
- get { return container; }
+ get { return Parent == null ? null : Parent.Toplevel; }
}
public AnonymousContainer AnonymousContainer {
set { anonymous_container = value; }
}
- //
- // Parent is only used by anonymous blocks to link back to their
- // parents
- //
- public ToplevelBlock (Block container, Parameters parameters, Location start) :
- this (container, (Flags) 0, parameters, start)
+ public ToplevelBlock (Block parent, Parameters parameters, Location start) :
+ this (parent, (Flags) 0, parameters, start)
{
}
- public ToplevelBlock (Block container, Parameters parameters, GenericMethod generic,
- Location start) :
- this (container, parameters, start)
+ public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
+ this (parent, parameters, start)
{
this.generic = generic;
}
{
}
- public ToplevelBlock (Block container, Flags flags, Parameters parameters, Location start) :
- base (null, flags | Flags.IsToplevel, start, Location.Null)
+ // 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) :
+ base (null, flags, start, Location.Null)
{
+ this.Toplevel = this;
+
this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
- this.container = container;
+ this.Parent = parent;
+ if (parent != null)
+ parent.AddAnonymousChild (this);
+
+ if (this.parameters.Count != 0)
+ ProcessParameters ();
}
public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
{
}
+ protected override void CloneTo (CloneContext clonectx, Statement t)
+ {
+ ToplevelBlock target = (ToplevelBlock) t;
+ base.CloneTo (clonectx, t);
+
+ if (parameters.Count != 0)
+ target.parameter_info = new ToplevelParameterInfo [parameters.Count];
+ for (int i = 0; i < parameters.Count; ++i)
+ target.parameter_info [i] = new ToplevelParameterInfo (target, i);
+ }
+
public bool CheckError158 (string name, Location loc)
{
if (AnonymousChildren != null) {
return true;
}
+ ToplevelParameterInfo [] parameter_info;
+ void ProcessParameters ()
+ {
+ int n = parameters.Count;
+ parameter_info = new ToplevelParameterInfo [n];
+ for (int i = 0; i < n; ++i) {
+ parameter_info [i] = new ToplevelParameterInfo (this, i);
+
+ string name = parameters [i].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]);
+ }
+
+ // mark this block as "used" so that we create local declarations in a sub-block
+ // FIXME: This appears to uncover a lot of bugs
+ //this.Use ();
+ }
+
bool DoCheckError158 (string name, Location loc)
{
LabeledStatement s = LookupLabel (name);
public void CreateIteratorHost (RootScopeInfo root)
{
- Report.Debug (64, "CREATE ITERATOR HOST", this, root,
- container, root_scope);
+ Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
- if ((container != null) || (root_scope != null))
+ if (Parent != null || root_scope != null)
throw new InternalErrorException ();
scope_info = root_scope = root;
if ((flags & Flags.VariablesInitialized) != 0)
throw new InternalErrorException ("block has already been resolved");
- container = new_parent;
Parent = new_parent;
}
// 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)
{
int idx;
for (ToplevelBlock t = this; t != null; t = t.Container) {
Parameter par = t.Parameters.GetParameterByName (name, out idx);
if (par != null)
- return new ParameterReference (par, this, idx, loc);
+ return t.parameter_info [idx];
}
return null;
}
return this_variable == null || this_variable.IsThisAssigned (ec);
}
- VariableInfo [] param_map;
- public VariableInfo [] ParameterMap {
- get {
- if ((flags & Flags.VariablesInitialized) == 0)
- throw new Exception ("Variables have not been initialized yet");
- return param_map;
- }
- }
-
public bool ResolveMeta (EmitContext ec, Parameters ip)
{
int errors = Report.Errors;
+ int orig_count = parameters.Count;
if (top_level_branching != null)
return true;
if (ip != null)
parameters = ip;
- if (!IsIterator && (container != null) && (parameters != null)) {
- foreach (Parameter p in parameters.FixedParameters) {
- if (!CheckError136_InParents (p.Name, loc))
- return false;
- }
- }
+ // Assert: orig_count != parameter.Count => orig_count == 0
+ if (orig_count != 0 && orig_count != parameters.Count)
+ throw new InternalErrorException ("parameter information mismatch");
int offset = Parent == null ? 0 : Parent.AssignableSlots;
- if (parameters != null) {
- for (int i = 0; i < parameters.Count; ++i) {
- Parameter.Modifier mod = parameters.ParameterModifier (i);
+ for (int i = 0; i < orig_count; ++i) {
+ Parameter.Modifier mod = parameters.ParameterModifier (i);
- if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
- continue;
+ if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
+ continue;
- if (param_map == null)
- param_map = new VariableInfo [parameters.Count];
- param_map [i] = new VariableInfo (ip, i, offset);
- offset += param_map [i].Length;
- }
+ VariableInfo vi = new VariableInfo (ip, i, offset);
+ parameter_info [i].VariableInfo = vi;
+ offset += vi.Length;
}
ResolveMeta (ec, offset);
return Report.Errors == errors;
}
+ // <summary>
+ // Check whether all `out' parameters have been assigned.
+ // </summary>
+ public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
+ {
+ if (vector.IsUnreachable)
+ return;
+
+ int n = parameter_info == null ? 0 : parameter_info.Length;
+
+ for (int i = 0; i < n; i++) {
+ VariableInfo var = parameter_info [i].VariableInfo;
+
+ if (var == null)
+ continue;
+
+ if (vector.IsAssigned (var, false))
+ continue;
+
+ Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
+ var.Name);
+ }
+ }
+
public override void EmitMeta (EmitContext ec)
{
base.EmitMeta (ec);
if (!fFoundDefault) {
ig.MarkLabel (lblDefault);
+ if (HaveUnwrap && !fFoundNull) {
+ ig.MarkLabel (null_target);
+ }
}
+
ig.MarkLabel (lblEnd);
}
//
return false;
}
- TypeExpr texpr = null;
- if (type is VarExpr) {
- Unary u = ((Pair) declarators[0]).Second as Unary;
- if (u == null)
- return false;
-
- Expression e = u.Expr.Resolve (ec);
- if (e == null || e.Type == null)
- return false;
-
- Type t = TypeManager.GetPointerType (e.Type);
- texpr = new TypeExpression (t, loc);
- }
- else
- texpr = type.ResolveAsTypeTerminal (ec, false);
-
+ TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
if (texpr == null)
return false;
LocalInfo vi = (LocalInfo) p.First;
Expression e = (Expression) p.Second;
- if (type is VarExpr)
- vi.VariableType = expr_type;
-
vi.VariableInfo.SetAssigned (ec);
vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
Type expr_type;
Expression [] resolved_vars;
Expression [] converted_vars;
- ExpressionStatement [] assign;
+ Expression [] assign;
TemporaryVariable local_copy;
public Using (object expression_or_block, Statement stmt, Location l)
//
bool ResolveLocalVariableDecls (EmitContext ec)
{
- int i = 0;
-
- TypeExpr texpr = null;
-
- if (expr is VarExpr) {
- Expression e = ((Expression)((DictionaryEntry)var_list[0]).Value).Resolve (ec);
- if (e == null || e.Type == null)
- return false;
- texpr = new TypeExpression (e.Type, loc);
- }
- else
- texpr = expr.ResolveAsTypeTerminal (ec, false);
-
- if (texpr == null)
- return false;
-
- expr_type = texpr.Type;
-
- //
- // The type must be an IDisposable or an implicit conversion
- // must exist.
- //
- converted_vars = new Expression [var_list.Count];
- resolved_vars = new Expression [var_list.Count];
- assign = new ExpressionStatement [var_list.Count];
+ resolved_vars = new Expression[var_list.Count];
+ assign = new Expression [var_list.Count];
+ converted_vars = new Expression[var_list.Count];
- bool need_conv = !TypeManager.ImplementsInterface (
- expr_type, TypeManager.idisposable_type);
-
- foreach (DictionaryEntry e in var_list){
+ for (int i = 0; i < assign.Length; ++i) {
+ DictionaryEntry e = (DictionaryEntry) var_list [i];
Expression var = (Expression) e.Key;
-
- if (expr is VarExpr) {
- LocalVariableReference l = var as LocalVariableReference;
- ((LocalInfo)l.Block.Variables[l.Name]).VariableType = expr_type;
- ((VarExpr)expr).Handled = true;
- }
+ Expression new_expr = (Expression) e.Value;
- var = var.ResolveLValue (ec, new EmptyExpression (), loc);
- if (var == null)
+ Expression a = new Assign (var, new_expr, loc);
+ a = a.Resolve (ec);
+ if (a == null)
return false;
resolved_vars [i] = var;
+ assign [i] = a;
- if (!need_conv) {
- i++;
+ if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
+ converted_vars [i] = var;
continue;
}
- converted_vars [i] = Convert.ImplicitConversion (
- ec, var, TypeManager.idisposable_type, loc);
-
- if (converted_vars [i] == null) {
- Error_IsNotConvertibleToIDisposable ();
+ a = Convert.ImplicitConversion (ec, a, TypeManager.idisposable_type, var.Location);
+ if (a == null) {
+ Error_IsNotConvertibleToIDisposable (var);
return false;
}
- i++;
- }
-
- i = 0;
- foreach (DictionaryEntry e in var_list){
- Expression var = resolved_vars [i];
- Expression new_expr = (Expression) e.Value;
- Expression a;
-
- a = new Assign (var, new_expr, loc);
- a = a.Resolve (ec);
- if (a == null)
- return false;
-
- if (!need_conv)
- converted_vars [i] = var;
- assign [i] = (ExpressionStatement) a;
- i++;
+ converted_vars [i] = a;
}
return true;
}
- void Error_IsNotConvertibleToIDisposable ()
+ static void Error_IsNotConvertibleToIDisposable (Expression expr)
{
- Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
- TypeManager.CSharpName (expr_type));
+ Report.SymbolRelatedToPreviousError (expr.Type);
+ Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
+ expr.GetSignatureForError ());
}
bool ResolveExpression (EmitContext ec)
{
if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
- Error_IsNotConvertibleToIDisposable ();
+ Error_IsNotConvertibleToIDisposable (expr);
return false;
}
}
int i = 0;
for (i = 0; i < assign.Length; i++) {
- assign [i].EmitStatement (ec);
+ assign [i].Emit (ec);
if (emit_finally)
ig.BeginExceptionBlock ();
if (expr == null)
return false;
- if (type is VarExpr) {
- Type element_type = null;
- if (TypeManager.HasElementType (expr.Type))
- element_type = TypeManager.GetElementType (expr.Type);
- else {
- MethodGroupExpr mg = Expression.MemberLookup (
- ec.ContainerType, expr.Type, "GetEnumerator", MemberTypes.Method,
- Expression.AllBindingFlags, loc) as MethodGroupExpr;
-
- if (mg == null)
- return false;
-
- MethodInfo get_enumerator = null;
- foreach (MethodInfo mi in mg.Methods) {
- if (TypeManager.GetParameterData (mi).Count != 0)
- continue;
- if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
- continue;
- if (CollectionForeach.IsOverride (mi))
- continue;
- get_enumerator = mi;
- }
-
- if (get_enumerator == null)
- return false;
-
- PropertyInfo pi = TypeManager.GetProperty (get_enumerator.ReturnType, "Current");
-
- if (pi == null)
- return false;
-
- element_type = pi.PropertyType;
- }
-
- type = new TypeLookupExpression (element_type.AssemblyQualifiedName);
-
- LocalVariableReference lv = variable as LocalVariableReference;
- ((LocalInfo)lv.Block.Variables[lv.Name]).VariableType = element_type;
- }
-
- Constant c = expr as Constant;
- if (c != null && c.GetValue () == null) {
+ if (expr.Type == TypeManager.null_type) {
Report.Error (186, loc, "Use of null is not valid in this context");
return false;
}
- TypeExpr texpr = type.ResolveAsTypeTerminal (ec, false);
- if (texpr == null)
- return false;
-
- Type var_type = texpr.Type;
-
if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
expr.ExprClassName);
}
if (expr.Type.IsArray) {
- array = new ArrayForeach (var_type, variable, expr, statement, loc);
+ array = new ArrayForeach (type, variable, expr, statement, loc);
return array.Resolve (ec);
- } else {
- collection = new CollectionForeach (
- var_type, variable, expr, statement, loc);
- return collection.Resolve (ec);
}
+
+ collection = new CollectionForeach (type, variable, expr, statement, loc);
+ return collection.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
Expression variable, expr, conv;
Statement statement;
Type array_type;
- Type var_type;
+ Expression var_type;
TemporaryVariable[] lengths;
ArrayCounter[] counter;
int rank;
TemporaryVariable copy;
Expression access;
- public ArrayForeach (Type var_type, Expression var,
+ public ArrayForeach (Expression var_type, Expression var,
Expression expr, Statement stmt, Location l)
{
this.var_type = var_type;
if (access == null)
return false;
- conv = Convert.ExplicitConversion (ec, access, var_type, loc);
+ VarExpr ve = var_type as VarExpr;
+ if (ve != null) {
+ // Infer implicitly typed local variable from foreach array type
+ var_type = new TypeExpression (access.Type, ve.Location);
+ }
+
+ var_type = var_type.ResolveAsTypeTerminal (ec, false);
+ if (var_type == null)
+ return false;
+
+ conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
if (conv == null)
return false;
MethodGroupExpr get_enumerator;
PropertyExpr get_current;
MethodInfo move_next;
- Type var_type, enumerator_type;
+ Expression var_type;
+ Type enumerator_type;
bool is_disposable;
bool enumerator_found;
- public CollectionForeach (Type var_type, Expression var,
+ public CollectionForeach (Expression var_type, Expression var,
Expression expr, Statement stmt, Location l)
{
this.var_type = var_type;
return false;
}
+ VarExpr ve = var_type as VarExpr;
+ if (ve != null) {
+ // Infer implicitly typed local variable from foreach enumerable type
+ var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
+ }
+
+ var_type = var_type.ResolveAsTypeTerminal (ec, false);
+ if (var_type == null)
+ return false;
+
enumerator = new TemporaryVariable (enumerator_type, loc);
enumerator.Resolve (ec);
get_current.InstanceExpression = enumerator;
Statement block = new CollectionForeachStatement (
- var_type, variable, get_current, statement, loc);
+ var_type.Type, variable, get_current, statement, loc);
loop = new While (move_next_expr, block, loc);