// 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 {
}
public Expression Source {
- get { return source; }
+ get {
+ return source;
+ }
}
protected override Expression DoResolve (ResolveContext ec)
return null;
}
- if (!TypeManager.IsEqual (target_type, source_type)) {
+ if (target_type != source_type) {
Expression resolved = ResolveConversions (ec);
if (resolved != this)
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
}
}
- 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 (FieldSpec spec, Expression expression, IMemberContext rc)
+ public FieldInitializer (FieldSpec spec, Expression expression, IMemberContext mc)
: base (new FieldExpr (spec, expression.Location), expression, expression.Location)
{
- this.rc = rc;
+ this.mc = mc;
if (!spec.IsStatic)
((FieldExpr)target).InstanceExpression = CompilerGeneratedThis.Instance;
}
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;
"Cannot assign to `{0}' because it is a `{1}'",
((MethodGroupExpr)target).Name, target.ExprClassName);
return null;
- }\r
-\r
+ }
+
var event_expr = target as EventExpr;
if (event_expr != null) {
source = Convert.ImplicitConversionRequired (ec, right, target.Type, loc);
else
rside = null;
- target = target.ResolveLValue (ec, rside);\r
- if (target == null)\r
- return null;\r
-\r
- eclass = ExprClass.Value;\r
+ target = target.ResolveLValue (ec, rside);
+ if (target == null)
+ return null;
+
+ eclass = ExprClass.Value;
type = event_expr.Operator.ReturnType;
return this;
}
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