X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fassign.cs;h=e308aee0e74bd5278dd49c55b28b086cd4a911ed;hb=af923bf52b6745a7cacd4aef5acb4c8720f0dd5a;hp=424a7c6275f0496bc3c0762e19aca7ed0d43635b;hpb=b68203fdbf0007b9fa182656633e9f98c0668990;p=mono.git diff --git a/mcs/mcs/assign.cs b/mcs/mcs/assign.cs index 424a7c6275f..e308aee0e74 100644 --- a/mcs/mcs/assign.cs +++ b/mcs/mcs/assign.cs @@ -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. /// 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; } @@ -206,19 +197,19 @@ namespace Mono.CSharp { builder = null; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { - ArrayList args = new ArrayList (1); + Arguments args = new Arguments (1); args.Add (new Argument (this)); - return CreateExpressionFactoryCall ("Constant", args); + return CreateExpressionFactoryCall (ec, "Constant", args); } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { return this; } - public override Expression DoResolveLValue (EmitContext ec, Expression right_side) + public override Expression DoResolveLValue (ResolveContext ec, Expression right_side) { 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 @@ -253,13 +241,6 @@ namespace Mono.CSharp { source.Emit (ec); - // HACK: variable is already emitted when source is an initializer - if (source is NewInitialize) { - if (leave_copy) - Emit (ec); - return; - } - Store (ec); if (leave_copy) @@ -272,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); } @@ -287,22 +265,24 @@ 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 bool PointsToAddress { - get { - return is_address; - } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); } } @@ -310,7 +290,7 @@ namespace Mono.CSharp { /// The Assign node takes care of assigning the value of source into /// the expression represented by target. /// - public class Assign : ExpressionStatement { + public abstract class Assign : ExpressionStatement { protected Expression target, source; protected Assign (Expression target, Expression source, Location loc) @@ -320,9 +300,9 @@ namespace Mono.CSharp { this.loc = loc; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { - Report.Error (832, loc, "An expression tree cannot contain an assignment operator"); + ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator"); return null; } @@ -334,7 +314,7 @@ namespace Mono.CSharp { get { return source; } } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { bool ok = true; source = source.Resolve (ec); @@ -344,7 +324,7 @@ namespace Mono.CSharp { source = EmptyExpression.Null; } - target = target.ResolveLValue (ec, source, Location); + target = target.ResolveLValue (ec, source); if (target == null || !ok) return null; @@ -356,38 +336,48 @@ namespace Mono.CSharp { type = target_type; if (!(target is IAssignMethod)) { - Error_ValueAssignment (loc); + Error_ValueAssignment (ec, loc); return null; } - if ((source.eclass == ExprClass.Type) && (source is TypeExpr)) { - source.Error_UnexpectedKind (ec.DeclContainer, "variable or value", loc); - return null; - } else if ((RootContext.Version == LanguageVersion.ISO_1) && - (source is MethodGroupExpr)){ - ((MethodGroupExpr) source).ReportUsageError (); + if ((RootContext.Version == LanguageVersion.ISO_1) && (source is MethodGroupExpr)){ + ((MethodGroupExpr) source).ReportUsageError (ec); return null; } - if (TypeManager.IsEqual (target_type, source_type)) { - if (target.eclass == ExprClass.Variable) { - New n = source as New; - if (n == null) - return this; - - if (n.HasInitializer) { - n.SetTargetVariable (target); - } else if (target_type.IsValueType) { - n.SetTargetVariable (target); - return n; - } - } + if (!TypeManager.IsEqual (target_type, source_type)) { + Expression resolved = ResolveConversions (ec); - return this; + if (resolved != this) + return resolved; } - return ResolveConversions (ec); + return this; + } + +#if NET_4_0 + public override System.Linq.Expressions.Expression MakeExpression (BuilderContext 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); } +#endif public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { @@ -396,7 +386,7 @@ namespace Mono.CSharp { type = storey.MutateType (type); } - protected virtual Expression ResolveConversions (EmitContext ec) + protected virtual Expression ResolveConversions (ResolveContext ec) { source = Convert.ImplicitConversionRequired (ec, source, target.Type, loc); if (source == null) @@ -407,7 +397,8 @@ namespace Mono.CSharp { void Emit (EmitContext ec, bool is_statement) { - ((IAssignMethod) target).EmitAssign (ec, source, !is_statement, this is CompoundAssign); + IAssignMethod t = (IAssignMethod) target; + t.EmitAssign (ec, source, !is_statement, this is CompoundAssign); } public override void Emit (EmitContext ec) @@ -429,7 +420,7 @@ namespace Mono.CSharp { } } - class SimpleAssign : Assign { + public class SimpleAssign : Assign { public SimpleAssign (Expression target, Expression source) : this (target, source, target.Location) { @@ -451,14 +442,14 @@ namespace Mono.CSharp { return t.Equals (source); } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { Expression e = base.DoResolve (ec); if (e == null || e != this) return e; if (CheckEqualAssign (target)) - Report.Warning (1717, 3, loc, "Assignment made to same variable; did you mean to assign something else?"); + ec.Report.Warning (1717, 3, loc, "Assignment made to same variable; did you mean to assign something else?"); return this; } @@ -471,22 +462,37 @@ namespace Mono.CSharp { // Keep resolved value because field initializers have their own rules // ExpressionStatement resolved; + IMemberContext rc; - public FieldInitializer (FieldBuilder field, Expression expression) - : base (new FieldExpr (field, expression.Location, true), expression, expression.Location) + public FieldInitializer (FieldBase field, Expression expression, IMemberContext rc) + : base (new FieldExpr (field, expression.Location), expression, expression.Location) { + this.rc = rc; if (!field.IsStatic) ((FieldExpr)target).InstanceExpression = CompilerGeneratedThis.Instance; } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { // Field initializer can be resolved (fail) many times if (source == null) return null; - if (resolved == null) - resolved = base.DoResolve (ec) as ExpressionStatement; + if (resolved == null) { + // + // Field initializers are tricky for partial classes. They have to + // share same constructor (block) but they have they own resolve scope. + // + + IMemberContext old = ec.MemberContext; + ec.MemberContext = rc; + + using (ec.Set (ResolveContext.Options.FieldInitializerScope)) { + resolved = base.DoResolve (ec) as ExpressionStatement; + } + + ec.MemberContext = old; + } return resolved; } @@ -531,13 +537,16 @@ namespace Mono.CSharp { this.loc = loc; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { return new SimpleAssign (target, source).CreateExpressionTree (ec); } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { + if (op != Binary.Operator.Addition && op != Binary.Operator.Subtraction) + target.Error_AssignmentEventOnly (ec); + source = source.Resolve (ec); if (source == null) return null; @@ -553,7 +562,10 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - throw new InternalErrorException ("don't know what to emit"); + if (RootContext.EvalMode) + EmitStatement (ec); + else + throw new InternalErrorException ("don't know what to emit"); } public override void EmitStatement (EmitContext ec) @@ -565,36 +577,25 @@ namespace Mono.CSharp { // // This class is used for compound assignments. // - class CompoundAssign : Assign { - Binary.Operator op; - Expression original_source; - - public CompoundAssign (Binary.Operator op, Expression target, Expression source) - : base (target, source, target.Location) + public class CompoundAssign : Assign + { + // This is just a hack implemented for arrays only + public sealed class TargetExpression : Expression { - original_source = source; - this.op = op; - } - - // !!! What a stupid name - public class Helper : Expression { Expression child; - public Helper (Expression child) + public TargetExpression (Expression child) { this.child = child; this.loc = child.Location; } - public override Expression CreateExpressionTree (EmitContext ec) + public override Expression CreateExpressionTree (ResolveContext ec) { throw new NotSupportedException ("ET"); } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext ec) { - child = child.Resolve (ec); - if (child == null) - return null; type = child.Type; eclass = ExprClass.Value; return this; @@ -606,13 +607,32 @@ namespace Mono.CSharp { } } - public override Expression DoResolve (EmitContext ec) + // Used for underlying binary operator + readonly Binary.Operator op; + Expression right; + Expression left; + + public CompoundAssign (Binary.Operator op, Expression target, Expression source) + : base (target, source, target.Location) + { + right = source; + this.op = op; + } + + public CompoundAssign (Binary.Operator op, Expression target, Expression source, Expression left) + : this (op, target, source) + { + this.left = left; + } + + protected override Expression DoResolve (ResolveContext ec) { - original_source = original_source.Resolve (ec); - if (original_source == null) + right = right.Resolve (ec); + if (right == null) return null; - using (ec.Set (EmitContext.Flags.InCompoundAssignment)) { + MemberAccess ma = target as MemberAccess; + using (ec.Set (ResolveContext.Options.CompoundAssignmentScope)) { target = target.Resolve (ec); } @@ -620,58 +640,94 @@ namespace Mono.CSharp { return null; if (target is MethodGroupExpr){ - Error_CannotAssign (((MethodGroupExpr)target).Name, target.ExprClassName); + ec.Report.Error (1656, loc, + "Cannot assign to `{0}' because it is a `{1}'", + ((MethodGroupExpr)target).Name, target.ExprClassName); return null; } if (target is EventExpr) - return new EventAddOrRemove (target, op, original_source, loc).DoResolve (ec); + return new EventAddOrRemove (target, op, right, loc).Resolve (ec); // // Only now we can decouple the original source/target // into a tree, to guarantee that we do not have side // effects. // - source = new Binary (op, new Helper (target), original_source, true); + if (left == null) + left = new TargetExpression (target); + + source = new Binary (op, left, right, true); + + if (target is DynamicMemberBinder) { + Arguments targs = ((DynamicMemberBinder) target).Arguments; + source = source.Resolve (ec); + + Arguments args = new Arguments (2); + args.AddRange (targs); + args.Add (new Argument (source)); + source = new DynamicMemberBinder (ma.Name, args, loc).ResolveLValue (ec, right); + + // Handles possible event addition/subtraction + if (op == Binary.Operator.Addition || op == Binary.Operator.Subtraction) { + args = new Arguments (2); + args.AddRange (targs); + args.Add (new Argument (right)); + string method_prefix = op == Binary.Operator.Addition ? + Event.AEventAccessor.AddPrefix : Event.AEventAccessor.RemovePrefix; + + var invoke = DynamicInvocation.CreateSpecialNameInvoke ( + new MemberAccess (right, method_prefix + ma.Name, loc), args, loc).Resolve (ec); + + args = new Arguments (1); + args.AddRange (targs); + source = new DynamicEventCompoundAssign (ma.Name, args, + (ExpressionStatement) source, (ExpressionStatement) invoke, loc).Resolve (ec); + } + + return source; + } + return base.DoResolve (ec); } - protected override Expression ResolveConversions (EmitContext ec) + protected override Expression ResolveConversions (ResolveContext ec) { - // source might have changed to BinaryDelegate Type target_type = target.Type; - Type source_type = source.Type; - Binary b = source as Binary; - if (b == null) - return base.ResolveConversions (ec); - - // FIXME: Restrict only to predefined operators // - // 1. if the source is explicitly convertible to the - // target_type + // 1. the return type is implicitly convertible to the type of target // - source = Convert.ExplicitConversion (ec, source, target_type, loc); - if (source == null){ - original_source.Error_ValueCannotBeConverted (ec, loc, target_type, true); - return null; + if (Convert.ImplicitConversionExists (ec, source, target_type)) { + source = Convert.ImplicitConversion (ec, source, target_type, loc); + return this; } // - // 2. and the original right side is implicitly convertible to - // the type of target + // Otherwise, if the selected operator is a predefined operator // - if (Convert.ImplicitConversionExists (ec, original_source, target_type)) - return this; + Binary b = source as Binary; + if (b != null) { + // + // 2a. the operator is a shift operator + // + // 2b. the return type is explicitly convertible to the type of x, and + // y is implicitly convertible to the type of x + // + if ((b.Oper & Binary.Operator.ShiftMask) != 0 || + Convert.ImplicitConversionExists (ec, right, target_type)) { + source = Convert.ExplicitConversion (ec, source, target_type, loc); + return this; + } + } - // - // In the spec 2.4 they added: or if type of the target is int - // and the operator is a shift operator... - // - if (source_type == TypeManager.int32_type && (b.Oper & Binary.Operator.ShiftMask) != 0) - return this; + 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); + } - original_source.Error_ValueCannotBeConverted (ec, loc, target_type, false); + right.Error_ValueCannotBeConverted (ec, loc, target_type, false); return null; } @@ -679,7 +735,7 @@ namespace Mono.CSharp { { CompoundAssign ctarget = (CompoundAssign) t; - ctarget.original_source = ctarget.source = source.Clone (clonectx); + ctarget.right = ctarget.source = source.Clone (clonectx); ctarget.target = target.Clone (clonectx); } }