oper_names [(int) Operator.AddressOf] = "op_AddressOf";
}
- public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
- {
- Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
- }
-
- public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
- {
- Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
- oper, type);
- }
-
void Error23 (Type t)
{
- Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
+ Report.Error (23, loc, "Operator `{0}' cannot be applied to operand of type `{1}'",
+ OperName (Oper), TypeManager.CSharpName (t));
}
/// <remarks>
}
ParameterReference pr = Expr as ParameterReference;
- if ((pr != null) && (ec.capture_context != null) &&
- ec.capture_context.IsParameterCaptured (pr.Name)) {
+ if ((pr != null) && pr.Parameter.IsCaptured) {
AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
return null;
}
}
+ public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
+ bool prepared;
+ LocalTemporary temp;
+
+ public abstract Variable Variable {
+ get;
+ }
+
+ public abstract bool IsRef {
+ get;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ //
+ // This method is used by parameters that are references, that are
+ // being passed as references: we only want to pass the pointer (that
+ // is already stored in the parameter, not the address of the pointer,
+ // and not the value of the variable).
+ //
+ public void EmitLoad (EmitContext ec)
+ {
+ Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
+ if (!prepared)
+ Variable.EmitInstance (ec);
+ Variable.Emit (ec);
+ }
+
+ public void Emit (EmitContext ec, bool leave_copy)
+ {
+ Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
+
+ EmitLoad (ec);
+
+ if (IsRef) {
+ if (prepared)
+ ec.ig.Emit (OpCodes.Dup);
+
+ //
+ // If we are a reference, we loaded on the stack a pointer
+ // Now lets load the real value
+ //
+ LoadFromPtr (ec.ig, type);
+ }
+
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+
+ if (IsRef || Variable.NeedsTemporary) {
+ temp = new LocalTemporary (Type);
+ temp.Store (ec);
+ }
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
+ bool prepare_for_load)
+ {
+ Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
+ source, loc);
+
+ ILGenerator ig = ec.ig;
+ prepared = prepare_for_load;
+
+ Variable.EmitInstance (ec);
+ if (prepare_for_load && Variable.HasInstance)
+ ig.Emit (OpCodes.Dup);
+ else if (IsRef && !prepared)
+ Variable.Emit (ec);
+
+ source.Emit (ec);
+
+ if (leave_copy) {
+ ig.Emit (OpCodes.Dup);
+ if (IsRef || Variable.NeedsTemporary) {
+ temp = new LocalTemporary (Type);
+ temp.Store (ec);
+ }
+ }
+
+ if (IsRef)
+ StoreFromPtr (ig, type);
+ else
+ Variable.EmitAssign (ec);
+
+ if (temp != null) {
+ temp.Emit (ec);
+ temp.Release (ec);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ Variable.EmitInstance (ec);
+ Variable.EmitAddressOf (ec);
+ }
+ }
+
/// <summary>
/// Local variables
/// </summary>
- public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public class LocalVariableReference : VariableReference, IVariable {
public readonly string Name;
public readonly Block Block;
public LocalInfo local_info;
bool is_readonly;
- bool prepared;
- LocalTemporary temp;
+ Variable variable;
public LocalVariableReference (Block block, string name, Location l)
{
get { return local_info.VariableInfo; }
}
+ public override bool IsRef {
+ get { return false; }
+ }
+
public bool IsReadOnly {
get { return is_readonly; }
}
if (!VerifyAssigned (ec))
return null;
- if (ec.CurrentAnonymousMethod != null){
- //
- // If we are referencing a variable from the external block
- // flag it for capturing
- //
- if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) ||
- ec.CurrentAnonymousMethod.IsIterator)
- {
- if (local_info.AddressTaken){
- AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
- return null;
- }
- ec.CaptureVariable (local_info);
+ //
+ // If we are referencing a variable from the external block
+ // flag it for capturing
+ //
+ if (ec.MustCaptureVariable (local_info)) {
+ if (local_info.AddressTaken){
+ AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
+ return null;
}
+
+ ScopeInfo scope = local_info.Block.CreateScopeInfo ();
+ variable = scope.AddLocal (local_info);
+ type = variable.Type;
}
return this;
} else if (right_side == EmptyExpression.LValueMemberOutAccess) {
code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
} else {
- Error_CannotAssign (Name, local_info.GetReadOnlyContext ());
- return null;
+ code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
}
Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
return null;
return Name == lvr.Name && Block == lvr.Block;
}
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods.
- //
- if (!prepared)
- ec.EmitCapturedVariableInstance (local_info);
-
- ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
- }
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- Emit (ec);
- if (leave_copy){
- ec.ig.Emit (OpCodes.Dup);
- if (local_info.FieldBuilder != null){
- temp = new LocalTemporary (Type);
- temp.Store (ec);
- }
- }
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- ILGenerator ig = ec.ig;
- prepared = prepare_for_load;
-
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- if (local_info.LocalBuilder == null)
- throw new Exception ("This should not happen: both Field and Local are null");
-
- source.Emit (ec);
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods or itereators.
- //
- ec.EmitCapturedVariableInstance (local_info);
-
- if (prepare_for_load)
- ig.Emit (OpCodes.Dup);
- source.Emit (ec);
- if (leave_copy){
- ig.Emit (OpCodes.Dup);
- temp = new LocalTemporary (Type);
- temp.Store (ec);
- }
- ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
- if (temp != null) {
- temp.Emit (ec);
- temp.Release (ec);
- }
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- ILGenerator ig = ec.ig;
-
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods or iterators
- //
- ec.EmitCapturedVariableInstance (local_info);
- ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
- }
+ public override Variable Variable {
+ get { return variable != null ? variable : local_info.Variable; }
}
public override string ToString ()
/// This represents a reference to a parameter in the intermediate
/// representation.
/// </summary>
- public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public class ParameterReference : VariableReference, IVariable {
Parameter par;
string name;
int idx;
Block block;
VariableInfo vi;
- public bool is_ref, is_out, prepared;
+ public bool is_ref, is_out;
public bool IsOut {
get {
}
}
- public bool IsRef {
+ public override bool IsRef {
get {
return is_ref;
}
}
}
- LocalTemporary temp;
+ public Parameter Parameter {
+ get {
+ return par;
+ }
+ }
+
+ Variable variable;
public ParameterReference (Parameter par, Block block, int idx, Location loc)
{
get { return vi; }
}
+ public override Variable Variable {
+ get { return variable != null ? variable : par.Variable; }
+ }
+
public bool VerifyFixed ()
{
// A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
if (is_out)
vi = block.ParameterMap [idx];
- if (ec.CurrentAnonymousMethod != null){
- if (is_ref && !block.Toplevel.IsLocalParameter (name)){
- Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block",
- par.Name);
- return false;
- }
+ AnonymousContainer am = ec.CurrentAnonymousMethod;
+ if (am == null)
+ return true;
- //
- // If we are referencing the parameter from the external block
- // flag it for capturing
- //
- //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
- if (!block.Toplevel.IsLocalParameter (name)){
- ec.CaptureParameter (name, type, idx);
+ if (is_ref && !block.Toplevel.IsLocalParameter (name)){
+ Report.Error (1628, Location,
+ "Cannot use ref or out parameter `{0}' inside an " +
+ "anonymous method block", par.Name);
+ return false;
+ }
+
+ if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
+ return true;
+
+ AnonymousMethodHost host = null;
+ ToplevelBlock toplevel = block.Toplevel;
+ while (toplevel != null) {
+ if (toplevel.IsLocalParameter (name)) {
+ host = toplevel.AnonymousMethodHost;
+ break;
}
+
+ toplevel = toplevel.Container;
}
+ variable = host.AddParameter (par, idx);
+ type = variable.Type;
return true;
}
if (!DoResolveBase (ec))
return null;
- if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
+ if (is_out && ec.DoFlowAnalysis &&
+ (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
return null;
return this;
ig.Emit (OpCodes.Ldarg, x);
}
- //
- // This method is used by parameters that are references, that are
- // being passed as references: we only want to pass the pointer (that
- // is already stored in the parameter, not the address of the pointer,
- // and not the value of the variable).
- //
- public void EmitLoad (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- EmitLdArg (ig, arg_idx);
-
- //
- // FIXME: Review for anonymous methods
- //
- }
-
- public override void Emit (EmitContext ec)
- {
- Emit (ec, false);
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitParameter (name, leave_copy, prepared, ref temp);
- return;
- }
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- EmitLdArg (ig, arg_idx);
-
- if (is_ref) {
- if (prepared)
- ec.ig.Emit (OpCodes.Dup);
-
- //
- // If we are a reference, we loaded on the stack a pointer
- // Now lets load the real value
- //
- LoadFromPtr (ig, type);
- }
-
- if (leave_copy) {
- ec.ig.Emit (OpCodes.Dup);
-
- if (is_ref) {
- temp = new LocalTemporary (type);
- temp.Store (ec);
- }
- }
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- prepared = prepare_for_load;
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load, ref temp);
- return;
- }
-
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
-
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- if (is_ref && !prepared)
- EmitLdArg (ig, arg_idx);
-
- source.Emit (ec);
-
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
-
- if (is_ref) {
- if (leave_copy) {
- temp = new LocalTemporary (type);
- temp.Store (ec);
- }
-
- StoreFromPtr (ig, type);
-
- if (temp != null) {
- temp.Emit (ec);
- temp.Release (ec);
- }
- } else {
- if (arg_idx <= 255)
- ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
- else
- ig.Emit (OpCodes.Starg, arg_idx);
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitAddressOfParameter (name);
- return;
- }
-
- int arg_idx = idx;
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- if (is_ref){
- if (arg_idx <= 255)
- ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
- else
- ec.ig.Emit (OpCodes.Ldarg, arg_idx);
- } else {
- if (arg_idx <= 255)
- ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
- else
- ec.ig.Emit (OpCodes.Ldarga, arg_idx);
- }
- }
-
public override string ToString ()
{
return "ParameterReference[" + name + "]";
{
eclass = ExprClass.Variable;
type = ec.ContainerType;
+ variable = new SimpleThis (type);
return this;
}
}
/// Represents the `this' construct
/// </summary>
- public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
-
+ public class This : VariableReference, IVariable
+ {
Block block;
VariableInfo variable_info;
-
+ protected Variable variable;
+ bool is_struct;
+
public This (Block block, Location loc)
{
this.loc = loc;
return !TypeManager.IsValueType (Type);
}
+ public override bool IsRef {
+ get { return is_struct; }
+ }
+
+ public override Variable Variable {
+ get { return variable; }
+ }
+
public bool ResolveBase (EmitContext ec)
{
eclass = ExprClass.Variable;
else
type = ec.ContainerType;
+ is_struct = ec.TypeContainer is Struct;
+
if (ec.IsStatic) {
- Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
+ Error (26, "Keyword `this' is not valid in a static property, " +
+ "static method, or static field initializer");
return false;
}
- if (block != null && block.Toplevel.ThisVariable != null)
- variable_info = block.Toplevel.ThisVariable.VariableInfo;
+ if (block != null) {
+ if (block.Toplevel.ThisVariable != null)
+ variable_info = block.Toplevel.ThisVariable.VariableInfo;
- if (ec.CurrentAnonymousMethod != null)
- ec.CaptureThis ();
+ AnonymousContainer am = ec.CurrentAnonymousMethod;
+ if (is_struct && (am != null) && !am.IsIterator) {
+ Report.Error (1673, loc, "Anonymous methods inside structs " +
+ "cannot access instance members of `this'. " +
+ "Consider copying `this' to a local variable " +
+ "outside the anonymous method and using the " +
+ "local instead.");
+ return false;
+ }
+
+ AnonymousMethodHost host = block.Toplevel.AnonymousMethodHost;
+ if ((host != null) && (!is_struct || host.IsIterator)) {
+ variable = host.CaptureThis ();
+ type = variable.Type;
+ is_struct = false;
+ }
+ }
+
+ if (variable == null)
+ variable = new SimpleThis (type);
return true;
}
if (!ResolveBase (ec))
return null;
- if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && !variable_info.IsAssigned (ec)) {
- Error (188, "The `this' object cannot be used before all of its fields are assigned to");
+ if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
+ !variable_info.IsAssigned (ec)) {
+ Error (188, "The `this' object cannot be used before all of its " +
+ "fields are assigned to");
variable_info.SetAssigned (ec);
return this;
}
return this;
}
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- Emit (ec);
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- ILGenerator ig = ec.ig;
-
- if (ec.TypeContainer is Struct){
- ec.EmitThis (false);
- source.Emit (ec);
-
- LocalTemporary t = null;
- if (leave_copy) {
- t = new LocalTemporary (type);
- ec.ig.Emit (OpCodes.Dup);
- t.Store (ec);
- }
-
- ig.Emit (OpCodes.Stobj, type);
-
- if (leave_copy) {
- t.Emit (ec);
- t.Release (ec);
- }
- } else {
- throw new Exception ("how did you get here");
- }
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- ec.EmitThis (false);
- if (ec.TypeContainer is Struct)
- ig.Emit (OpCodes.Ldobj, type);
- }
-
public override int GetHashCode()
{
return block.GetHashCode ();
return block == t.block;
}
- public void AddressOf (EmitContext ec, AddressOp mode)
+ protected class SimpleThis : Variable
{
- ec.EmitThis (true);
+ Type type;
- // FIMXE
- // FIGURE OUT WHY LDARG_S does not work
- //
- // consider: struct X { int val; int P { set { val = value; }}}
- //
- // Yes, this looks very bad. Look at `NOTAS' for
- // an explanation.
- // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
+ public SimpleThis (Type type)
+ {
+ this.type = type;
+ }
+
+ public override Type Type {
+ get { return type; }
+ }
+
+ public override bool HasInstance {
+ get { return false; }
+ }
+
+ public override bool NeedsTemporary {
+ get { return false; }
+ }
+
+ public override void EmitInstance (EmitContext ec)
+ {
+ // Do nothing.
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
+
+ public override void EmitAssign (EmitContext ec)
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public override void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
}
}
TypeArguments args;
public MemberAccess (Expression expr, string id)
- : this (expr, id, null)
+ : this (expr, id, expr.Location)
{
}
- public MemberAccess (Expression expr, string identifier, Location loc, TypeArguments args)
+ public MemberAccess (Expression expr, string identifier, Location loc)
{
this.expr = expr;
Identifier = identifier;
this.loc = loc;
- this.args = args;
}
- public MemberAccess (Expression expr, string id, Location loc)
- : this (expr, id, loc, null)
- {
- }
-
public MemberAccess (Expression expr, string id, TypeArguments args)
- : this (expr, id, expr.Location, args)
+ : this (expr, id)
{
+ this.args = args;
}
public Expression Expr {
}
Type expr_type = new_expr.Type;
- if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
- Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
+ if (expr_type.IsPointer){
+ Error (23, "The `.' operator can not be applied to pointer operands (" +
+ TypeManager.CSharpName (expr_type) + ")");
return null;
- }
- if (expr_type == TypeManager.anonymous_method_type){
- Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
+ } else if (expr_type == TypeManager.void_type) {
+ Error (23, "The `.' operator can not be applied to operands of type 'void'");
return null;
+ } else if (expr_type == TypeManager.anonymous_method_type){
+ Error (23, "The `.' operator can not be applied to anonymous methods");
}