* ImportTest.cs (Add1): Fix test on windows.
[mono.git] / mcs / mcs / assign.cs
index c9a31c52f5fa1498bc93dc0fd3c8dcd1fdf004b5..e308aee0e74bd5278dd49c55b28b086cd4a911ed 100644 (file)
@@ -14,7 +14,6 @@
 using System;
 using System.Reflection;
 using System.Reflection.Emit;
-using System.Collections;
 
 namespace Mono.CSharp {
 
@@ -176,27 +175,19 @@ namespace Mono.CSharp {
        ///   Does not happen with a class because a class is a pointer -- so you always
        ///   get the indirection.
        ///
-       ///   The `is_address' stuff is really just a hack. We need to come up with a better
-       ///   way to handle it.
        /// </remarks>
        public class LocalTemporary : Expression, IMemoryLocation, IAssignMethod {
                LocalBuilder builder;
-               bool is_address;
 
-               public LocalTemporary (Type t) : this (t, false) {}
-
-               public LocalTemporary (Type t, bool is_address)
+               public LocalTemporary (Type t)
                {
                        type = t;
                        eclass = ExprClass.Value;
-                       this.is_address = is_address;
                }
 
                public LocalTemporary (LocalBuilder b, Type t)
+                       : this (t)
                {
-                       type = t;
-                       eclass = ExprClass.Value;
-                       loc = Location.Null;
                        builder = b;
                }
 
@@ -213,7 +204,7 @@ namespace Mono.CSharp {
                        return CreateExpressionFactoryCall (ec, "Constant", args);
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        return this;
                }
@@ -231,9 +222,6 @@ namespace Mono.CSharp {
                                throw new InternalErrorException ("Emit without Store, or after Release");
 
                        ig.Emit (OpCodes.Ldloc, builder);
-                       // we need to copy from the pointer
-                       if (is_address)
-                               LoadFromPtr (ig, type);
                }
 
                #region IAssignMethod Members
@@ -265,14 +253,11 @@ namespace Mono.CSharp {
                        get { return builder; }
                }
 
-               // NB: if you have `is_address' on the stack there must
-               // be a managed pointer. Otherwise, it is the type from
-               // the ctor.
                public void Store (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        if (builder == null)
-                               builder = ec.GetTemporaryLocal (is_address ? TypeManager.GetReferenceType (type): type);
+                               builder = ec.GetTemporaryLocal (type);
 
                        ig.Emit (OpCodes.Stloc, builder);
                }
@@ -280,28 +265,25 @@ namespace Mono.CSharp {
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
                        if (builder == null)
-                               builder = ec.GetTemporaryLocal (is_address ? TypeManager.GetReferenceType (type): type);
+                               builder = ec.GetTemporaryLocal (type);
 
-                       // if is_address, than this is just the address anyways,
-                       // so we just return this.
                        ILGenerator ig = ec.ig;
 
-                       if (is_address)
+                       if (builder.LocalType.IsByRef) {
+                               //
+                               // if is_address, than this is just the address anyways,
+                               // so we just return this.
+                               //
                                ig.Emit (OpCodes.Ldloc, builder);
-                       else
+                       } else {
                                ig.Emit (OpCodes.Ldloca, builder);
+                       }
                }
 
                public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
                {
                        type = storey.MutateType (type);
                }
-
-               public bool PointsToAddress {
-                       get {
-                               return is_address;
-                       }
-               }
        }
 
        /// <summary>
@@ -332,7 +314,7 @@ namespace Mono.CSharp {
                        get { return source; }
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        bool ok = true;
                        source = source.Resolve (ec);
@@ -358,8 +340,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if ((RootContext.Version == LanguageVersion.ISO_1) &&
-                                  (source is MethodGroupExpr)){
+                       if ((RootContext.Version == LanguageVersion.ISO_1) && (source is MethodGroupExpr)){
                                ((MethodGroupExpr) source).ReportUsageError (ec);
                                return null;
                        }
@@ -377,7 +358,22 @@ namespace Mono.CSharp {
 #if NET_4_0
                public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
                {
-                       var target_object = target.MakeExpression (ctx);
+                       var tassign = target as IDynamicAssign;
+                       if (tassign == null)
+                               throw new InternalErrorException (target.GetType () + " does not support dynamic assignment");
+
+                       var target_object = tassign.MakeAssignExpression (ctx);
+
+                       //
+                       // Some hacking is needed as DLR does not support void type and requires
+                       // always have object convertible return type to support caching and chaining
+                       //
+                       // We do this by introducing an explicit block which returns RHS value when
+                       // available or null
+                       //
+                       if (target_object.NodeType == System.Linq.Expressions.ExpressionType.Block)
+                               return target_object;
+
                        var source_object = System.Linq.Expressions.Expression.Convert (source.MakeExpression (ctx), target_object.Type);
                        return System.Linq.Expressions.Expression.Assign (target_object, source_object);
                }
@@ -446,7 +442,7 @@ namespace Mono.CSharp {
                        return t.Equals (source);
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        Expression e = base.DoResolve (ec);
                        if (e == null || e != this)
@@ -468,7 +464,7 @@ namespace Mono.CSharp {
                ExpressionStatement resolved;
                IMemberContext rc;
 
-               public FieldInitializer (FieldBuilder field, Expression expression, IMemberContext rc)
+               public FieldInitializer (FieldBase field, Expression expression, IMemberContext rc)
                        : base (new FieldExpr (field, expression.Location), expression, expression.Location)
                {
                        this.rc = rc;
@@ -476,7 +472,7 @@ namespace Mono.CSharp {
                                ((FieldExpr)target).InstanceExpression = CompilerGeneratedThis.Instance;
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        // Field initializer can be resolved (fail) many times
                        if (source == null)
@@ -485,7 +481,7 @@ namespace Mono.CSharp {
                        if (resolved == null) {
                                //
                                // Field initializers are tricky for partial classes. They have to
-                               // share same costructor (block) but they have they own resolve scope.
+                               // share same constructor (block) but they have they own resolve scope.
                                //
 
                                IMemberContext old = ec.MemberContext;
@@ -546,7 +542,7 @@ namespace Mono.CSharp {
                        return new SimpleAssign (target, source).CreateExpressionTree (ec);
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        if (op != Binary.Operator.Addition && op != Binary.Operator.Subtraction)
                                target.Error_AssignmentEventOnly (ec);
@@ -598,7 +594,7 @@ namespace Mono.CSharp {
                                throw new NotSupportedException ("ET");
                        }
 
-                       public override Expression DoResolve (ResolveContext ec)
+                       protected override Expression DoResolve (ResolveContext ec)
                        {
                                type = child.Type;
                                eclass = ExprClass.Value;
@@ -629,7 +625,7 @@ namespace Mono.CSharp {
                        this.left = left;
                }
 
-               public override Expression DoResolve (ResolveContext ec)
+               protected override Expression DoResolve (ResolveContext ec)
                {
                        right = right.Resolve (ec);
                        if (right == null)
@@ -651,7 +647,7 @@ namespace Mono.CSharp {
                        }
 
                        if (target is EventExpr)
-                               return new EventAddOrRemove (target, op, right, loc).DoResolve (ec);
+                               return new EventAddOrRemove (target, op, right, loc).Resolve (ec);
 
                        //
                        // Only now we can decouple the original source/target
@@ -663,7 +659,6 @@ namespace Mono.CSharp {
 
                        source = new Binary (op, left, right, true);
 
-                       // TODO: TargetExpression breaks MemberAccess composition
                        if (target is DynamicMemberBinder) {
                                Arguments targs = ((DynamicMemberBinder) target).Arguments;
                                source = source.Resolve (ec);
@@ -671,7 +666,7 @@ namespace Mono.CSharp {
                                Arguments args = new Arguments (2);
                                args.AddRange (targs);
                                args.Add (new Argument (source));
-                               source = new DynamicMemberBinder (true, ma.Name, args, loc).Resolve (ec);
+                               source = new DynamicMemberBinder (ma.Name, args, loc).ResolveLValue (ec, right);
 
                                // Handles possible event addition/subtraction
                                if (op == Binary.Operator.Addition || op == Binary.Operator.Subtraction) {
@@ -681,7 +676,7 @@ namespace Mono.CSharp {
                                        string method_prefix = op == Binary.Operator.Addition ?
                                                Event.AEventAccessor.AddPrefix : Event.AEventAccessor.RemovePrefix;
 
-                                       Expression invoke = new DynamicInvocation (
+                                       var invoke = DynamicInvocation.CreateSpecialNameInvoke (
                                                new MemberAccess (right, method_prefix + ma.Name, loc), args, loc).Resolve (ec);
 
                                        args = new Arguments (1);
@@ -726,6 +721,12 @@ namespace Mono.CSharp {
                                }
                        }
 
+                       if (TypeManager.IsDynamicType (source.Type)) {
+                               Arguments arg = new Arguments (1);
+                               arg.Add (new Argument (source));
+                               return new SimpleAssign (target, new DynamicConversion (target_type, CSharpBinderFlags.ConvertExplicit, arg, loc), loc).Resolve (ec);
+                       }
+
                        right.Error_ValueCannotBeConverted (ec, loc, target_type, false);
                        return null;
                }