If the window manager does not support _NET_ACTIVE_WINDOW, fall back to XGetInputFocus
[mono.git] / mcs / mcs / assign.cs
1 //
2 // assign.cs: Assignments.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Martin Baulig (martin@ximian.com)
7 //   Marek Safar (marek.safar@gmail.com)        
8 //
9 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 //
11 // Copyright 2001, 2002, 2003 Ximian, Inc.
12 // Copyright 2004-2008 Novell, Inc
13 // Copyright 2011 Xamarin Inc
14 //
15 using System;
16
17 #if STATIC
18 using IKVM.Reflection.Emit;
19 #else
20 using System.Reflection.Emit;
21 #endif
22
23 namespace Mono.CSharp {
24
25         /// <summary>
26         ///   This interface is implemented by expressions that can be assigned to.
27         /// </summary>
28         /// <remarks>
29         ///   This interface is implemented by Expressions whose values can not
30         ///   store the result on the top of the stack.
31         ///
32         ///   Expressions implementing this (Properties, Indexers and Arrays) would
33         ///   perform an assignment of the Expression "source" into its final
34         ///   location.
35         ///
36         ///   No values on the top of the stack are expected to be left by
37         ///   invoking this method.
38         /// </remarks>
39         public interface IAssignMethod {
40                 //
41                 // This is an extra version of Emit. If leave_copy is `true'
42                 // A copy of the expression will be left on the stack at the
43                 // end of the code generated for EmitAssign
44                 //
45                 void Emit (EmitContext ec, bool leave_copy);
46
47                 //
48                 // This method does the assignment
49                 // `source' will be stored into the location specified by `this'
50                 // if `leave_copy' is true, a copy of `source' will be left on the stack
51                 // if `prepare_for_load' is true, when `source' is emitted, there will
52                 // be data on the stack that it can use to compuatate its value. This is
53                 // for expressions like a [f ()] ++, where you can't call `f ()' twice.
54                 //
55                 void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
56
57                 /*
58                 For simple assignments, this interface is very simple, EmitAssign is called with source
59                 as the source expression and leave_copy and prepare_for_load false.
60
61                 For compound assignments it gets complicated.
62
63                 EmitAssign will be called as before, however, prepare_for_load will be
64                 true. The @source expression will contain an expression
65                 which calls Emit. So, the calls look like:
66
67                 this.EmitAssign (ec, source, false, true) ->
68                         source.Emit (ec); ->
69                                 [...] ->
70                                         this.Emit (ec, false); ->
71                                         end this.Emit (ec, false); ->
72                                 end [...]
73                         end source.Emit (ec);
74                 end this.EmitAssign (ec, source, false, true)
75
76
77                 When prepare_for_load is true, EmitAssign emits a `token' on the stack that
78                 Emit will use for its state.
79
80                 Let's take FieldExpr as an example. assume we are emitting f ().y += 1;
81
82                 Here is the call tree again. This time, each call is annotated with the IL
83                 it produces:
84
85                 this.EmitAssign (ec, source, false, true)
86                         call f
87                         dup
88
89                         Binary.Emit ()
90                                 this.Emit (ec, false);
91                                 ldfld y
92                                 end this.Emit (ec, false);
93
94                                 IntConstant.Emit ()
95                                 ldc.i4.1
96                                 end IntConstant.Emit
97
98                                 add
99                         end Binary.Emit ()
100
101                         stfld
102                 end this.EmitAssign (ec, source, false, true)
103
104                 Observe two things:
105                         1) EmitAssign left a token on the stack. It was the result of f ().
106                         2) This token was used by Emit
107
108                 leave_copy (in both EmitAssign and Emit) tells the compiler to leave a copy
109                 of the expression at that point in evaluation. This is used for pre/post inc/dec
110                 and for a = x += y. Let's do the above example with leave_copy true in EmitAssign
111
112                 this.EmitAssign (ec, source, true, true)
113                         call f
114                         dup
115
116                         Binary.Emit ()
117                                 this.Emit (ec, false);
118                                 ldfld y
119                                 end this.Emit (ec, false);
120
121                                 IntConstant.Emit ()
122                                 ldc.i4.1
123                                 end IntConstant.Emit
124
125                                 add
126                         end Binary.Emit ()
127
128                         dup
129                         stloc temp
130                         stfld
131                         ldloc temp
132                 end this.EmitAssign (ec, source, true, true)
133
134                 And with it true in Emit
135
136                 this.EmitAssign (ec, source, false, true)
137                         call f
138                         dup
139
140                         Binary.Emit ()
141                                 this.Emit (ec, true);
142                                 ldfld y
143                                 dup
144                                 stloc temp
145                                 end this.Emit (ec, true);
146
147                                 IntConstant.Emit ()
148                                 ldc.i4.1
149                                 end IntConstant.Emit
150
151                                 add
152                         end Binary.Emit ()
153
154                         stfld
155                         ldloc temp
156                 end this.EmitAssign (ec, source, false, true)
157
158                 Note that these two examples are what happens for ++x and x++, respectively.
159                 */
160         }
161
162         /// <summary>
163         ///   An Expression to hold a temporary value.
164         /// </summary>
165         /// <remarks>
166         ///   The LocalTemporary class is used to hold temporary values of a given
167         ///   type to "simulate" the expression semantics. The local variable is
168         ///   never captured.
169         ///
170         ///   The local temporary is used to alter the normal flow of code generation
171         ///   basically it creates a local variable, and its emit instruction generates
172         ///   code to access this value, return its address or save its value.
173         ///
174         ///   If `is_address' is true, then the value that we store is the address to the
175         ///   real value, and not the value itself.
176         ///
177         ///   This is needed for a value type, because otherwise you just end up making a
178         ///   copy of the value on the stack and modifying it. You really need a pointer
179         ///   to the origional value so that you can modify it in that location. This
180         ///   Does not happen with a class because a class is a pointer -- so you always
181         ///   get the indirection.
182         ///
183         /// </remarks>
184         public class LocalTemporary : Expression, IMemoryLocation, IAssignMethod {
185                 LocalBuilder builder;
186
187                 public LocalTemporary (TypeSpec t)
188                 {
189                         type = t;
190                         eclass = ExprClass.Value;
191                 }
192
193                 public LocalTemporary (LocalBuilder b, TypeSpec t)
194                         : this (t)
195                 {
196                         builder = b;
197                 }
198
199                 public void Release (EmitContext ec)
200                 {
201                         ec.FreeTemporaryLocal (builder, type);
202                         builder = null;
203                 }
204
205                 public override bool ContainsEmitWithAwait ()
206                 {
207                         return false;
208                 }
209
210                 public override Expression CreateExpressionTree (ResolveContext ec)
211                 {
212                         Arguments args = new Arguments (1);
213                         args.Add (new Argument (this));
214                         return CreateExpressionFactoryCall (ec, "Constant", args);
215                 }
216
217                 protected override Expression DoResolve (ResolveContext ec)
218                 {
219                         return this;
220                 }
221
222                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
223                 {
224                         return this;
225                 }
226
227                 public override void Emit (EmitContext ec)
228                 {
229                         if (builder == null)
230                                 throw new InternalErrorException ("Emit without Store, or after Release");
231
232                         ec.Emit (OpCodes.Ldloc, builder);
233                 }
234
235                 #region IAssignMethod Members
236
237                 public void Emit (EmitContext ec, bool leave_copy)
238                 {
239                         Emit (ec);
240
241                         if (leave_copy)
242                                 Emit (ec);
243                 }
244
245                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
246                 {
247                         if (isCompound)
248                                 throw new NotImplementedException ();
249
250                         source.Emit (ec);
251
252                         Store (ec);
253
254                         if (leave_copy)
255                                 Emit (ec);
256                 }
257
258                 #endregion
259
260                 public LocalBuilder Builder {
261                         get { return builder; }
262                 }
263
264                 public void Store (EmitContext ec)
265                 {
266                         if (builder == null)
267                                 builder = ec.GetTemporaryLocal (type);
268
269                         ec.Emit (OpCodes.Stloc, builder);
270                 }
271
272                 public void AddressOf (EmitContext ec, AddressOp mode)
273                 {
274                         if (builder == null)
275                                 builder = ec.GetTemporaryLocal (type);
276
277                         if (builder.LocalType.IsByRef) {
278                                 //
279                                 // if is_address, than this is just the address anyways,
280                                 // so we just return this.
281                                 //
282                                 ec.Emit (OpCodes.Ldloc, builder);
283                         } else {
284                                 ec.Emit (OpCodes.Ldloca, builder);
285                         }
286                 }
287         }
288
289         /// <summary>
290         ///   The Assign node takes care of assigning the value of source into
291         ///   the expression represented by target.
292         /// </summary>
293         public abstract class Assign : ExpressionStatement {
294                 protected Expression target, source;
295
296                 protected Assign (Expression target, Expression source, Location loc)
297                 {
298                         this.target = target;
299                         this.source = source;
300                         this.loc = loc;
301                 }
302                 
303                 public Expression Target {
304                         get { return target; }
305                 }
306
307                 public Expression Source {
308                         get {
309                                 return source;
310                         }
311                 }
312
313                 public override bool ContainsEmitWithAwait ()
314                 {
315                         return target.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ();
316                 }
317
318                 public override Expression CreateExpressionTree (ResolveContext ec)
319                 {
320                         ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
321                         return null;
322                 }
323
324                 protected override Expression DoResolve (ResolveContext ec)
325                 {
326                         bool ok = true;
327                         source = source.Resolve (ec);
328                                                 
329                         if (source == null) {
330                                 ok = false;
331                                 source = EmptyExpression.Null;
332                         }
333
334                         target = target.ResolveLValue (ec, source);
335
336                         if (target == null || !ok)
337                                 return null;
338
339                         TypeSpec target_type = target.Type;
340                         TypeSpec source_type = source.Type;
341
342                         eclass = ExprClass.Value;
343                         type = target_type;
344
345                         if (!(target is IAssignMethod)) {
346                                 Error_ValueAssignment (ec, source);
347                                 return null;
348                         }
349
350                         if (target_type != source_type) {
351                                 Expression resolved = ResolveConversions (ec);
352
353                                 if (resolved != this)
354                                         return resolved;
355                         }
356
357                         return this;
358                 }
359
360 #if NET_4_0 || MONODROID
361                 public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
362                 {
363                         var tassign = target as IDynamicAssign;
364                         if (tassign == null)
365                                 throw new InternalErrorException (target.GetType () + " does not support dynamic assignment");
366
367                         var target_object = tassign.MakeAssignExpression (ctx, source);
368
369                         //
370                         // Some hacking is needed as DLR does not support void type and requires
371                         // always have object convertible return type to support caching and chaining
372                         //
373                         // We do this by introducing an explicit block which returns RHS value when
374                         // available or null
375                         //
376                         if (target_object.NodeType == System.Linq.Expressions.ExpressionType.Block)
377                                 return target_object;
378
379                         System.Linq.Expressions.UnaryExpression source_object;
380                         if (ctx.HasSet (BuilderContext.Options.CheckedScope)) {
381                                 source_object = System.Linq.Expressions.Expression.ConvertChecked (source.MakeExpression (ctx), target_object.Type);
382                         } else {
383                                 source_object = System.Linq.Expressions.Expression.Convert (source.MakeExpression (ctx), target_object.Type);
384                         }
385
386                         return System.Linq.Expressions.Expression.Assign (target_object, source_object);
387                 }
388 #endif
389                 protected virtual Expression ResolveConversions (ResolveContext ec)
390                 {
391                         source = Convert.ImplicitConversionRequired (ec, source, target.Type, source.Location);
392                         if (source == null)
393                                 return null;
394
395                         return this;
396                 }
397
398                 void Emit (EmitContext ec, bool is_statement)
399                 {
400                         IAssignMethod t = (IAssignMethod) target;
401                         t.EmitAssign (ec, source, !is_statement, this is CompoundAssign);
402                 }
403
404                 public override void Emit (EmitContext ec)
405                 {
406                         Emit (ec, false);
407                 }
408
409                 public override void EmitStatement (EmitContext ec)
410                 {
411                         Emit (ec, true);
412                 }
413
414                 protected override void CloneTo (CloneContext clonectx, Expression t)
415                 {
416                         Assign _target = (Assign) t;
417
418                         _target.target = target.Clone (clonectx);
419                         _target.source = source.Clone (clonectx);
420                 }
421
422                 public override object Accept (StructuralVisitor visitor)
423                 {
424                         return visitor.Visit (this);
425                 }
426         }
427
428         public class SimpleAssign : Assign
429         {
430                 public SimpleAssign (Expression target, Expression source)
431                         : this (target, source, target.Location)
432                 {
433                 }
434
435                 public SimpleAssign (Expression target, Expression source, Location loc)
436                         : base (target, source, loc)
437                 {
438                 }
439
440                 bool CheckEqualAssign (Expression t)
441                 {
442                         if (source is Assign) {
443                                 Assign a = (Assign) source;
444                                 if (t.Equals (a.Target))
445                                         return true;
446                                 return a is SimpleAssign && ((SimpleAssign) a).CheckEqualAssign (t);
447                         }
448                         return t.Equals (source);
449                 }
450
451                 protected override Expression DoResolve (ResolveContext ec)
452                 {
453                         Expression e = base.DoResolve (ec);
454                         if (e == null || e != this)
455                                 return e;
456
457                         if (CheckEqualAssign (target))
458                                 ec.Report.Warning (1717, 3, loc, "Assignment made to same variable; did you mean to assign something else?");
459
460                         return this;
461                 }
462         }
463
464         public class RuntimeExplicitAssign : Assign
465         {
466                 public RuntimeExplicitAssign (Expression target, Expression source)
467                         : base (target, source, target.Location)
468                 {
469                 }
470
471                 protected override Expression ResolveConversions (ResolveContext ec)
472                 {
473                         source = EmptyCast.Create (source, target.Type);
474                         return this;
475                 }
476         }
477
478         //
479         // Compiler generated assign
480         //
481         class CompilerAssign : Assign
482         {
483                 public CompilerAssign (Expression target, Expression source, Location loc)
484                         : base (target, source, loc)
485                 {
486                         if (target.Type != null) {
487                                 type = target.Type;
488                                 eclass = ExprClass.Value;
489                         }
490                 }
491
492                 protected override Expression DoResolve (ResolveContext ec)
493                 {
494                         var expr = base.DoResolve (ec);
495                         var vr = target as VariableReference;
496                         if (vr != null && vr.VariableInfo != null)
497                                 vr.VariableInfo.IsEverAssigned = false;
498
499                         return expr;
500                 }
501
502                 public void UpdateSource (Expression source)
503                 {
504                         base.source = source;
505                 }
506         }
507
508         //
509         // Implements fields and events class initializers
510         //
511         public class FieldInitializer : Assign
512         {
513                 //
514                 // Field initializers are tricky for partial classes. They have to
515                 // share same constructor (block) for expression trees resolve but
516                 // they have they own resolve scope
517                 //
518                 sealed class FieldInitializerContext : ResolveContext
519                 {
520                         ExplicitBlock ctor_block;
521
522                         public FieldInitializerContext (IMemberContext mc, ResolveContext constructorContext)
523                                 : base (mc, Options.FieldInitializerScope | Options.ConstructorScope)
524                         {
525                                 this.ctor_block = constructorContext.CurrentBlock.Explicit;
526                         }
527
528                         public override ExplicitBlock ConstructorBlock {
529                                 get {
530                                         return ctor_block;
531                                 }
532                         }
533                 }
534
535                 //
536                 // Keep resolved value because field initializers have their own rules
537                 //
538                 ExpressionStatement resolved;
539                 IMemberContext mc;
540
541                 public FieldInitializer (FieldSpec spec, Expression expression, IMemberContext mc)
542                         : base (new FieldExpr (spec, expression.Location), expression, expression.Location)
543                 {
544                         this.mc = mc;
545                         if (!spec.IsStatic)
546                                 ((FieldExpr)target).InstanceExpression = new CompilerGeneratedThis (mc.CurrentType, expression.Location);
547                 }
548
549                 protected override Expression DoResolve (ResolveContext ec)
550                 {
551                         // Field initializer can be resolved (fail) many times
552                         if (source == null)
553                                 return null;
554
555                         if (resolved == null) {
556                                 var ctx = new FieldInitializerContext (mc, ec);
557                                 resolved = base.DoResolve (ctx) as ExpressionStatement;
558                         }
559
560                         return resolved;
561                 }
562
563                 public override void EmitStatement (EmitContext ec)
564                 {
565                         if (resolved == null)
566                                 return;
567
568                         //
569                         // Emit sequence symbol info even if we are in compiler generated
570                         // block to allow debugging filed initializers when constructor is
571                         // compiler generated
572                         //
573                         if (ec.HasSet (BuilderContext.Options.OmitDebugInfo)) {
574                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, false)) {
575                                         ec.Mark (loc);
576                                 }
577                         }
578
579                         if (resolved != this)
580                                 resolved.EmitStatement (ec);
581                         else
582                                 base.EmitStatement (ec);
583                 }
584                 
585                 public bool IsDefaultInitializer {
586                         get {
587                                 Constant c = source as Constant;
588                                 if (c == null)
589                                         return false;
590                                 
591                                 FieldExpr fe = (FieldExpr)target;
592                                 return c.IsDefaultInitializer (fe.Type);
593                         }
594                 }
595
596                 public override bool IsSideEffectFree {
597                         get {
598                                 return source.IsSideEffectFree;
599                         }
600                 }
601         }
602
603         //
604         // This class is used for compound assignments.
605         //
606         public class CompoundAssign : Assign
607         {
608                 // This is just a hack implemented for arrays only
609                 public sealed class TargetExpression : Expression
610                 {
611                         readonly Expression child;
612
613                         public TargetExpression (Expression child)
614                         {
615                                 this.child = child;
616                                 this.loc = child.Location;
617                         }
618
619                         public override bool ContainsEmitWithAwait ()
620                         {
621                                 return child.ContainsEmitWithAwait ();
622                         }
623
624                         public override Expression CreateExpressionTree (ResolveContext ec)
625                         {
626                                 throw new NotSupportedException ("ET");
627                         }
628
629                         protected override Expression DoResolve (ResolveContext ec)
630                         {
631                                 type = child.Type;
632                                 eclass = ExprClass.Value;
633                                 return this;
634                         }
635
636                         public override void Emit (EmitContext ec)
637                         {
638                                 child.Emit (ec);
639                         }
640
641                         public override Expression EmitToField (EmitContext ec)
642                         {
643                                 return child.EmitToField (ec);
644                         }
645                 }
646
647                 // Used for underlying binary operator
648                 readonly Binary.Operator op;
649                 Expression right;
650                 Expression left;
651
652                 public CompoundAssign (Binary.Operator op, Expression target, Expression source, Location loc)
653                         : base (target, source, loc)
654                 {
655                         right = source;
656                         this.op = op;
657                 }
658
659                 public CompoundAssign (Binary.Operator op, Expression target, Expression source, Expression left, Location loc)
660                         : this (op, target, source, loc)
661                 {
662                         this.left = left;
663                 }
664
665                 public Binary.Operator Operator {
666                         get {
667                                 return op;
668                         }
669                 }
670
671                 protected override Expression DoResolve (ResolveContext ec)
672                 {
673                         right = right.Resolve (ec);
674                         if (right == null)
675                                 return null;
676
677                         MemberAccess ma = target as MemberAccess;
678                         using (ec.Set (ResolveContext.Options.CompoundAssignmentScope)) {
679                                 target = target.Resolve (ec);
680                         }
681                         
682                         if (target == null)
683                                 return null;
684
685                         if (target is MethodGroupExpr){
686                                 ec.Report.Error (1656, loc,
687                                         "Cannot assign to `{0}' because it is a `{1}'",
688                                         ((MethodGroupExpr)target).Name, target.ExprClassName);
689                                 return null;
690                         }
691
692                         var event_expr = target as EventExpr;
693                         if (event_expr != null) {
694                                 source = Convert.ImplicitConversionRequired (ec, right, target.Type, loc);
695                                 if (source == null)
696                                         return null;
697
698                                 Expression rside;
699                                 if (op == Binary.Operator.Addition)
700                                         rside = EmptyExpression.EventAddition;
701                                 else if (op == Binary.Operator.Subtraction)
702                                         rside = EmptyExpression.EventSubtraction;
703                                 else
704                                         rside = null;
705
706                                 target = target.ResolveLValue (ec, rside);
707                                 if (target == null)
708                                         return null;
709
710                                 eclass = ExprClass.Value;
711                                 type = event_expr.Operator.ReturnType;
712                                 return this;
713                         }
714
715                         //
716                         // Only now we can decouple the original source/target
717                         // into a tree, to guarantee that we do not have side
718                         // effects.
719                         //
720                         if (left == null)
721                                 left = new TargetExpression (target);
722
723                         source = new Binary (op, left, right, true, loc);
724
725                         if (target is DynamicMemberAssignable) {
726                                 Arguments targs = ((DynamicMemberAssignable) target).Arguments;
727                                 source = source.Resolve (ec);
728
729                                 Arguments args = new Arguments (targs.Count + 1);
730                                 args.AddRange (targs);
731                                 args.Add (new Argument (source));
732
733                                 var binder_flags = CSharpBinderFlags.ValueFromCompoundAssignment;
734
735                                 //
736                                 // Compound assignment does target conversion using additional method
737                                 // call, set checked context as the binary operation can overflow
738                                 //
739                                 if (ec.HasSet (ResolveContext.Options.CheckedScope))
740                                         binder_flags |= CSharpBinderFlags.CheckedContext;
741
742                                 if (target is DynamicMemberBinder) {
743                                         source = new DynamicMemberBinder (ma.Name, binder_flags, args, loc).Resolve (ec);
744
745                                         // Handles possible event addition/subtraction
746                                         if (op == Binary.Operator.Addition || op == Binary.Operator.Subtraction) {
747                                                 args = new Arguments (targs.Count + 1);
748                                                 args.AddRange (targs);
749                                                 args.Add (new Argument (right));
750                                                 string method_prefix = op == Binary.Operator.Addition ?
751                                                         Event.AEventAccessor.AddPrefix : Event.AEventAccessor.RemovePrefix;
752
753                                                 var invoke = DynamicInvocation.CreateSpecialNameInvoke (
754                                                         new MemberAccess (right, method_prefix + ma.Name, loc), args, loc).Resolve (ec);
755
756                                                 args = new Arguments (targs.Count);
757                                                 args.AddRange (targs);
758                                                 source = new DynamicEventCompoundAssign (ma.Name, args,
759                                                         (ExpressionStatement) source, (ExpressionStatement) invoke, loc).Resolve (ec);
760                                         }
761                                 } else {
762                                         source = new DynamicIndexBinder (binder_flags, args, loc).Resolve (ec);
763                                 }
764
765                                 return source;
766                         }
767
768                         return base.DoResolve (ec);
769                 }
770
771                 protected override Expression ResolveConversions (ResolveContext ec)
772                 {
773                         //
774                         // LAMESPEC: Under dynamic context no target conversion is happening
775                         // This allows more natual dynamic behaviour but breaks compatibility
776                         // with static binding
777                         //
778                         if (target is RuntimeValueExpression)
779                                 return this;
780
781                         TypeSpec target_type = target.Type;
782
783                         //
784                         // 1. the return type is implicitly convertible to the type of target
785                         //
786                         if (Convert.ImplicitConversionExists (ec, source, target_type)) {
787                                 source = Convert.ImplicitConversion (ec, source, target_type, loc);
788                                 return this;
789                         }
790
791                         //
792                         // Otherwise, if the selected operator is a predefined operator
793                         //
794                         Binary b = source as Binary;
795                         if (b == null && source is ReducedExpression)
796                                 b = ((ReducedExpression) source).OriginalExpression as Binary;
797
798                         if (b != null) {
799                                 //
800                                 // 2a. the operator is a shift operator
801                                 //
802                                 // 2b. the return type is explicitly convertible to the type of x, and
803                                 // y is implicitly convertible to the type of x
804                                 //
805                                 if ((b.Oper & Binary.Operator.ShiftMask) != 0 ||
806                                         Convert.ImplicitConversionExists (ec, right, target_type)) {
807                                         source = Convert.ExplicitConversion (ec, source, target_type, loc);
808                                         return this;
809                                 }
810                         }
811
812                         if (source.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
813                                 Arguments arg = new Arguments (1);
814                                 arg.Add (new Argument (source));
815                                 return new SimpleAssign (target, new DynamicConversion (target_type, CSharpBinderFlags.ConvertExplicit, arg, loc), loc).Resolve (ec);
816                         }
817
818                         right.Error_ValueCannotBeConverted (ec, loc, target_type, false);
819                         return null;
820                 }
821
822                 protected override void CloneTo (CloneContext clonectx, Expression t)
823                 {
824                         CompoundAssign ctarget = (CompoundAssign) t;
825
826                         ctarget.right = ctarget.source = source.Clone (clonectx);
827                         ctarget.target = target.Clone (clonectx);
828                 }
829
830                 public override object Accept (StructuralVisitor visitor)
831                 {
832                         return visitor.Visit (this);
833                 }
834         }
835 }