namespace Mono.CSharp {
using System;
using System.Collections;
+ using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
#if NET_4_0
+ using System.Linq;
using SLE = System.Linq.Expressions;
#endif
}
}
- public class ParenthesizedExpression : Expression
+ public class ParenthesizedExpression : ShimExpression
{
- public Expression Expr;
-
public ParenthesizedExpression (Expression expr)
+ : base (expr)
{
- Expr = expr;
loc = expr.Location;
}
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
public override Expression DoResolve (ResolveContext ec)
{
- Expr = Expr.Resolve (ec);
- return Expr;
+ return expr.Resolve (ec);
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
- return Expr.DoResolveLValue (ec, right_side);
- }
-
- public override void Emit (EmitContext ec)
- {
- throw new Exception ("Should not happen");
- }
-
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- ParenthesizedExpression target = (ParenthesizedExpression) t;
-
- target.Expr = Expr.Clone (clonectx);
+ return expr.DoResolveLValue (ec, right_side);
}
}
throw new NotImplementedException (oper.ToString ());
}
+#if NET_4_0
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
+ {
+ var expr = Expr.MakeExpression (ctx);
+ bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
+
+ switch (Oper) {
+ case Operator.UnaryNegation:
+ return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
+ case Operator.LogicalNot:
+ return SLE.Expression.Not (expr);
+ case Operator.OnesComplement:
+ return SLE.Expression.OnesComplement (expr);
+ default:
+ throw new NotImplementedException (Oper.ToString ());
+ }
+ }
+#endif
+
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
type = storey.MutateType (type);
Type[] predefined = predefined_operators [(int) Oper];
foreach (Type t in predefined) {
- Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
+ Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
if (oper_expr == null)
continue;
}
Mode mode;
- bool is_expr = false;
- bool recurse = false;
+ bool is_expr, recurse;
Expression expr;
- //
- // This is expensive for the simplest case.
- //
- UserOperatorCall method;
+ // Holds the real operation
+ Expression operation;
public UnaryMutator (Mode m, Expression e)
{
expr = e;
}
- static string OperName (Mode mode)
- {
- return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
- "++" : "--";
- }
-
- /// <summary>
- /// Returns whether an object of type `t' can be incremented
- /// or decremented with add/sub (ie, basically whether we can
- /// use pre-post incr-decr operations on it, but it is not a
- /// System.Decimal, which we require operator overloading to catch)
- /// </summary>
- static bool IsIncrementableNumber (Type t)
- {
- return (t == TypeManager.sbyte_type) ||
- (t == TypeManager.byte_type) ||
- (t == TypeManager.short_type) ||
- (t == TypeManager.ushort_type) ||
- (t == TypeManager.int32_type) ||
- (t == TypeManager.uint32_type) ||
- (t == TypeManager.int64_type) ||
- (t == TypeManager.uint64_type) ||
- (t == TypeManager.char_type) ||
- (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
- (t == TypeManager.float_type) ||
- (t == TypeManager.double_type) ||
- (t.IsPointer && t != TypeManager.void_ptr_type);
- }
-
- Expression ResolveOperator (ResolveContext ec)
- {
- type = expr.Type;
-
- //
- // The operand of the prefix/postfix increment decrement operators
- // should be an expression that is classified as a variable,
- // a property access or an indexer access
- //
- if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
- expr = expr.ResolveLValue (ec, expr);
- } else {
- ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
- }
-
- //
- // Step 1: Perform Operator Overload location
- //
- MethodGroupExpr mg;
- string op_name;
-
- if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
- op_name = Operator.GetMetadataName (Operator.OpType.Increment);
- else
- op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
-
- mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
-
- if (mg != null) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
- mg = mg.OverloadResolve (ec, ref args, false, loc);
- if (mg == null)
- return null;
-
- method = new UserOperatorCall (mg, args, null, loc);
- Convert.ImplicitConversionRequired (ec, method, type, loc);
- return this;
- }
-
- if (!IsIncrementableNumber (type)) {
- ec.Report.Error (187, loc, "No such operator '" + OperName (mode) + "' defined for type '" +
- TypeManager.CSharpName (type) + "'");
- return null;
- }
-
- return this;
- }
-
public override Expression CreateExpressionTree (ResolveContext ec)
{
return new SimpleAssign (this, this).CreateExpressionTree (ec);
return ResolveOperator (ec);
}
- //
- // Loads the proper "1" into the stack based on the type, then it emits the
- // opcode for the operation requested
- //
- void LoadOneAndEmitOp (EmitContext ec, Type t)
- {
- //
- // Measure if getting the typecode and using that is more/less efficient
- // that comparing types. t.GetTypeCode() is an internal call.
- //
- ILGenerator ig = ec.ig;
-
- if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
- LongConstant.EmitLong (ig, 1);
- else if (t == TypeManager.double_type)
- ig.Emit (OpCodes.Ldc_R8, 1.0);
- else if (t == TypeManager.float_type)
- ig.Emit (OpCodes.Ldc_R4, 1.0F);
- else if (t.IsPointer){
- Type et = TypeManager.GetElementType (t);
- int n = GetTypeSize (et);
-
- if (n == 0)
- ig.Emit (OpCodes.Sizeof, et);
- else {
- IntConstant.EmitInt (ig, n);
- ig.Emit (OpCodes.Conv_I);
- }
- } else
- ig.Emit (OpCodes.Ldc_I4_1);
-
- //
- // Now emit the operation
- //
-
- Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
- Binary.EmitOperatorOpcode (ec, op, t);
-
- if (t == TypeManager.sbyte_type){
- if (ec.HasSet (EmitContext.Options.CheckedScope))
- ig.Emit (OpCodes.Conv_Ovf_I1);
- else
- ig.Emit (OpCodes.Conv_I1);
- } else if (t == TypeManager.byte_type){
- if (ec.HasSet (EmitContext.Options.CheckedScope))
- ig.Emit (OpCodes.Conv_Ovf_U1);
- else
- ig.Emit (OpCodes.Conv_U1);
- } else if (t == TypeManager.short_type){
- if (ec.HasSet (EmitContext.Options.CheckedScope))
- ig.Emit (OpCodes.Conv_Ovf_I2);
- else
- ig.Emit (OpCodes.Conv_I2);
- } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
- if (ec.HasSet (EmitContext.Options.CheckedScope))
- ig.Emit (OpCodes.Conv_Ovf_U2);
- else
- ig.Emit (OpCodes.Conv_U2);
- }
-
- }
-
void EmitCode (EmitContext ec, bool is_expr)
{
recurse = true;
//
if (recurse) {
((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
- if (method == null)
- LoadOneAndEmitOp (ec, expr.Type);
- else
- ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
+
+ operation.Emit (ec);
+
recurse = false;
return;
}
//
string GetOperatorExpressionTypeName ()
{
- if ((mode & Mode.IsDecrement) != 0)
- return "Decrement";
+ return IsDecrement ? "Decrement" : "Increment";
+ }
+
+ bool IsDecrement {
+ get { return (mode & Mode.IsDecrement) != 0; }
+ }
+
+ //
+ // Returns whether an object of type `t' can be incremented
+ // or decremented with add/sub (ie, basically whether we can
+ // use pre-post incr-decr operations on it, but it is not a
+ // System.Decimal, which we require operator overloading to catch)
+ //
+ static bool IsPredefinedOperator (Type t)
+ {
+ return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
+ TypeManager.IsEnumType (t) ||
+ t.IsPointer && t != TypeManager.void_ptr_type;
+ }
- return "Increment";
+#if NET_4_0
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
+ {
+ var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
+ var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
+ return SLE.Expression.Assign (target, source);
}
+#endif
protected override void CloneTo (CloneContext clonectx, Expression t)
{
target.expr = expr.Clone (clonectx);
}
+
+ Expression ResolveOperator (ResolveContext ec)
+ {
+ type = expr.Type;
+
+ if (expr is RuntimeValueExpression) {
+ operation = expr;
+ } else {
+ // Use itself at the top of the stack
+ operation = new EmptyExpression (type);
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+ expr = expr.ResolveLValue (ec, expr);
+ } else {
+ ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
+ }
+
+ //
+ // 1. Check predefined types
+ //
+ if (IsPredefinedOperator (type)) {
+ // TODO: Move to IntConstant once I get rid of int32_type
+ var one = new IntConstant (1, loc);
+
+ // TODO: Cache this based on type when using EmptyExpression in
+ // context cache
+ Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+ operation = new Binary (op, operation, one);
+ operation = operation.Resolve (ec);
+ if (operation.Type != type)
+ operation = Convert.ExplicitNumericConversion (operation, type);
+
+ return this;
+ }
+
+ //
+ // Step 2: Perform Operator Overload location
+ //
+ MethodGroupExpr mg;
+ string op_name;
+
+ if (IsDecrement)
+ op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
+ else
+ op_name = Operator.GetMetadataName (Operator.OpType.Increment);
+
+ mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+
+ if (mg != null) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+ mg = mg.OverloadResolve (ec, ref args, false, loc);
+ if (mg == null)
+ return null;
+
+ args[0].Expr = operation;
+ operation = new UserOperatorCall (mg, args, null, loc);
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ return this;
+ }
+
+ string name = IsDecrement ?
+ Operator.GetName (Operator.OpType.Decrement) :
+ Operator.GetName (Operator.OpType.Increment);
+
+ Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
+ return null;
+ }
}
/// <summary>
if (do_isinst)
ig.Emit (OpCodes.Isinst, type);
-#if GMCS_SOURCE
if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
ig.Emit (OpCodes.Unbox_Any, type);
-#endif
}
public override Expression DoResolve (ResolveContext ec)
/// FIXME: Cast expressions have an unusual set of parsing
/// rules, we need to figure those out.
/// </summary>
- public class Cast : Expression {
+ public class Cast : ShimExpression {
Expression target_type;
- Expression expr;
public Cast (Expression cast_type, Expression expr)
: this (cast_type, expr, cast_type.Location)
}
public Cast (Expression cast_type, Expression expr, Location loc)
+ : base (expr)
{
this.target_type = cast_type;
- this.expr = expr;
this.loc = loc;
}
get { return target_type; }
}
- public Expression Expr {
- get { return expr; }
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
public override Expression DoResolve (ResolveContext ec)
{
expr = expr.Resolve (ec);
} else if (TypeManager.IsDynamicType (expr.Type)) {
Arguments arg = new Arguments (1);
arg.Add (new Argument (expr));
- return new DynamicConversion (type, true, arg, loc).Resolve (ec);
+ return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
}
expr = Convert.ExplicitConversion (ec, expr, type, loc);
return expr;
}
- public override void Emit (EmitContext ec)
- {
- throw new Exception ("Should not happen");
- }
-
protected override void CloneTo (CloneContext clonectx, Expression t)
{
Cast target = (Cast) t;
target.expr = expr.Clone (clonectx);
}
}
+
+ public class ImplicitCast : ShimExpression
+ {
+ bool arrayAccess;
+
+ public ImplicitCast (Expression expr, Type target, bool arrayAccess)
+ : base (expr)
+ {
+ this.loc = expr.Location;
+ this.type = target;
+ this.arrayAccess = arrayAccess;
+ }
+
+ public override Expression DoResolve (ResolveContext ec)
+ {
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ if (arrayAccess)
+ expr = ConvertExpressionToArrayIndex (ec, expr);
+ else
+ expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
+
+ return expr;
+ }
+ }
//
// C# 2.0 Default value expression
{
b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
- Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
+ Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
if (e != null || ec.Report.Errors != prev_e)
return e;
} else if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !TypeManager.IsDynamicType (left.Type) &&
- ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
+ ((lc != null && lc.IsDefaultValue && !(lc is NullLiteral)) || (rc != null && rc.IsDefaultValue && !(rc is NullLiteral)))) {
if ((ResolveOperator (ec)) == null) {
Error_OperatorCannotBeApplied (ec, left, right);
switch (oper) {
case Operator.Addition:
return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
+ case Operator.BitwiseAnd:
+ return SLE.Expression.And (le, re);
+ case Operator.BitwiseOr:
+ return SLE.Expression.Or (le, re);
+ case Operator.Division:
+ return SLE.Expression.Divide (le, re);
+ case Operator.Equality:
+ return SLE.Expression.Equal (le, re);
+ case Operator.ExclusiveOr:
+ return SLE.Expression.ExclusiveOr (le, re);
+ case Operator.GreaterThan:
+ return SLE.Expression.GreaterThan (le, re);
+ case Operator.GreaterThanOrEqual:
+ return SLE.Expression.GreaterThanOrEqual (le, re);
+ case Operator.Inequality:
+ return SLE.Expression.NotEqual (le, re);
+ case Operator.LeftShift:
+ return SLE.Expression.LeftShift (le, re);
+ case Operator.LessThan:
+ return SLE.Expression.LessThan (le, re);
+ case Operator.LessThanOrEqual:
+ return SLE.Expression.LessThanOrEqual (le, re);
+ case Operator.LogicalAnd:
+ return SLE.Expression.AndAlso (le, re);
+ case Operator.LogicalOr:
+ return SLE.Expression.OrElse (le, re);
+ case Operator.Modulus:
+ return SLE.Expression.Modulo (le, re);
+ case Operator.Multiply:
+ return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
+ case Operator.RightShift:
+ return SLE.Expression.RightShift (le, re);
+ case Operator.Subtraction:
+ return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
default:
throw new NotImplementedException (oper.ToString ());
}
return expr;
//
- // TODO: Need to corectly implemented Coumpound Assigment for all operators
// Section: 7.16.2
//
- if (Convert.ImplicitConversionExists (ec, left, rtype))
+
+ //
+ // If the return type of the selected operator is implicitly convertible to the type of x
+ //
+ if (Convert.ImplicitConversionExists (ec, expr, ltype))
return expr;
- if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+ //
+ // Otherwise, if the selected operator is a predefined operator, if the return type of the
+ // selected operator is explicitly convertible to the type of x, and if y is implicitly
+ // convertible to the type of x or the operator is a shift operator, then the operation
+ // is evaluated as x = (T)(x op y), where T is the type of x
+ //
+ expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
+ if (expr == null)
return null;
- expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
- return expr;
+ if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
+ return expr;
+
+ return null;
}
//
if (lgen) {
if (!TypeManager.IsReferenceType (l))
return null;
- left = new BoxedCast (left, TypeManager.object_type);
+
+ l = TypeManager.object_type;
+ left = new BoxedCast (left, l);
} else if (l.IsInterface) {
l = TypeManager.object_type;
} else if (TypeManager.IsStruct (l)) {
if (rgen) {
if (!TypeManager.IsReferenceType (r))
return null;
- right = new BoxedCast (right, TypeManager.object_type);
+
+ r = TypeManager.object_type;
+ right = new BoxedCast (right, r);
} else if (r.IsInterface) {
r = TypeManager.object_type;
} else if (TypeManager.IsStruct (r)) {
if (best_operator == null) {
ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
- OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
+ OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
best_operator = po;
break;
public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
{
- Arguments binder_args = new Arguments (4);
+ Arguments binder_args = new Arguments (3);
MemberAccess sle = new MemberAccess (new MemberAccess (
new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
- MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
+ CSharpBinderFlags flags = 0;
+ if (ec.HasSet (ResolveContext.Options.CheckedScope))
+ flags = CSharpBinderFlags.CheckedContext;
- binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
- binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
+ if ((oper & Operator.LogicalMask) != 0)
+ flags |= CSharpBinderFlags.BinaryOperationLogical;
- bool member_access = left is DynamicMemberBinder || right is DynamicMemberBinder;
- binder_args.Add (new Argument (new BoolLiteral (member_access, loc)));
+ binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
+ binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
- return new New (new MemberAccess (binder, "CSharpBinaryOperationBinder", loc), binder_args, loc);
+ return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
}
public override Expression CreateExpressionTree (ResolveContext ec)
}
}
}
+
+ //
+ // A boolean-expression is an expression that yields a result
+ // of type bool
+ //
+ public class BooleanExpression : ShimExpression
+ {
+ public BooleanExpression (Expression expr)
+ : base (expr)
+ {
+ this.loc = expr.Location;
+ }
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ // TODO: We should emit IsTrue (v4) instead of direct user operator
+ // call but that would break csc compatibility
+ return base.CreateExpressionTree (ec);
+ }
+
+ public override Expression DoResolve (ResolveContext ec)
+ {
+ // A boolean-expression is required to be of a type
+ // that can be implicitly converted to bool or of
+ // a type that implements operator true
+
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ Assign ass = expr as Assign;
+ if (ass != null && ass.Source is Constant) {
+ ec.Report.Warning (665, 3, loc,
+ "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
+ }
+
+ if (expr.Type == TypeManager.bool_type)
+ return expr;
+
+ if (TypeManager.IsDynamicType (expr.Type)) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+ return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
+ }
+
+ type = TypeManager.bool_type;
+ Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
+ if (converted != null)
+ return converted;
+
+ //
+ // If no implicit conversion to bool exists, try using `operator true'
+ //
+ converted = GetOperatorTrue (ec, expr, loc);
+ if (converted == null) {
+ expr.Error_ValueCannotBeConverted (ec, loc, type, false);
+ return null;
+ }
+
+ return converted;
+ }
+ }
/// <summary>
/// Implements the ternary conditional operator (?:)
/// </summary>
public class Conditional : Expression {
Expression expr, true_expr, false_expr;
-
- public Conditional (Expression expr, Expression true_expr, Expression false_expr)
+
+ public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
{
this.expr = expr;
this.true_expr = true_expr;
public override Expression DoResolve (ResolveContext ec)
{
- expr = Expression.ResolveBoolean (ec, expr, loc);
-
- Assign ass = expr as Assign;
- if (ass != null && ass.Source is Constant) {
- ec.Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
- }
-
+ expr = expr.Resolve (ec);
true_expr = true_expr.Resolve (ec);
false_expr = false_expr.Resolve (ec);
} else {
ec.Report.Error (173, loc,
"Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
- true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
+ TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
return null;
}
}
return GetHoistedVariable (ec.CurrentAnonymousMethod);
}
+ public override string GetSignatureForError ()
+ {
+ return Name;
+ }
+
public override void Emit (EmitContext ec)
{
Emit (ec, false);
}
}
}
-
- if (type.IsPointer){
- if (!ec.IsUnsafe){
- UnsafeError (ec, loc);
- return null;
- }
- }
-
+
//
// Only base will allow this invocation to happen.
//
return false;
method = TypeManager.DropGenericMethodArguments (method);
- if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
+ if (TypeManager.IsBeingCompiled (method)) {
IMethodData md = TypeManager.GetMethod (method);
if (md != null)
return md.IsExcluded ();
} else {
call_op = OpCodes.Callvirt;
-#if GMCS_SOURCE
if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
ig.Emit (OpCodes.Constrained, instance_expr.Type);
-#endif
}
if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
target.expr = expr.Clone (clonectx);
}
- public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
- {
- mg.MutateHoistedGenericType (storey);
- type = storey.MutateType (type);
- if (arguments != null) {
- arguments.MutateHoistedGenericType (storey);
- }
- }
- }
-/*
- //
- // It's either a cast or delegate invocation
- //
- public class InvocationOrCast : ExpressionStatement
- {
- Expression expr;
- Expression argument;
-
- public InvocationOrCast (Expression expr, Expression argument)
- {
- this.expr = expr;
- this.argument = argument;
- this.loc = expr.Location;
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
- public override Expression DoResolve (ResolveContext ec)
+#if NET_4_0
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- Expression e = ResolveCore (ec);
- if (e == null)
- return null;
-
- return e.Resolve (ec);
+ return MakeExpression (ctx, mg.InstanceExpression, (MethodInfo) mg, arguments);
}
- Expression ResolveCore (EmitContext ec)
+ public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodInfo mi, Arguments args)
{
- //
- // First try to resolve it as a cast.
- //
- TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
- if (te != null) {
- return new Cast (te, argument, loc);
- }
+ var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
+ SLE.Expression expr = SLE.Expression.Call (instance_expr, mi,
+ Arguments.MakeExpression (args, ctx));
- //
- // This can either be a type or a delegate invocation.
- // Let's just resolve it and see what we'll get.
- //
- expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
- if (expr == null)
- return null;
-
- //
- // Ok, so it's a Cast.
- //
- if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
- return new Cast (expr, argument, loc);
- }
-
- if (expr.eclass == ExprClass.Namespace) {
- expr.Error_UnexpectedKind (null, "type", loc);
- return null;
- }
-
- //
- // It's a delegate invocation.
- //
- if (!TypeManager.IsDelegateType (expr.Type)) {
- Error (149, "Method name expected");
- return null;
+ if (mi.ReturnType == typeof (void)) {
+ expr = SLE.Expression.Block (
+ expr,
+ SLE.Expression.Default (typeof (object)));
}
- ArrayList args = new ArrayList (1);
- args.Add (new Argument (argument, Argument.AType.Expression));
- return new DelegateInvocation (expr, args, loc);
+ return expr;
}
+#endif
- public override ExpressionStatement ResolveStatement (EmitContext ec)
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- Expression e = ResolveCore (ec);
- if (e == null)
- return null;
-
- ExpressionStatement s = e as ExpressionStatement;
- if (s == null) {
- Error_InvalidExpressionStatement ();
- return null;
+ mg.MutateHoistedGenericType (storey);
+ type = storey.MutateType (type);
+ if (arguments != null) {
+ arguments.MutateHoistedGenericType (storey);
}
-
- return s.ResolveStatement (ec);
- }
-
- public override void Emit (EmitContext ec)
- {
- throw new Exception ("Cannot happen");
- }
-
- public override void EmitStatement (EmitContext ec)
- {
- throw new Exception ("Cannot happen");
- }
-
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- InvocationOrCast target = (InvocationOrCast) t;
-
- target.expr = expr.Clone (clonectx);
- target.argument = argument.Clone (clonectx);
}
}
-*/
/// <summary>
/// Implements the new expression
bool DoEmitTypeParameter (EmitContext ec)
{
-#if GMCS_SOURCE
ILGenerator ig = ec.ig;
-// IMemoryLocation ml;
MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
new Type [] { type });
ig.Emit (OpCodes.Call, ci);
ig.MarkLabel (label_end);
return true;
-#else
- throw new InternalErrorException ();
-#endif
}
//
int num_arguments = 0;
protected int dimensions;
protected readonly string rank;
+ Expression first_emit;
+ LocalTemporary first_emit_temp;
- protected ArrayList array_data;
+ protected List<Expression> array_data;
IDictionary bounds;
if (array_data == null) {
args = new Arguments (arguments.Count + 1);
args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
- foreach (Expression a in arguments) {
- if (arguments.Count == 1) {
- Constant c = a as Constant;
- if (c.IsDefaultValue)
- return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
- }
+ foreach (Expression a in arguments)
args.Add (new Argument (a.CreateExpressionTree (ec)));
- }
return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
}
args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
if (array_data != null) {
for (int i = 0; i < array_data.Count; ++i) {
- Expression e = (Expression) array_data [i];
+ Expression e = array_data [i];
if (e == null)
e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
return;
}
}
-
}
- Expression first_emit;
- LocalTemporary first_emit_temp;
-
protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
{
element = element.Resolve (ec);
// We use this to store all the date values in the order in which we
// will need to store them in the byte blob later
//
- array_data = new ArrayList ();
+ array_data = new List<Expression> ();
bounds = new System.Collections.Specialized.HybridDictionary ();
if (arguments != null)
byte [] element;
int count = array_data.Count;
- if (TypeManager.IsEnumType (array_element_type))
- array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
-
- factor = GetTypeSize (array_element_type);
+ Type element_type = array_element_type;
+ if (TypeManager.IsEnumType (element_type))
+ element_type = TypeManager.GetEnumUnderlyingType (element_type);
+
+ factor = GetTypeSize (element_type);
if (factor == 0)
- throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
+ throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
data = new byte [(count * factor + 3) & ~3];
int idx = 0;
continue;
}
- if (array_element_type == TypeManager.int64_type){
+ if (element_type == TypeManager.int64_type){
if (!(v is Expression)){
long val = (long) v;
val = (val >> 8);
}
}
- } else if (array_element_type == TypeManager.uint64_type){
+ } else if (element_type == TypeManager.uint64_type){
if (!(v is Expression)){
ulong val = (ulong) v;
val = (val >> 8);
}
}
- } else if (array_element_type == TypeManager.float_type) {
+ } else if (element_type == TypeManager.float_type) {
if (!(v is Expression)){
element = BitConverter.GetBytes ((float) v);
if (!BitConverter.IsLittleEndian)
System.Array.Reverse (data, idx, 4);
}
- } else if (array_element_type == TypeManager.double_type) {
+ } else if (element_type == TypeManager.double_type) {
if (!(v is Expression)){
element = BitConverter.GetBytes ((double) v);
if (!BitConverter.IsLittleEndian)
System.Array.Reverse (data, idx, 8);
}
- } else if (array_element_type == TypeManager.char_type){
+ } else if (element_type == TypeManager.char_type){
if (!(v is Expression)){
int val = (int) ((char) v);
data [idx] = (byte) (val & 0xff);
data [idx+1] = (byte) (val >> 8);
}
- } else if (array_element_type == TypeManager.short_type){
+ } else if (element_type == TypeManager.short_type){
if (!(v is Expression)){
int val = (int) ((short) v);
data [idx] = (byte) (val & 0xff);
data [idx+1] = (byte) (val >> 8);
}
- } else if (array_element_type == TypeManager.ushort_type){
+ } else if (element_type == TypeManager.ushort_type){
if (!(v is Expression)){
int val = (int) ((ushort) v);
data [idx] = (byte) (val & 0xff);
data [idx+1] = (byte) (val >> 8);
}
- } else if (array_element_type == TypeManager.int32_type) {
+ } else if (element_type == TypeManager.int32_type) {
if (!(v is Expression)){
int val = (int) v;
data [idx+2] = (byte) ((val >> 16) & 0xff);
data [idx+3] = (byte) (val >> 24);
}
- } else if (array_element_type == TypeManager.uint32_type) {
+ } else if (element_type == TypeManager.uint32_type) {
if (!(v is Expression)){
uint val = (uint) v;
data [idx+2] = (byte) ((val >> 16) & 0xff);
data [idx+3] = (byte) (val >> 24);
}
- } else if (array_element_type == TypeManager.sbyte_type) {
+ } else if (element_type == TypeManager.sbyte_type) {
if (!(v is Expression)){
sbyte val = (sbyte) v;
data [idx] = (byte) val;
}
- } else if (array_element_type == TypeManager.byte_type) {
+ } else if (element_type == TypeManager.byte_type) {
if (!(v is Expression)){
byte val = (byte) v;
data [idx] = (byte) val;
}
- } else if (array_element_type == TypeManager.bool_type) {
+ } else if (element_type == TypeManager.bool_type) {
if (!(v is Expression)){
bool val = (bool) v;
data [idx] = (byte) (val ? 1 : 0);
}
- } else if (array_element_type == TypeManager.decimal_type){
+ } else if (element_type == TypeManager.decimal_type){
if (!(v is Expression)){
int [] bits = Decimal.GetBits ((decimal) v);
int p = idx;
data [p++] = (byte) (nbits [j] >> 24);
}
}
- } else
- throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
+ } else {
+ throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
+ }
- idx += factor;
+ idx += factor;
}
return data;
}
+#if NET_4_0
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
+ {
+ var initializers = new SLE.Expression [array_data.Count];
+ for (var i = 0; i < initializers.Length; i++) {
+ if (array_data [i] == null)
+ initializers [i] = SLE.Expression.Default (array_element_type);
+ else
+ initializers [i] = array_data [i].MakeExpression (ctx);
+ }
+
+ return SLE.Expression.NewArrayInit (array_element_type, initializers);
+ }
+#endif
+
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
array_element_type = storey.MutateType (array_element_type);
e.Emit (ec);
if (arguments.Count == 1)
- ig.Emit (OpCodes.Newarr, array_element_type);
+ ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
else {
ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
}
// the static initializer will initialize at least 25% of array values.
// NOTE: const_initializers_count does not contain default constant values.
if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
- TypeManager.IsPrimitiveType (array_element_type)) {
+ (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
EmitStaticInitializers (ec);
if (!only_constant_initializers)
}
if (array_data == null) {
- Constant c = (Constant) arguments [0];
- if (c.IsDefaultValue) {
+ Expression arg = (Expression) arguments[0];
+ object arg_value;
+ if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
value = Array.CreateInstance (array_element_type, 0);
return true;
}
+
// ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
return base.GetAttributableValue (ec, null, out value);
}
public override void Emit (EmitContext ec)
{
- int size = GetTypeSize (type_queried);
-
- if (size == 0)
- ec.ig.Emit (OpCodes.Sizeof, type_queried);
- else
- IntConstant.EmitInt (ec.ig, size);
+ ec.ig.Emit (OpCodes.Sizeof, type_queried);
}
protected override void CloneTo (CloneContext clonectx, Expression t)
if (expr_type == null)
return;
- Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
+ expr_type.Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, loc);
return;
}
/// <summary>
/// Implements array access
/// </summary>
- public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
+ public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
//
// Points to our "data" repository
//
} else if (TypeManager.IsStruct (type)){
ig.Emit (OpCodes.Ldelema, type);
ig.Emit (OpCodes.Ldobj, type);
-#if GMCS_SOURCE
} else if (type.IsGenericParameter) {
ig.Emit (OpCodes.Ldelem, type);
-#endif
} else if (type.IsPointer)
ig.Emit (OpCodes.Ldelem_I);
else
has_type_arg = true;
is_stobj = true;
return OpCodes.Stobj;
-#if GMCS_SOURCE
} else if (t.IsGenericParameter) {
has_type_arg = true;
return OpCodes.Stelem;
-#endif
-
} else if (t.IsPointer)
return OpCodes.Stelem_I;
else
}
}
+#if NET_4_0
+ public SLE.Expression MakeAssignExpression (BuilderContext ctx)
+ {
+ return SLE.Expression.ArrayAccess (
+ ea.Expr.MakeExpression (ctx),
+ Arguments.MakeExpression (ea.Arguments, ctx));
+ }
+
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
+ {
+ return SLE.Expression.ArrayIndex (
+ ea.Expr.MakeExpression (ctx),
+ Arguments.MakeExpression (ea.Arguments, ctx));
+ }
+#endif
+
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
type = storey.MutateType (type);
/// <summary>
/// Expressions that represent an indexer call.
/// </summary>
- public class IndexerAccess : Expression, IAssignMethod
+ public class IndexerAccess : Expression, IDynamicAssign
{
class IndexerMethodGroupExpr : MethodGroupExpr
{
eclass = ExprClass.IndexerAccess;
return this;
}
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
public void Emit (EmitContext ec, bool leave_copy)
{
}
}
- public override void Emit (EmitContext ec)
+ public override string GetSignatureForError ()
{
- Emit (ec, false);
+ return TypeManager.CSharpSignature (get != null ? get : set, false);
}
- public override string GetSignatureForError ()
+#if NET_4_0
+ public SLE.Expression MakeAssignExpression (BuilderContext ctx)
{
- return TypeManager.CSharpSignature (get != null ? get : set, false);
+ var value = new[] { set_expr.MakeExpression (ctx) };
+ var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
+
+ return SLE.Expression.Block (
+ SLE.Expression.Call (instance_expr.MakeExpression (ctx), set, args),
+ value [0]);
+ }
+
+ public override SLE.Expression MakeExpression (BuilderContext ctx)
+ {
+ var args = Arguments.MakeExpression (arguments, ctx);
+ return SLE.Expression.Call (instance_expr.MakeExpression (ctx), get, args);
}
+#endif
public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
else
left = ec.GetThis (loc);
- MemberExpr me = (MemberExpr) member_lookup;
+ MemberExpr me = member_lookup as MemberExpr;
+ if (me == null){
+ if (member_lookup is TypeExpression){
+ ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
+ Identifier, member_lookup.GetSignatureForError ());
+ } else {
+ ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
+ Identifier, member_lookup.ExprClassName);
+ }
+
+ return null;
+ }
+
me = me.ResolveMemberAccess (ec, left, loc, null);
if (me == null)
return null;
public class ArrayIndexCast : TypeCast
{
public ArrayIndexCast (Expression expr)
- : base (expr, expr.Type)
+ : base (expr, TypeManager.int32_type)
{
+ if (expr.Type == TypeManager.int32_type)
+ throw new ArgumentException ("unnecessary array index conversion");
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
- Arguments args = new Arguments (2);
- args.Add (new Argument (child.CreateExpressionTree (ec)));
- args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
- return CreateExpressionFactoryCall (ec, "ConvertChecked", args);
+ using (ec.Set (ResolveContext.Options.CheckedScope)) {
+ return base.CreateExpressionTree (ec);
+ }
}
public override void Emit (EmitContext ec)
{
child.Emit (ec);
-
- if (type == TypeManager.int32_type)
- return;
- if (type == TypeManager.uint32_type)
+ var expr_type = child.Type;
+
+ if (expr_type == TypeManager.uint32_type)
ec.ig.Emit (OpCodes.Conv_U);
- else if (type == TypeManager.int64_type)
+ else if (expr_type == TypeManager.int64_type)
ec.ig.Emit (OpCodes.Conv_Ovf_I);
- else if (type == TypeManager.uint64_type)
+ else if (expr_type == TypeManager.uint64_type)
ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
else
throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
}
+
+ public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
+ {
+ return child.GetAttributableValue (ec, value_type, out value);
+ }
}
//
Constant c = count as Constant;
if (c != null && c.IsNegative) {
ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
- return null;
}
if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
AnonymousTypeClass CreateAnonymousType (ResolveContext ec, ArrayList parameters)
{
- AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
+ AnonymousTypeClass type = parent.Module.Compiled.GetAnonymousType (parameters);
if (type != null)
return type;
if (ec.Report.Errors == 0)
type.CloseType ();
- parent.Module.AddAnonymousType (type);
+ parent.Module.Compiled.AddAnonymousType (type);
return type;
}
}
}
- public class AnonymousTypeParameter : Expression
+ public class AnonymousTypeParameter : ShimExpression
{
public readonly string Name;
- Expression initializer;
public AnonymousTypeParameter (Expression initializer, string name, Location loc)
+ : base (initializer)
{
this.Name = name;
this.loc = loc;
- this.initializer = initializer;
}
public AnonymousTypeParameter (Parameter parameter)
+ : base (new SimpleName (parameter.Name, parameter.Location))
{
this.Name = parameter.Name;
this.loc = parameter.Location;
- this.initializer = new SimpleName (Name, loc);
}
- protected override void CloneTo (CloneContext clonectx, Expression target)
- {
- AnonymousTypeParameter t = (AnonymousTypeParameter) target;
- t.initializer = initializer.Clone (clonectx);
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
- }
-
public override bool Equals (object o)
{
AnonymousTypeParameter other = o as AnonymousTypeParameter;
public override Expression DoResolve (ResolveContext ec)
{
- Expression e = initializer.Resolve (ec);
+ Expression e = expr.Resolve (ec);
if (e == null)
return null;
ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
Name, initializer);
}
-
- public override void Emit (EmitContext ec)
- {
- throw new InternalErrorException ("Should not be reached");
- }
}
}