2 // assign.cs: Assignments.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System.Reflection;
11 using System.Reflection.Emit;
13 namespace Mono.CSharp {
16 /// This interface is implemented by expressions that can be assigned to.
19 /// This interface is implemented by Expressions whose values can not
20 /// store the result on the top of the stack.
22 /// Expressions implementing this (Properties, Indexers and Arrays) would
23 /// perform an assignment of the Expression "source" into its final
26 /// No values on the top of the stack are expected to be left by
27 /// invoking this method.
29 public interface IAssignMethod {
30 void EmitAssign (EmitContext ec, Expression source);
34 /// An Expression to hold a temporary value.
37 /// The LocalTemporary class is used to hold temporary values of a given
38 /// type to "simulate" the expression semantics on property and indexer
39 /// access whose return values are void.
41 /// The local temporary is used to alter the normal flow of code generation
42 /// basically it creates a local variable, and its emit instruction generates
43 /// code to access this value, return its address or save its value.
45 public class LocalTemporary : Expression, IMemoryLocation {
48 public LocalTemporary (EmitContext ec, Type t)
51 eclass = ExprClass.Value;
52 builder = ec.GetTemporaryStorage (t);
55 public void Release (EmitContext ec)
57 ec.FreeTemporaryStorage (builder);
61 public LocalTemporary (LocalBuilder b, Type t)
64 eclass = ExprClass.Value;
68 public override Expression DoResolve (EmitContext ec)
73 public override void Emit (EmitContext ec)
75 ec.ig.Emit (OpCodes.Ldloc, builder);
78 public void Store (EmitContext ec)
80 ec.ig.Emit (OpCodes.Stloc, builder);
83 public void AddressOf (EmitContext ec, AddressOp mode)
85 ec.ig.Emit (OpCodes.Ldloca, builder);
90 /// The Assign node takes care of assigning the value of source into
91 /// the expression represented by target.
93 public class Assign : ExpressionStatement {
94 Expression target, source;
97 public Assign (Expression target, Expression source, Location l)
100 this.source = source;
104 public Expression Target {
114 public Expression Source {
124 public static void error70 (EventInfo ei, Location l)
126 Report.Error (70, l, "The event '" + ei.Name +
127 "' can only appear on the left-side of a += or -= (except when" +
128 " used from within the type '" + ei.DeclaringType + "')");
131 public override Expression DoResolve (EmitContext ec)
133 source = source.Resolve (ec);
137 target = target.ResolveLValue (ec, source);
142 Type target_type = target.Type;
143 Type source_type = source.Type;
146 eclass = ExprClass.Value;
149 // If we are doing a property assignment, then
150 // set the `value' field on the property, and Resolve
153 if (target is PropertyExpr){
154 PropertyExpr property_assign = (PropertyExpr) target;
157 // FIXME: Maybe handle this in the LValueResolve
159 if (!property_assign.VerifyAssignable ())
165 if (target is IndexerAccess){
166 IndexerAccess ia = (IndexerAccess) target;
171 if (target is EventExpr) {
174 EventInfo ei = ((EventExpr) target).EventInfo;
177 Expression ml = MemberLookup (
178 ec, ec.TypeContainer.TypeBuilder, ei.Name,
179 MemberTypes.Event, AllBindingFlags, l);
183 // If this is the case, then the Event does not belong
184 // to this TypeContainer and so, according to the spec
185 // is allowed to only appear on the left hand of
186 // the += and -= operators
188 // Note that if target will not appear as an EventExpr
189 // in the case it is being referenced within the same type container;
190 // it will appear as a FieldExpr in that case.
193 if (!(source is Binary)) {
197 tmp = ((Binary) source);
198 if (tmp.Oper != Binary.Operator.Addition &&
199 tmp.Oper != Binary.Operator.Subtraction) {
207 if (source is New && target_type.IsSubclassOf (TypeManager.value_type)){
208 New n = (New) source;
210 n.ValueTypeVariable = target;
214 if (target_type != source_type){
215 source = ConvertImplicitRequired (ec, source, target_type, l);
220 if (target.eclass != ExprClass.Variable && target.eclass != ExprClass.EventAccess){
221 Report.Error (131, l,
222 "Left hand of an assignment must be a variable, " +
223 "a property or an indexer");
230 void Emit (EmitContext ec, bool is_statement)
232 if (target is EventExpr) {
233 ((EventExpr) target).EmitAddOrRemove (ec, source);
238 // FIXME! We need a way to "probe" if the process can
239 // just use `dup' to propagate the result
241 IAssignMethod am = (IAssignMethod) target;
244 am.EmitAssign (ec, source);
246 LocalTemporary tempo;
248 tempo = new LocalTemporary (ec, source.Type);
252 am.EmitAssign (ec, tempo);
258 public override void Emit (EmitContext ec)
263 public override void EmitStatement (EmitContext ec)