[Mono-list] Properties are now working.
Miguel de Icaza
miguel@ximian.com
Sun, 14 Oct 2001 18:57:05 -0400
Hey guys,
Today I got properties working in the compiler (get/set, error
checking, instance or class support). Very simple changes to the work
from friday. I will hold on a bit on indexers, as that requires to
tackle also arrays at the same time.
I am now going to try to fix the compiler so we can handle test-22
which exhibits an interesting bug.
Miguel.
Index: ChangeLog
===================================================================
RCS file: /cvs/public/mcs/mcs/ChangeLog,v
retrieving revision 1.132
diff -u -r1.132 ChangeLog
--- ChangeLog 2001/10/12 18:52:18 1.132
+++ ChangeLog 2001/10/14 19:02:26
@@ -1,3 +1,13 @@
+2001-10-14 Miguel de Icaza <miguel@ximian.com>
+
+ * expression.cs (PropertyExpr): Make this into an
+ ExpressionStatement, and support the EmitStatement code path.
+
+ Perform get/set error checking, clean up the interface.
+
+ * assign.cs: recognize PropertyExprs as targets, and if so, turn
+ them into toplevel access objects.
+
2001-10-12 Miguel de Icaza <miguel@ximian.com>
* expression.cs: PropertyExpr::PropertyExpr: use work around the
Index: assign.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/assign.cs,v
retrieving revision 1.16
diff -u -r1.16 assign.cs
--- assign.cs 2001/10/12 14:18:21 1.16
+++ assign.cs 2001/10/14 19:02:26
@@ -50,6 +50,19 @@
if (target == null || source == null)
return null;
+ //
+ // If we are doing a property assignment, then
+ // set the `value' field on the property, and Resolve
+ // it.
+ //
+ if (target is PropertyExpr){
+ PropertyExpr property_assign = (PropertyExpr) target;
+
+ property_assign.Value = source;
+
+ return property_assign.Resolve (ec);
+ }
+
Type target_type = target.Type;
Type source_type = source.Type;
Index: expression.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/expression.cs,v
retrieving revision 1.82
diff -u -r1.82 expression.cs
--- expression.cs 2001/10/12 18:52:18 1.82
+++ expression.cs 2001/10/14 19:02:38
@@ -3899,28 +3899,25 @@
a.Emit (ec);
}
}
-
- public override void Emit (EmitContext ec)
+
+ public static void EmitCall (EmitContext ec,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments)
{
- bool is_static = method.IsStatic;
ILGenerator ig = ec.ig;
bool struct_call = false;
if (!is_static){
- MethodGroupExpr mg = (MethodGroupExpr) this.expr;
-
//
// If this is ourselves, push "this"
//
- if (mg.InstanceExpression == null){
+ if (instance_expr == null){
ig.Emit (OpCodes.Ldarg_0);
} else {
- Expression ie = mg.InstanceExpression;
-
//
// Push the instance expression
//
- if (ie.Type.IsSubclassOf (TypeManager.value_type)){
+ if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
struct_call = true;
@@ -3931,16 +3928,18 @@
//
// If not we have to use some temporary storage for
// it.
- if (ie is MemoryLocation)
- ((MemoryLocation) ie).AddressOf (ec);
+ if (instance_expr is MemoryLocation)
+ ((MemoryLocation) instance_expr).AddressOf (ec);
else {
- ie.Emit (ec);
- LocalBuilder temp = ec.GetTemporaryStorage (ie.Type);
+ Type t = instance_expr.Type;
+
+ instance_expr.Emit (ec);
+ LocalBuilder temp = ec.GetTemporaryStorage (t);
ig.Emit (OpCodes.Stloc, temp);
ig.Emit (OpCodes.Ldloca, temp);
}
} else
- ie.Emit (ec);
+ instance_expr.Emit (ec);
}
}
@@ -3959,6 +3958,13 @@
ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
}
}
+
+ public override void Emit (EmitContext ec)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+ EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments);
+ }
public override void EmitStatement (EmitContext ec)
{
@@ -4505,34 +4511,58 @@
}
// <summary>
- // Fully resolved expression that evaluates to a Property
+ // Expression that evaluates to a Property. The Assign class
+ // might set the `Value' expression if we are in an assignment.
// </summary>
- public class PropertyExpr : Expression, LValue {
+ public class PropertyExpr : ExpressionStatement {
public readonly PropertyInfo PropertyInfo;
public readonly bool IsStatic;
MethodInfo [] Accessors;
Location loc;
Expression instance_expr;
+ Expression value;
- public PropertyExpr (PropertyInfo pi, Location loc)
+ public PropertyExpr (PropertyInfo pi, Location l)
{
PropertyInfo = pi;
eclass = ExprClass.PropertyAccess;
IsStatic = false;
-
+ loc = l;
Accessors = TypeManager.GetAccessors (pi);
if (Accessors != null)
- for (int i = 0; i < Accessors.Length; i++)
- if (Accessors [i].IsStatic)
- IsStatic = true;
+ for (int i = 0; i < Accessors.Length; i++){
+ if (Accessors [i] != null)
+ if (Accessors [i].IsStatic)
+ IsStatic = true;
+ }
else
Accessors = new MethodInfo [2];
type = pi.PropertyType;
}
+ //
+ // Controls the Value of the PropertyExpr. If the value
+ // is null, then the property is being used in a `read' mode.
+ // otherwise the property is used in assignment mode.
+ //
+ // The value is set to a fully resolved type by assign.
+ //
+ public Expression Value {
+ get {
+ return value;
+ }
+
+ set {
+ this.value = value;
+ }
+ }
+
+ //
+ // The instance expression associated with this expression
+ //
public Expression InstanceExpression {
set {
instance_expr = value;
@@ -4544,44 +4574,46 @@
}
override public Expression DoResolve (EmitContext ec)
- {
- // We are born in resolved state.
- return this;
- }
-
- public Expression LValueResolve (EmitContext ec)
{
- if (!PropertyInfo.CanWrite){
- Report.Error (200, loc,
- "The property `" + PropertyInfo.Name +
- "' can not be assigned to, as it has not set accessor");
- return null;
+ if (value == null){
+ if (!PropertyInfo.CanRead){
+ Report.Error (154, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be used in " +
+ "this context because it lacks a get accessor");
+ return null;
+ }
+ } else {
+ if (!PropertyInfo.CanWrite){
+ Report.Error (200, loc,
+ "The property `" + PropertyInfo.Name +
+ "' can not be assigned to, as it has not set accessor");
+ return null;
+ }
}
return this;
- }
-
- public void Store (EmitContext ec)
- {
}
-
+
override public void Emit (EmitContext ec)
{
- //
- // This really should be done in Resolve, but
- // at that point we might be used as an LValue
- // and it is valid to only have a setter and no getter.
- //
+ if (value == null)
+ Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null);
+ else {
+ Argument arg = new Argument (value, Argument.AType.Expression);
+ ArrayList args = new ArrayList ();
- if (!PropertyInfo.CanRead){
- Report.Error (154, loc,
- "The property `" + PropertyInfo.Name +
- "' can not be used in " +
- "this context because it lacks a get accessor");
- return;
+ args.Add (arg);
+ Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args);
}
-
- throw new Exception ("Unimplemented");
+ }
+
+ override public void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ if (value == null){
+ ec.ig.Emit (OpCodes.Pop);
+ }
}
}