// Copyright 2004-2008 Novell, Inc
//
using System;
-using System.Reflection;
+
+#if STATIC
+using IKVM.Reflection.Emit;
+#else
using System.Reflection.Emit;
+#endif
namespace Mono.CSharp {
// be data on the stack that it can use to compuatate its value. This is
// for expressions like a [f ()] ++, where you can't call `f ()' twice.
//
- void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
+ void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
/*
For simple assignments, this interface is very simple, EmitAssign is called with source
builder = null;
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return false;
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args = new Arguments (1);
Emit (ec);
}
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
- if (prepare_for_load)
+ if (isCompound)
throw new NotImplementedException ();
source.Emit (ec);
this.loc = loc;
}
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
- return null;
- }
-
public Expression Target {
get { return target; }
}
public Expression Source {
- get { return source; }
+ get {
+ return source;
+ }
+ }
+
+ public override bool ContainsEmitWithAwait ()
+ {
+ return target.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ();
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
+ return null;
}
protected override Expression DoResolve (ResolveContext ec)
return null;
}
- if ((RootContext.Version == LanguageVersion.ISO_1) && (source is MethodGroupExpr)){
- ((MethodGroupExpr) source).ReportUsageError (ec);
- return null;
- }
-
- if (!TypeManager.IsEqual (target_type, source_type)) {
+ if (target_type != source_type) {
Expression resolved = ResolveConversions (ec);
if (resolved != this)
if (tassign == null)
throw new InternalErrorException (target.GetType () + " does not support dynamic assignment");
- var target_object = tassign.MakeAssignExpression (ctx);
+ var target_object = tassign.MakeAssignExpression (ctx, source);
//
// Some hacking is needed as DLR does not support void type and requires
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);
+ System.Linq.Expressions.UnaryExpression source_object;
+ if (ctx.HasSet (BuilderContext.Options.CheckedScope)) {
+ source_object = System.Linq.Expressions.Expression.ConvertChecked (source.MakeExpression (ctx), target_object.Type);
+ } else {
+ source_object = System.Linq.Expressions.Expression.Convert (source.MakeExpression (ctx), target_object.Type);
+ }
+
return System.Linq.Expressions.Expression.Assign (target_object, source_object);
}
#endif
protected virtual Expression ResolveConversions (ResolveContext ec)
{
- source = Convert.ImplicitConversionRequired (ec, source, target.Type, loc);
+ source = Convert.ImplicitConversionRequired (ec, source, target.Type, source.Location);
if (source == null)
return null;
}
}
- public class SimpleAssign : Assign {
+ public class SimpleAssign : Assign
+ {
public SimpleAssign (Expression target, Expression source)
: this (target, source, target.Location)
{
}
}
- // This class implements fields and events class initializers
+ public class RuntimeExplicitAssign : Assign
+ {
+ public RuntimeExplicitAssign (Expression target, Expression source)
+ : base (target, source, target.Location)
+ {
+ }
+
+ protected override Expression ResolveConversions (ResolveContext ec)
+ {
+ source = EmptyCast.Create (source, target.Type);
+ return this;
+ }
+ }
+
+ //
+ // Compiler generated assign
+ //
+ class CompilerAssign : Assign
+ {
+ public CompilerAssign (Expression target, Expression source, Location loc)
+ : base (target, source, loc)
+ {
+ }
+
+ public void UpdateSource (Expression source)
+ {
+ base.source = source;
+ }
+ }
+
+ //
+ // Implements fields and events class initializers
+ //
public class FieldInitializer : Assign
{
+ //
+ // Field initializers are tricky for partial classes. They have to
+ // share same constructor (block) for expression trees resolve but
+ // they have they own resolve scope
+ //
+ sealed class FieldInitializerContext : ResolveContext
+ {
+ ExplicitBlock ctor_block;
+
+ public FieldInitializerContext (IMemberContext mc, ResolveContext constructorContext)
+ : base (mc, Options.FieldInitializerScope | Options.ConstructorScope)
+ {
+ this.ctor_block = constructorContext.CurrentBlock.Explicit;
+ }
+
+ public override ExplicitBlock ConstructorBlock {
+ get {
+ return ctor_block;
+ }
+ }
+ }
+
//
// Keep resolved value because field initializers have their own rules
//
ExpressionStatement resolved;
- IMemberContext rc;
+ IMemberContext mc;
- public FieldInitializer (FieldBase field, Expression expression, IMemberContext rc)
- : base (new FieldExpr (field, expression.Location), expression, expression.Location)
+ public FieldInitializer (FieldSpec spec, Expression expression, IMemberContext mc)
+ : base (new FieldExpr (spec, expression.Location), expression, expression.Location)
{
- this.rc = rc;
- if (!field.IsStatic)
- ((FieldExpr)target).InstanceExpression = CompilerGeneratedThis.Instance;
+ this.mc = mc;
+ if (!spec.IsStatic)
+ ((FieldExpr)target).InstanceExpression = new CompilerGeneratedThis (mc.CurrentType, expression.Location);
}
protected override Expression DoResolve (ResolveContext ec)
return null;
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;
+ var ctx = new FieldInitializerContext (mc, ec);
+ resolved = base.DoResolve (ctx) as ExpressionStatement;
}
return resolved;
base.EmitStatement (ec);
}
- public bool IsComplexInitializer {
- get { return !(source is Constant); }
- }
-
public bool IsDefaultInitializer {
get {
Constant c = source as Constant;
return c.IsDefaultInitializer (fe.Type);
}
}
- }
-
- class EventAddOrRemove : ExpressionStatement {
- EventExpr target;
- Binary.Operator op;
- Expression source;
-
- public EventAddOrRemove (Expression target, Binary.Operator op, Expression source, Location loc)
- {
- this.target = target as EventExpr;
- this.op = op;
- this.source = source;
- this.loc = loc;
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- return new SimpleAssign (target, source).CreateExpressionTree (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;
-
- source = Convert.ImplicitConversionRequired (ec, source, target.Type, loc);
- if (source == null)
- return null;
-
- eclass = ExprClass.Value;
- type = TypeManager.void_type;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- if (RootContext.EvalMode)
- EmitStatement (ec);
- else
- throw new InternalErrorException ("don't know what to emit");
- }
- public override void EmitStatement (EmitContext ec)
- {
- target.EmitAddOrRemove (ec, op == Binary.Operator.Addition, source);
+ public override bool IsSideEffectFree {
+ get {
+ return source.IsSideEffectFree;
+ }
}
}
// This is just a hack implemented for arrays only
public sealed class TargetExpression : Expression
{
- Expression child;
+ readonly Expression child;
+
public TargetExpression (Expression child)
{
this.child = child;
this.loc = child.Location;
}
+ public override bool ContainsEmitWithAwait ()
+ {
+ return child.ContainsEmitWithAwait ();
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
{
child.Emit (ec);
}
+
+ public override Expression EmitToField (EmitContext ec)
+ {
+ return child.EmitToField (ec);
+ }
}
// Used for underlying binary operator
return null;
}
- if (target is EventExpr)
- return new EventAddOrRemove (target, op, right, loc).Resolve (ec);
+ var event_expr = target as EventExpr;
+ if (event_expr != null) {
+ source = Convert.ImplicitConversionRequired (ec, right, target.Type, loc);
+ if (source == null)
+ return null;
+
+ Expression rside;
+ if (op == Binary.Operator.Addition)
+ rside = EmptyExpression.EventAddition;
+ else if (op == Binary.Operator.Subtraction)
+ rside = EmptyExpression.EventSubtraction;
+ else
+ rside = null;
+
+ target = target.ResolveLValue (ec, rside);
+ if (target == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ type = event_expr.Operator.ReturnType;
+ return this;
+ }
//
// Only now we can decouple the original source/target
source = new Binary (op, left, right, true, loc);
- if (target is DynamicMemberBinder) {
- Arguments targs = ((DynamicMemberBinder) target).Arguments;
+ if (target is DynamicMemberAssignable) {
+ Arguments targs = ((DynamicMemberAssignable) target).Arguments;
source = source.Resolve (ec);
- Arguments args = new Arguments (2);
+ Arguments args = new Arguments (targs.Count + 1);
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);
+
+ var binder_flags = CSharpBinderFlags.ValueFromCompoundAssignment;
+
+ //
+ // Compound assignment does target conversion using additional method
+ // call, set checked context as the binary operation can overflow
+ //
+ if (ec.HasSet (ResolveContext.Options.CheckedScope))
+ binder_flags |= CSharpBinderFlags.CheckedContext;
+
+ if (target is DynamicMemberBinder) {
+ source = new DynamicMemberBinder (ma.Name, binder_flags, args, loc).Resolve (ec);
+
+ // Handles possible event addition/subtraction
+ if (op == Binary.Operator.Addition || op == Binary.Operator.Subtraction) {
+ args = new Arguments (targs.Count + 1);
+ 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 (targs.Count);
+ args.AddRange (targs);
+ source = new DynamicEventCompoundAssign (ma.Name, args,
+ (ExpressionStatement) source, (ExpressionStatement) invoke, loc).Resolve (ec);
+ }
+ } else {
+ source = new DynamicIndexBinder (binder_flags, args, loc).Resolve (ec);
}
return source;
protected override Expression ResolveConversions (ResolveContext ec)
{
+ //
+ // LAMESPEC: Under dynamic context no target conversion is happening
+ // This allows more natual dynamic behaviour but breaks compatibility
+ // with static binding
+ //
+ if (target is RuntimeValueExpression)
+ return this;
+
TypeSpec target_type = target.Type;
//
// Otherwise, if the selected operator is a predefined operator
//
Binary b = source as Binary;
+ if (b == null && source is ReducedExpression)
+ b = ((ReducedExpression) source).OriginalExpression as Binary;
+
if (b != null) {
//
// 2a. the operator is a shift operator
}
}
- if (source.Type == InternalType.Dynamic) {
+ if (source.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
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);