public class UserOperatorCall : Expression {
public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
- readonly ArrayList arguments;
- readonly MethodGroupExpr mg;
+ protected readonly ArrayList arguments;
+ protected readonly MethodGroupExpr mg;
readonly ExpressionTreeExpression expr_tree;
public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
public class Unary : Expression {
public enum Operator : byte {
UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
- Indirection, AddressOf, TOP
+ AddressOf, TOP
}
+ public static readonly string [] oper_names;
+ static Type [] [] predefined_operators;
+
public readonly Operator Oper;
public Expression Expr;
this.loc = loc;
}
- /// <summary>
- /// Returns a stringified representation of the Operator
- /// </summary>
- static public string OperName (Operator oper)
- {
- switch (oper){
- case Operator.UnaryPlus:
- return "+";
- case Operator.UnaryNegation:
- return "-";
- case Operator.LogicalNot:
- return "!";
- case Operator.OnesComplement:
- return "~";
- case Operator.AddressOf:
- return "&";
- case Operator.Indirection:
- return "*";
- }
-
- return oper.ToString ();
- }
-
- public static readonly string [] oper_names;
-
static Unary ()
{
oper_names = new string [(int)Operator.TOP];
oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
- oper_names [(int) Operator.Indirection] = "op_Indirection";
oper_names [(int) Operator.AddressOf] = "op_AddressOf";
}
- public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
- {
- Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
- }
-
- public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
- {
- Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
- oper, type);
- }
-
- void Error23 (Type t)
- {
- Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
- }
-
// <summary>
// This routine will attempt to simplify the unary expression when the
// argument is a constant.
return e;
}
return null;
-
- case Operator.AddressOf:
- return e;
-
- case Operator.Indirection:
- return e;
}
throw new Exception ("Can not constant fold: " + Oper.ToString());
}
- Expression ResolveOperator (EmitContext ec)
+ Expression ResolveOperator (EmitContext ec, Expression expr)
{
- //
- // Step 1: Default operations on CLI native types.
- //
+ if (predefined_operators == null)
+ CreatePredefinedOperatorsTable ();
- // Attempt to use a constant folding operation.
- Constant cexpr = Expr as Constant;
- if (cexpr != null) {
- cexpr = TryReduceConstant (ec, cexpr);
- if (cexpr != null) {
- return cexpr;
- }
- }
+ Type expr_type = expr.Type;
+ Expression best_expr;
//
- // Step 2: Perform Operator Overload location
+ // Primitive types first
//
- Type expr_type = Expr.Type;
- string op_name = oper_names [(int) Oper];
-
- MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
- if (user_op != null) {
- ArrayList args = new ArrayList (1);
- args.Add (new Argument (Expr));
- user_op = user_op.OverloadResolve (ec, ref args, false, loc);
-
- if (user_op == null) {
- Error23 (expr_type);
+ if (TypeManager.IsPrimitiveType (expr_type)) {
+ best_expr = ResolvePrimitivePredefinedType (expr);
+ if (best_expr == null)
return null;
- }
- return new UserOperatorCall (user_op, args, CreateExpressionTree, loc);
- }
-
- switch (Oper){
- case Operator.LogicalNot:
- if (expr_type != TypeManager.bool_type) {
- Expr = ResolveBoolean (ec, Expr, loc);
- if (Expr == null){
- Error23 (expr_type);
- return null;
- }
- }
-
- type = TypeManager.bool_type;
+ type = best_expr.Type;
+ Expr = best_expr;
return this;
+ }
- case Operator.OnesComplement:
- // Unary numeric promotions
- if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
- expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
- expr_type == TypeManager.char_type)
- {
- type = TypeManager.int32_type;
- return EmptyCast.Create (this, type);
- }
-
- // Predefined operators
- if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
- expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
- TypeManager.IsEnumType (expr_type))
- {
- type = expr_type;
- return this;
- }
-
- type = TypeManager.int32_type;
- Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
- if (Expr != null)
- return this;
-
- Error23 (expr_type);
- return null;
-
- case Operator.AddressOf:
- if (!ec.InUnsafe) {
- UnsafeError (loc);
- return null;
- }
-
- if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
- return null;
- }
-
- IVariable variable = Expr as IVariable;
- bool is_fixed = variable != null && variable.VerifyFixed ();
-
- if (!ec.InFixedInitializer && !is_fixed) {
- Error (212, "You can only take the address of unfixed expression inside " +
- "of a fixed statement initializer");
- return null;
- }
-
- if (ec.InFixedInitializer && is_fixed) {
- Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
- return null;
- }
-
- LocalVariableReference lr = Expr as LocalVariableReference;
- if (lr != null){
- if (lr.local_info.IsCaptured){
- AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
- return null;
- }
- lr.local_info.AddressTaken = true;
- lr.local_info.Used = true;
- }
-
- ParameterReference pr = Expr as ParameterReference;
- if ((pr != null) && pr.Parameter.IsCaptured) {
- AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
+ //
+ // E operator ~(E x);
+ //
+ if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type)) {
+ best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)));
+ if (best_expr == null)
return null;
- }
-
- // According to the specs, a variable is considered definitely assigned if you take
- // its address.
- if ((variable != null) && (variable.VariableInfo != null)){
- variable.VariableInfo.SetAssigned (ec);
- }
- type = TypeManager.GetPointerType (Expr.Type);
+ Expr = EmptyCast.Create (best_expr, expr_type);
+ type = Expr.Type;
return this;
-
- case Operator.Indirection:
- if (!ec.InUnsafe){
- UnsafeError (loc);
- return null;
- }
-
- if (!expr_type.IsPointer){
- Error (193, "The * or -> operator must be applied to a pointer");
- return null;
- }
-
- //
- // We create an Indirection expression, because
- // it can implement the IMemoryLocation.
- //
- return new Indirection (Expr, loc);
-
- case Operator.UnaryPlus:
- // Unary numeric promotions
- if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
- expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
- expr_type == TypeManager.char_type)
- {
- return EmptyCast.Create (Expr, TypeManager.int32_type);
- }
-
- // Predefined operators
- if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
- expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
- expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
- expr_type == TypeManager.decimal_type)
- {
- return Expr;
- }
-
- Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
- if (Expr != null) {
- // Because we can completely ignore unary +
- return Expr;
- }
-
- Error23 (expr_type);
- return null;
-
- case Operator.UnaryNegation:
- //
- // transform - - expr into expr
- //
- Unary u = Expr as Unary;
- if (u != null && u.Oper == Operator.UnaryNegation) {
- return u.Expr;
- }
-
- // Unary numeric promotions
- if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
- expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
- expr_type == TypeManager.char_type)
- {
- type = TypeManager.int32_type;
- return EmptyCast.Create (this, type);
- }
-
- //
- // Predefined operators
- //
- if (expr_type == TypeManager.uint32_type) {
- type = TypeManager.int64_type;
- Expr = Convert.ImplicitNumericConversion (Expr, type);
- return this;
- }
-
- if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
- expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
- expr_type == TypeManager.decimal_type)
- {
- type = expr_type;
- return this;
- }
-
- //
- // User conversion
-
- type = TypeManager.int32_type;
- Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
- if (Expr != null)
- return this;
-
- Error23 (expr_type);
- return null;
}
- Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
- TypeManager.CSharpName (expr_type) + "'");
- return null;
+ return ResolveUserType (ec, expr);
}
public override Expression CreateExpressionTree (EmitContext ec)
return CreateExpressionFactoryCall (method_name, args);
}
+ static void CreatePredefinedOperatorsTable ()
+ {
+ predefined_operators = new Type [(int) Operator.TOP] [];
+
+ //
+ // 7.6.1 Unary plus operator
+ //
+ predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
+ TypeManager.int32_type, TypeManager.uint32_type,
+ TypeManager.int64_type, TypeManager.uint64_type,
+ TypeManager.float_type, TypeManager.double_type,
+ TypeManager.decimal_type
+ };
+
+ //
+ // 7.6.2 Unary minus operator
+ //
+ predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
+ TypeManager.int32_type,
+ TypeManager.int64_type,
+ TypeManager.float_type, TypeManager.double_type,
+ TypeManager.decimal_type
+ };
+
+ //
+ // 7.6.3 Logical negation operator
+ //
+ predefined_operators [(int) Operator.LogicalNot] = new Type [] {
+ TypeManager.bool_type
+ };
+
+ //
+ // 7.6.4 Bitwise complement operator
+ //
+ predefined_operators [(int) Operator.OnesComplement] = new Type [] {
+ TypeManager.int32_type, TypeManager.uint32_type,
+ TypeManager.int64_type, TypeManager.uint64_type
+ };
+ }
+
+ //
+ // Unary numeric promotions
+ //
+ static Expression DoNumericPromotion (Operator op, Expression expr)
+ {
+ Type expr_type = expr.Type;
+ if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
+ expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
+ expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
+ expr_type == TypeManager.char_type)
+ return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
+
+ if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
+ return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
+
+ return expr;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
+ eclass = ExprClass.Value;
+
if (Oper == Operator.AddressOf) {
Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
Error (211, "Cannot take the address of the given expression");
return null;
}
+
+ return ResolveAddressOf (ec);
}
- else
- Expr = Expr.Resolve (ec);
+ Expr = Expr.Resolve (ec);
if (Expr == null)
return null;
return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
#endif
- eclass = ExprClass.Value;
- return ResolveOperator (ec);
+ //
+ // Attempt to use a constant folding operation.
+ //
+ Constant cexpr = Expr as Constant;
+ if (cexpr != null) {
+ cexpr = TryReduceConstant (ec, cexpr);
+ if (cexpr != null)
+ return cexpr;
+ }
+
+ Expression expr = ResolveOperator (ec, Expr);
+ if (expr == null)
+ Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
+
+ //
+ // Reduce unary operator on predefined types
+ //
+ if (expr == this && Oper == Operator.UnaryPlus)
+ return Expr;
+
+ return expr;
}
public override Expression DoResolveLValue (EmitContext ec, Expression right)
{
- if (Oper == Operator.Indirection)
- return DoResolve (ec);
-
return null;
}
}
}
- public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
- {
- if (Oper == Operator.LogicalNot)
- Expr.EmitBranchable (ec, target, !on_true);
- else
- base.EmitBranchable (ec, target, on_true);
- }
+ public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
+ {
+ if (Oper == Operator.LogicalNot)
+ Expr.EmitBranchable (ec, target, !on_true);
+ else
+ base.EmitBranchable (ec, target, on_true);
+ }
+
+ public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
+ {
+ Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
+ oper, TypeManager.CSharpName (t));
+ }
+
+ //
+ // Returns a stringified representation of the Operator
+ //
+ public static string OperName (Operator oper)
+ {
+ switch (oper) {
+ case Operator.UnaryPlus:
+ return "+";
+ case Operator.UnaryNegation:
+ return "-";
+ case Operator.LogicalNot:
+ return "!";
+ case Operator.OnesComplement:
+ return "~";
+ case Operator.AddressOf:
+ return "&";
+ }
+
+ throw new NotImplementedException (oper.ToString ());
+ }
+
+ Expression ResolveAddressOf (EmitContext ec)
+ {
+ if (!ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
+ }
+
+ if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
+ return null;
+ }
+
+ IVariable variable = Expr as IVariable;
+ bool is_fixed = variable != null && variable.VerifyFixed ();
+
+ if (!ec.InFixedInitializer && !is_fixed) {
+ Error (212, "You can only take the address of unfixed expression inside " +
+ "of a fixed statement initializer");
+ return null;
+ }
+
+ if (ec.InFixedInitializer && is_fixed) {
+ Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
+ return null;
+ }
+
+ LocalVariableReference lr = Expr as LocalVariableReference;
+ if (lr != null) {
+ if (lr.local_info.IsCaptured) {
+ AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
+ return null;
+ }
+ lr.local_info.AddressTaken = true;
+ lr.local_info.Used = true;
+ }
+
+ ParameterReference pr = Expr as ParameterReference;
+ if ((pr != null) && pr.Parameter.IsCaptured) {
+ AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
+ return null;
+ }
+
+ // According to the specs, a variable is considered definitely assigned if you take
+ // its address.
+ if ((variable != null) && (variable.VariableInfo != null)) {
+ variable.VariableInfo.SetAssigned (ec);
+ }
+
+ type = TypeManager.GetPointerType (Expr.Type);
+ return this;
+ }
+
+ Expression ResolvePrimitivePredefinedType (Expression expr)
+ {
+ expr = DoNumericPromotion (Oper, expr);
+ Type expr_type = expr.Type;
+ Type[] predefined = predefined_operators [(int) Oper];
+ foreach (Type t in predefined) {
+ if (t == expr_type)
+ return expr;
+ }
+ return null;
+ }
+
+ //
+ // Unary user type overload resolution
+ //
+ Expression ResolveUserType (EmitContext ec, Expression expr)
+ {
+ //
+ // Perform user-operator overload resolution
+ //
+ string op_name = oper_names [(int) Oper];
+ MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
+ if (user_op != null) {
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (expr));
+ user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
+
+ if (user_op != null) {
+ Expr = ((Argument) args [0]).Expr;
+ return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+ }
+ }
+
+ Type[] predefined = predefined_operators [(int) Oper];
+ Expression best_expr = null;
+ foreach (Type t in predefined) {
+ Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
+ if (oper_expr == null)
+ continue;
+
+ //
+ // decimal type is predefined but has user-operators
+ //
+ if (oper_expr.Type == TypeManager.decimal_type)
+ oper_expr = ResolveUserType (ec, oper_expr);
+ else
+ oper_expr = ResolvePrimitivePredefinedType (oper_expr);
+
+ if (oper_expr == null)
+ continue;
- public override string ToString ()
- {
- return "Unary (" + Oper + ", " + Expr + ")";
+ if (best_expr == null) {
+ best_expr = oper_expr;
+ continue;
+ }
+
+ int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
+ if (result == 0) {
+ Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
+ OperName (Oper), TypeManager.CSharpName (expr.Type));
+ break;
+ }
+
+ if (result == 2)
+ best_expr = oper_expr;
+ }
+
+ if (best_expr == null)
+ return null;
+
+ //
+ // HACK: Decimal user-operator is included in standard operators
+ //
+ if (best_expr.Type == TypeManager.decimal_type)
+ return best_expr;
+
+ Expr = best_expr;
+ type = best_expr.Type;
+ return this;
}
protected override void CloneTo (CloneContext clonectx, Expression t)
public Indirection (Expression expr, Location l)
{
this.expr = expr;
- type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
- eclass = ExprClass.Variable;
loc = l;
}
public override Expression DoResolve (EmitContext ec)
{
- //
- // Born fully resolved
- //
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ if (!ec.InUnsafe)
+ UnsafeError (loc);
+
+ if (!expr.Type.IsPointer) {
+ Error (193, "The * or -> operator must be applied to a pointer");
+ return null;
+ }
+
+ type = TypeManager.GetElementType (expr.Type);
+ eclass = ExprClass.Variable;
return this;
}
return this;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ return new Assign (this, this).CreateExpressionTree (ec);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
expr = expr.Resolve (ec);
return left == type;
}
- public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr, bool lnull, bool rnull)
+ public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
{
- if (lnull)
- return Convert.ImplicitConversionExists (ec, rexpr, right);
- if (rnull)
- return Convert.ImplicitConversionExists (ec, lexpr, left);
-
if (TypeManager.IsEqual (left, lexpr.Type) &&
TypeManager.IsEqual (right, rexpr.Type))
return true;
{
}
- public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr, bool lnull, bool rnull)
+ public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
{
if (left == null) {
if (!lexpr.Type.IsPointer)
l = TypeManager.CSharpName (left.Type);
if (right.eclass == ExprClass.MethodGroup)
- r = left.ExprClassName;
+ r = right.ExprClassName;
else
r = TypeManager.CSharpName (right.Type);
t == TypeManager.ushort_type || t == TypeManager.byte_type);
}
+ static bool IsFloat (Type t)
+ {
+ return t == TypeManager.float_type || t == TypeManager.double_type;
+ }
+
Expression ResolveOperator (EmitContext ec)
{
Type l = left.Type;
}
if ((TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
- (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)) &&
- !(this is Nullable.LiftedBinaryOperator))
+ (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
return DoResolveCore (ec, left, right);
Type l = left.Type;
Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
- bool left_is_null = left is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
- bool right_is_null = right is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
-
foreach (PredefinedOperator po in operators) {
if ((po.OperatorsMask & oper_mask) == 0)
continue;
if (!po.IsPrimitiveApplicable (l))
continue;
} else {
- if (!po.IsApplicable (ec, left, right, left_is_null, right_is_null))
+ if (!po.IsApplicable (ec, left, right))
continue;
}
if (union == null)
return null;
+ Expression oper_expr;
+
+ // TODO: CreateExpressionTree is allocated every time
if (user_oper != oper) {
- // FIXME: This has to derive from UserOperatorCall to handle expression tree
- return new ConditionalLogicalOperator (oper == Operator.LogicalAnd,
- left, right, left.Type, loc).Resolve (ec);
- }
+ oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+ oper == Operator.LogicalAnd, loc).Resolve (ec);
+ } else {
+ oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
- //
- // This is used to check if a test 'x == null' can be optimized to a reference equals,
- // and not invoke user operator
- //
- if ((oper & Operator.EqualityMask) != 0) {
- if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
- (right is NullLiteral && IsBuildInEqualityOperator (l))) {
- type = TypeManager.bool_type;
- // FIXME: this breaks expression tree
- if (left is NullLiteral || right is NullLiteral)
- return this;
- } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
- //
- // Two System.Delegate(s) are never equal
- //
- return null;
+ //
+ // This is used to check if a test 'x == null' can be optimized to a reference equals,
+ // and not invoke user operator
+ //
+ if ((oper & Operator.EqualityMask) != 0) {
+ if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
+ (right is NullLiteral && IsBuildInEqualityOperator (l))) {
+ type = TypeManager.bool_type;
+ if (left is NullLiteral || right is NullLiteral)
+ oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
+ } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
+ //
+ // Two System.Delegate(s) are never equal
+ //
+ return null;
+ }
}
}
left = larg.Expr;
right = rarg.Expr;
- // TODO: CreateExpressionTree is allocated every time
- return new UserOperatorCall (union, args, CreateExpressionTree, loc);
+ return oper_expr;
}
public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
Type l = left.Type;
OpCode opcode;
- bool is_unsigned = IsUnsigned (l);
switch (oper){
case Operator.Multiply:
if (ec.CheckState){
if (l == TypeManager.int32_type || l == TypeManager.int64_type)
opcode = OpCodes.Mul_Ovf;
- else if (is_unsigned)
+ else if (!IsFloat (l))
opcode = OpCodes.Mul_Ovf_Un;
else
opcode = OpCodes.Mul;
break;
case Operator.Division:
- if (is_unsigned)
+ if (IsUnsigned (l))
opcode = OpCodes.Div_Un;
else
opcode = OpCodes.Div;
break;
case Operator.Modulus:
- if (is_unsigned)
+ if (IsUnsigned (l))
opcode = OpCodes.Rem_Un;
else
opcode = OpCodes.Rem;
if (ec.CheckState){
if (l == TypeManager.int32_type || l == TypeManager.int64_type)
opcode = OpCodes.Add_Ovf;
- else if (is_unsigned)
+ else if (!IsFloat (l))
opcode = OpCodes.Add_Ovf_Un;
else
opcode = OpCodes.Add;
if (ec.CheckState){
if (l == TypeManager.int32_type || l == TypeManager.int64_type)
opcode = OpCodes.Sub_Ovf;
- else if (is_unsigned)
+ else if (!IsFloat (l))
opcode = OpCodes.Sub_Ovf_Un;
else
opcode = OpCodes.Sub;
break;
case Operator.RightShift:
- if (is_unsigned)
+ if (IsUnsigned (l))
opcode = OpCodes.Shr_Un;
else
opcode = OpCodes.Shr;
break;
case Operator.LessThan:
- if (is_unsigned)
+ if (IsUnsigned (l))
opcode = OpCodes.Clt_Un;
else
opcode = OpCodes.Clt;
break;
case Operator.GreaterThan:
- if (is_unsigned)
+ if (IsUnsigned (l))
opcode = OpCodes.Cgt_Un;
else
opcode = OpCodes.Cgt;
break;
case Operator.LessThanOrEqual:
- Type lt = left.Type;
-
- if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
+ if (IsUnsigned (l) || IsFloat (l))
ig.Emit (OpCodes.Cgt_Un);
else
ig.Emit (OpCodes.Cgt);
break;
case Operator.GreaterThanOrEqual:
- Type le = left.Type;
-
- if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
+ if (IsUnsigned (l) || IsFloat (l))
ig.Emit (OpCodes.Clt_Un);
else
ig.Emit (OpCodes.Clt);
switch (oper) {
case Operator.Addition:
- if (method == null && ec.CheckState)
+ if (method == null && ec.CheckState && !IsFloat (left.Type))
method_name = "AddChecked";
else
method_name = "Add";
case Operator.BitwiseAnd:
method_name = "And";
break;
+ case Operator.BitwiseOr:
+ method_name = "Or";
+ break;
case Operator.Division:
method_name = "Divide";
break;
case Operator.GreaterThanOrEqual:
method_name = "GreaterThanOrEqual";
lift_arg = true;
- break;
+ break;
+ case Operator.Inequality:
+ method_name = "NotEqual";
+ lift_arg = true;
+ break;
+ case Operator.LeftShift:
+ method_name = "LeftShift";
+ break;
case Operator.LessThan:
method_name = "LessThan";
+ lift_arg = true;
+ break;
+ case Operator.LessThanOrEqual:
+ method_name = "LessThanOrEqual";
+ lift_arg = true;
break;
case Operator.LogicalAnd:
method_name = "AndAlso";
break;
- case Operator.Inequality:
- method_name = "NotEqual";
- lift_arg = true;
+ case Operator.LogicalOr:
+ method_name = "OrElse";
+ break;
+ case Operator.Modulus:
+ method_name = "Modulo";
+ break;
+ case Operator.Multiply:
+ if (method == null && ec.CheckState && !IsFloat (left.Type))
+ method_name = "MultiplyChecked";
+ else
+ method_name = "Multiply";
break;
case Operator.RightShift:
method_name = "RightShift";
break;
-
- case Operator.BitwiseOr:
- method_name = "Or";
+ case Operator.Subtraction:
+ if (method == null && ec.CheckState && !IsFloat (left.Type))
+ method_name = "SubtractChecked";
+ else
+ method_name = "Subtract";
break;
- case Operator.LogicalOr:
- method_name = "OrElse";
- break;
default:
throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
}
//
// User-defined conditional logical operator
//
- public class ConditionalLogicalOperator : Expression {
- Expression left, right;
- bool is_and;
- Expression op_true, op_false;
- UserOperatorCall op;
- LocalTemporary left_temp;
+ public class ConditionalLogicalOperator : UserOperatorCall {
+ readonly bool is_and;
+ Expression oper;
- public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
+ public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
+ ExpressionTreeExpression expr_tree, bool is_and, Location loc)
+ : base (oper_method, arguments, expr_tree, loc)
{
- type = t;
- eclass = ExprClass.Value;
- this.loc = loc;
- this.left = left;
- this.right = right;
this.is_and = is_and;
}
- public override Expression CreateExpressionTree (EmitContext ec)
- {
- ArrayList args = new ArrayList (3);
- args.Add (new Argument (left.CreateExpressionTree (ec)));
- args.Add (new Argument (right.CreateExpressionTree (ec)));
- args.Add (new Argument (op.Method.CreateExpressionTree (ec)));
- return CreateExpressionFactoryCall (is_and ? "AndAlso" : "OrElse", args);
- }
-
- protected void Error19 ()
- {
- Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
- }
-
- protected void Error218 ()
- {
- Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
- "declarations of operator true and operator false");
- }
-
public override Expression DoResolve (EmitContext ec)
{
- MethodGroupExpr operator_group;
-
- operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
- if (operator_group == null) {
- Error19 ();
- return null;
- }
-
- left_temp = new LocalTemporary (type);
-
- ArrayList arguments = new ArrayList (2);
- arguments.Add (new Argument (left_temp, Argument.AType.Expression));
- arguments.Add (new Argument (right, Argument.AType.Expression));
- operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
- if (operator_group == null) {
- Error19 ();
- return null;
- }
-
- MethodInfo method = (MethodInfo)operator_group;
- if (method.ReturnType != type) {
- Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
- "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
+ MethodInfo method = (MethodInfo)mg;
+ type = TypeManager.TypeToCoreType (method.ReturnType);
+ ParameterData pd = TypeManager.GetParameterData (method);
+ if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
+ Report.Error (217, loc,
+ "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
+ TypeManager.CSharpSignature (method));
return null;
}
- op = new UserOperatorCall (operator_group, arguments, null, loc);
-
- op_true = GetOperatorTrue (ec, left_temp, loc);
- op_false = GetOperatorFalse (ec, left_temp, loc);
- if ((op_true == null) || (op_false == null)) {
- Error218 ();
+ Expression left_dup = new EmptyExpression (type);
+ Expression op_true = GetOperatorTrue (ec, left_dup, loc);
+ Expression op_false = GetOperatorFalse (ec, left_dup, loc);
+ if (op_true == null || op_false == null) {
+ Report.Error (218, loc,
+ "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
+ TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
return null;
}
+ oper = is_and ? op_false : op_true;
+ eclass = ExprClass.Value;
return this;
}
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Label false_target = ig.DefineLabel ();
Label end_target = ig.DefineLabel ();
- left.Emit (ec);
- left_temp.Store (ec);
+ //
+ // Emit and duplicate left argument
+ //
+ ((Argument)arguments [0]).Expr.Emit (ec);
+ ig.Emit (OpCodes.Dup);
+ arguments.RemoveAt (0);
- (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
- left_temp.Emit (ec);
- ig.Emit (OpCodes.Br, end_target);
- ig.MarkLabel (false_target);
- op.Emit (ec);
+ oper.EmitBranchable (ec, end_target, true);
+ base.Emit (ec);
ig.MarkLabel (end_target);
-
- // We release 'left_temp' here since 'op' may refer to it too
- left_temp.Release (ec);
}
}
}
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList arg = new ArrayList (1);
+ arg.Add (new Argument (this));
+ return CreateExpressionFactoryCall ("Constant", arg);
+ }
+
protected Expression DoResolveBase (EmitContext ec)
{
type = local_info.VariableType;
/// </summary>
public class Invocation : ExpressionStatement {
protected ArrayList Arguments;
- Expression expr;
+ protected Expression expr;
protected MethodGroupExpr mg;
bool arguments_resolved;
this.expr = expr;
Arguments = arguments;
- loc = expr.Location;
+ if (expr != null)
+ loc = expr.Location;
}
public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
return null;
}
- mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name);
+ mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
if (mg == null) {
Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
expr_resolved.GetSignatureForError ());
Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
return cast.Resolve (ec);
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = Arguments == null ?
+ new ArrayList (1) : new ArrayList (Arguments.Count + 1);
+
+ args.Add (new Argument (method.CreateExpressionTree (ec)));
+ if (Arguments != null) {
+ Expression expr;
+ foreach (Argument a in Arguments) {
+ expr = a.Expr.CreateExpressionTree (ec);
+ if (expr != null)
+ args.Add (new Argument (expr));
+ }
+ }
+
+ return CreateExpressionFactoryCall ("New", args);
+ }
public override Expression DoResolve (EmitContext ec)
{
internal class TypeOfMethod : Expression
{
- readonly MethodInfo method;
+ readonly MethodBase method;
- public TypeOfMethod (MethodInfo method, Location loc)
+ public TypeOfMethod (MethodBase method, Location loc)
{
this.method = method;
this.loc = loc;
public override Expression DoResolve (EmitContext ec)
{
- if (TypeManager.methodbase_get_type_from_handle == null) {
+ bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
+ MethodInfo mi = is_generic ?
+ TypeManager.methodbase_get_type_from_handle_generic :
+ TypeManager.methodbase_get_type_from_handle;
+
+ if (mi == null) {
Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
- if (t != null && handle_type != null)
- TypeManager.methodbase_get_type_from_handle = TypeManager.GetPredefinedMethod (t,
- "GetMethodFromHandle", loc, handle_type);
+ if (t == null || handle_type == null)
+ return null;
+
+ mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
+ is_generic ?
+ new Type[] { handle_type, TypeManager.runtime_handle_type } :
+ new Type[] { handle_type } );
+
+ if (is_generic)
+ TypeManager.methodbase_get_type_from_handle_generic = mi;
+ else
+ TypeManager.methodbase_get_type_from_handle = mi;
}
type = typeof (MethodBase);
public override void Emit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldtoken, method);
- ec.ig.Emit (OpCodes.Call, TypeManager.methodbase_get_type_from_handle);
+ if (method is MethodInfo)
+ ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
+ else
+ ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
+
+ bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
+ MethodInfo mi;
+ if (is_generic) {
+ mi = TypeManager.methodbase_get_type_from_handle_generic;
+ ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
+ } else {
+ mi = TypeManager.methodbase_get_type_from_handle;
+ }
+
+ ec.ig.Emit (OpCodes.Call, mi);
+ }
+ }
+
+ internal class TypeOfField : Expression
+ {
+ readonly FieldInfo field;
+
+ public TypeOfField (FieldInfo field, Location loc)
+ {
+ this.field = field;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (TypeManager.fieldinfo_get_field_from_handle == null) {
+ Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
+ Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
+
+ if (t != null && handle_type != null)
+ TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
+ "GetFieldFromHandle", loc, handle_type);
+ }
+
+ type = typeof (FieldInfo);
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, field);
+ ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
}
}
}
Type expr_type = expr_resolved.Type;
- if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
+ if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
+ expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
return null;
}
- if (expr_type == TypeManager.anonymous_method_type){
- Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
- return null;
- }
Constant c = expr_resolved as Constant;
if (c != null && c.GetValue () == null) {
if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
expr_eclass == ExprClass.EventAccess) {
- ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
+ ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier, loc);
if (ex_method_lookup != null) {
ex_method_lookup.ExtensionExpression = expr_resolved;
//
// An object initializer expression
//
- public class ElementInitializer : Expression
+ public class ElementInitializer : Assign
{
- Expression initializer;
public readonly string Name;
public ElementInitializer (string name, Expression initializer, Location loc)
+ : base (null, initializer, loc)
{
this.Name = name;
- this.initializer = initializer;
- this.loc = loc;
}
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public override Expression CreateExpressionTree (EmitContext ec)
{
- if (initializer == null)
- return;
+ ArrayList args = new ArrayList (2);
+ FieldExpr fe = target as FieldExpr;
+ if (fe != null)
+ args.Add (new Argument (fe.CreateTypeOfExpression ()));
+ else
+ args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
- ElementInitializer target = (ElementInitializer) t;
- target.initializer = initializer.Clone (clonectx);
+ args.Add (new Argument (source.CreateExpressionTree (ec)));
+ return CreateExpressionFactoryCall (
+ source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
+ args);
}
public override Expression DoResolve (EmitContext ec)
{
- if (initializer == null)
+ if (source == null)
return EmptyExpressionStatement.Instance;
- MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
+ MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
- if (element_member == null)
+ if (me == null)
return null;
- element_member.InstanceExpression = ec.CurrentInitializerVariable;
+ target = me;
+ me.InstanceExpression = ec.CurrentInitializerVariable;
- if (initializer is CollectionOrObjectInitializers) {
+ if (source is CollectionOrObjectInitializers) {
Expression previous = ec.CurrentInitializerVariable;
- ec.CurrentInitializerVariable = element_member;
- initializer = initializer.Resolve (ec);
+ ec.CurrentInitializerVariable = target;
+ source = source.Resolve (ec);
ec.CurrentInitializerVariable = previous;
- return initializer;
+ if (source == null)
+ return null;
+
+ eclass = source.eclass;
+ type = source.Type;
+ return this;
}
- Assign a = new Assign (element_member, initializer, loc);
- if (a.Resolve (ec) == null)
+ Expression expr = base.DoResolve (ec);
+ if (expr == null)
return null;
//
// Ignore field initializers with default value
//
- Constant c = a.Source as Constant;
- if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
+ Constant c = source as Constant;
+ if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
return EmptyExpressionStatement.Instance;
- return a;
+ return expr;
}
protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
return null;
}
-
- public override void Emit (EmitContext ec)
+
+ public override void EmitStatement (EmitContext ec)
{
- throw new NotSupportedException ("Should not be reached");
+ if (source is CollectionOrObjectInitializers)
+ source.Emit (ec);
+ else
+ base.EmitStatement (ec);
}
}
//
// A collection initializer expression
//
- public class CollectionElementInitializer : Expression
+ public class CollectionElementInitializer : Invocation
{
public class ElementInitializerArgument : Argument
{
}
}
- ArrayList arguments;
-
public CollectionElementInitializer (Expression argument)
+ : base (null, new ArrayList (1), true)
{
- arguments = new ArrayList (1);
- arguments.Add (argument);
+ Arguments.Add (argument);
this.loc = argument.Location;
}
public CollectionElementInitializer (ArrayList arguments, Location loc)
+ : base (null, arguments, true)
{
- this.arguments = arguments;
this.loc = loc;
}
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public override Expression CreateExpressionTree (EmitContext ec)
{
- CollectionElementInitializer target = (CollectionElementInitializer) t;
- ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
- foreach (Expression e in arguments)
- t_arguments.Add (e.Clone (clonectx));
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (mg.CreateExpressionTree (ec)));
+
+ ArrayList expr_initializers = new ArrayList (Arguments.Count);
+ foreach (Argument a in Arguments)
+ expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
+
+ args.Add (new Argument (new ArrayCreation (
+ CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
+ return CreateExpressionFactoryCall ("ElementInit", args);
}
public override Expression DoResolve (EmitContext ec)
{
- // TODO: We should call a constructor which takes element counts argument,
- // for know types like List<T>, Dictionary<T, U>
+ if (eclass != ExprClass.Invalid)
+ return this;
+
+ // TODO: We could call a constructor which takes element count argument,
+ // for known types like List<T>, Dictionary<T, U>
- for (int i = 0; i < arguments.Count; ++i)
- arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
+ for (int i = 0; i < Arguments.Count; ++i) {
+ Expression expr = ((Expression) Arguments [i]).Resolve (ec);
+ if (expr == null)
+ return null;
- Expression add_method = new Invocation (
- new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
- arguments);
+ Arguments [i] = new ElementInitializerArgument (expr);
+ }
- add_method = add_method.Resolve (ec);
+ base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
- return add_method;
- }
-
- public override void Emit (EmitContext ec)
- {
- throw new NotSupportedException ("Should not be reached");
+ return base.DoResolve (ec);
}
}
}
}
+ public bool IsCollectionInitializer {
+ get {
+ return type == typeof (CollectionOrObjectInitializers);
+ }
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression target)
{
CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
foreach (Expression e in initializers)
t.initializers.Add (e.Clone (clonectx));
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList expr_initializers = new ArrayList (initializers.Count);
+ foreach (Expression e in initializers) {
+ Expression expr = e.CreateExpressionTree (ec);
+ if (expr != null)
+ expr_initializers.Add (expr);
+ }
+
+ return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
+ }
public override Expression DoResolve (EmitContext ec)
{
+ if (eclass != ExprClass.Invalid)
+ return this;
+
bool is_elements_initialization = false;
ArrayList element_names = null;
for (int i = 0; i < initializers.Count; ++i) {
initializers [i] = e;
}
- type = typeof (CollectionOrObjectInitializers);
+ type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
eclass = ExprClass.Variable;
return this;
}
this.new_instance = newInstance;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ // Should not be reached
+ throw new NotSupportedException ();
+ }
+
public override Expression DoResolve (EmitContext ec)
{
return this;
target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (base.CreateExpressionTree (ec)));
+ args.Add (new Argument (initializers.CreateExpressionTree (ec)));
+
+ return CreateExpressionFactoryCall (
+ initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
+ args);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
if (eclass != ExprClass.Invalid)