// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2001, 2002, 2003 Ximian, Inc.
-// (C) 2003, 2004 Novell, Inc.
+// Copyright 2001, 2002, 2003 Ximian, Inc.
+// Copyright 2003-2008 Novell, Inc.
//
#define USE_OLD
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)
this.arguments = args;
this.expr_tree = expr_tree;
- type = ((MethodInfo)mg).ReturnType;
+ type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
eclass = ExprClass.Value;
this.loc = loc;
}
return expr_tree (ec, mg);
ArrayList args = new ArrayList (arguments.Count + 1);
- args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
+ args.Add (new Argument (new NullLiteral (loc)));
args.Add (new Argument (mg.CreateExpressionTree (ec)));
foreach (Argument a in arguments) {
args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
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;
+ Expression enum_conversion;
public Unary (Operator op, Expression expr, Location loc)
{
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.
// </summary>
Constant TryReduceConstant (EmitContext ec, Constant e)
{
+ if (e is SideEffectConstant) {
+ Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
+ return r == null ? null : new SideEffectConstant (r, e, r.Location);
+ }
+
Type expr_type = e.Type;
switch (Oper){
if (expr_type != TypeManager.bool_type)
return null;
- BoolConstant b = (BoolConstant) e;
- return new BoolConstant (!(b.Value), b.Location);
+ bool b = (bool)e.GetValue ();
+ return new BoolConstant (!b, e.Location);
case Operator.OnesComplement:
// Unary numeric promotions
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)
+ protected Expression ResolveOperator (EmitContext ec, Expression expr)
{
- //
- // Step 1: Default operations on CLI native types.
- //
+ eclass = ExprClass.Value;
- // Attempt to use a constant folding operation.
- Constant cexpr = Expr as Constant;
- if (cexpr != null) {
- cexpr = TryReduceConstant (ec, cexpr);
- if (cexpr != null) {
- return cexpr;
- }
- }
+ if (predefined_operators == null)
+ CreatePredefinedOperatorsTable ();
+
+ 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);
- 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;
- 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);
+ if (TypeManager.IsPrimitiveType (expr_type)) {
+ best_expr = ResolvePrimitivePredefinedType (expr);
+ 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);
+ type = best_expr.Type;
+ Expr = best_expr;
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
+ //
+ // E operator ~(E x);
+ //
+ if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
+ return ResolveEnumOperator (ec, expr);
- type = TypeManager.int32_type;
- Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
- if (Expr != null)
- return this;
+ return ResolveUserType (ec, expr);
+ }
- Error23 (expr_type);
+ protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
+ {
+ Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
+ Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
+ if (best_expr == null)
return null;
- }
- Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
- TypeManager.CSharpName (expr_type) + "'");
- return null;
+ Expr = best_expr;
+ enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
+ type = expr.Type;
+ return EmptyCast.Create (this, type);
}
public override Expression CreateExpressionTree (EmitContext ec)
Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
{
- string method_name;
+ string method_name;
switch (Oper) {
+ case Operator.AddressOf:
+ Error_PointerInsideExpressionTree ();
+ return null;
case Operator.UnaryNegation:
- method_name = "Negate";
+ if (ec.CheckState && user_op == null && !IsFloat (type))
+ method_name = "NegateChecked";
+ else
+ method_name = "Negate";
break;
+ case Operator.OnesComplement:
case Operator.LogicalNot:
method_name = "Not";
break;
+ case Operator.UnaryPlus:
+ method_name = "UnaryPlus";
+ break;
default:
throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
}
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)
{
if (Oper == Operator.AddressOf) {
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;
-#if GMCS_SOURCE
if (TypeManager.IsNullableValueType (Expr.Type))
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 Emit (EmitContext ec)
+ {
+ EmitOperator (ec, type);
+ }
+
+ protected void EmitOperator (EmitContext ec, Type type)
{
ILGenerator ig = ec.ig;
switch (Oper) {
case Operator.UnaryPlus:
- throw new Exception ("This should be caught by Resolve");
+ Expr.Emit (ec);
+ break;
case Operator.UnaryNegation:
- if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
+ if (ec.CheckState && !IsFloat (type)) {
ig.Emit (OpCodes.Ldc_I4_0);
if (type == TypeManager.int64_type)
ig.Emit (OpCodes.Conv_U8);
throw new Exception ("This should not happen: Operator = "
+ Oper.ToString ());
}
+
+ //
+ // Same trick as in Binary expression
+ //
+ if (enum_conversion != null)
+ enum_conversion.Emit (ec);
}
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
base.EmitBranchable (ec, target, on_true);
}
- public override string ToString ()
- {
- return "Unary (" + Oper + ", " + Expr + ")";
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ Expr.EmitSideEffect (ec);
+ }
+
+ 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));
+ }
+
+ static bool IsFloat (Type t)
+ {
+ return t == TypeManager.float_type || t == TypeManager.double_type;
+ }
+
+ //
+ // 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);
+ eclass = ExprClass.Value;
+ 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;
+ }
+
+ //
+ // Perform user-operator overload resolution
+ //
+ protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
+ {
+ 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)
+ return 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)
+ return null;
+
+ Expr = ((Argument) args [0]).Expr;
+ return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+ }
+
+ //
+ // Unary user type overload resolution
+ //
+ Expression ResolveUserType (EmitContext ec, Expression expr)
+ {
+ Expression best_expr = ResolveUserOperator (ec, expr);
+ if (best_expr != null)
+ return best_expr;
+
+ Type[] predefined = predefined_operators [(int) Oper];
+ 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;
+
+ 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 CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
public override void Emit (EmitContext ec)
{
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 SimpleAssign (this, this).CreateExpressionTree (ec);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
expr = expr.Resolve (ec);
: base (expr, probe_type, l)
{
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (expr.CreateExpressionTree (ec)));
+ args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
+ return CreateExpressionFactoryCall ("TypeIs", args);
+ }
public override void Emit (EmitContext ec)
{
ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
}
-
+
Expression CreateConstantResult (bool result)
{
if (result)
Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
TypeManager.CSharpName (probe_type_expr.Type));
- return new BoolConstant (result, loc);
+ return ReducedExpression.Create (new BoolConstant (result, loc), this);
}
public override Expression DoResolve (EmitContext ec)
/// Implementation of the `as' operator.
/// </summary>
public class As : Probe {
+ bool do_isinst;
+ Expression resolved_type;
+
public As (Expression expr, Expression probe_type, Location l)
: base (expr, probe_type, l)
{
}
- bool do_isinst = false;
- Expression resolved_type;
-
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (expr.CreateExpressionTree (ec)));
+ args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
+ return CreateExpressionFactoryCall ("TypeAs", args);
+ }
+
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
}
#endif
if (expr.IsNull && TypeManager.IsNullableType (type)) {
- Report.Warning (458, 2, loc, "The result of the expression is always `null' of type `{0}'",
- TypeManager.CSharpName (type));
+ return Nullable.LiftedNull.CreateFromExpression (this);
}
Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
this.loc = loc;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (this));
+ args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ return CreateExpressionFactoryCall ("Constant", args);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
if (constraints != null && constraints.IsReferenceType)
return new EmptyConstantCast (new NullLiteral (Location), type);
} else {
- Constant c = New.Constantify(type);
+ Constant c = New.Constantify (type);
if (c != null)
return new EmptyConstantCast (c, type);
/// </summary>
public class Binary : Expression {
- class PredefinedOperator {
+ protected class PredefinedOperator {
protected readonly Type left;
protected readonly Type right;
public readonly Operator OperatorsMask;
this.ReturnType = return_type;
}
+ public virtual Expression ConvertResult (EmitContext ec, Binary b)
+ {
+ b.type = ReturnType;
+
+ if (left != null)
+ b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+
+ if (right != null)
+ b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+
+ return b;
+ }
+
public bool IsPrimitiveApplicable (Type type)
{
//
return result == 1 ? best_operator : this;
}
-
- public virtual Expression ConvertResult (EmitContext ec, Binary b)
- {
- if (left != null)
- b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
-
- if (right != null)
- b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
-
- b.type = ReturnType;
- return b;
- }
}
class PredefinedStringOperator : PredefinedOperator {
public override Expression ConvertResult (EmitContext ec, Binary b)
{
- base.ConvertResult (ec, b);
+ //
+ // Use original expression for nullable arguments
+ //
+ Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
+ if (unwrap != null)
+ b.left = unwrap.Original;
+
+ unwrap = b.right as Nullable.Unwrap;
+ if (unwrap != null)
+ b.right = unwrap.Original;
+
+ b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+ b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
//
// Start a new concat expression using converted expression
public override Expression ConvertResult (EmitContext ec, Binary b)
{
- base.ConvertResult (ec, b);
+ b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+
+ Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
+
+ int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
+
+ //
+ // b = b.left >> b.right & (0x1f|0x3f)
+ //
+ b.right = new Binary (Operator.BitwiseAnd,
+ b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
- // FIXME: use conversion for expression tree
- int shiftmask = (left == TypeManager.int32_type || left == TypeManager.uint32_type) ? 31 : 63;
- b.right = new Binary (Operator.BitwiseAnd, b.right, new IntConstant (shiftmask, b.right.Location)).Resolve (ec);
+ //
+ // Expression tree representation does not use & mask
+ //
+ b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
+ b.type = ReturnType;
return b;
}
}
LeftShift = 5 | ShiftMask,
RightShift = 6 | ShiftMask,
- LessThan = 7 | ComparisonMask,
- GreaterThan = 8 | ComparisonMask,
- LessThanOrEqual = 9 | ComparisonMask,
- GreaterThanOrEqual = 10 | ComparisonMask,
+ LessThan = 7 | ComparisonMask | RelationalMask,
+ GreaterThan = 8 | ComparisonMask | RelationalMask,
+ LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
+ GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
Equality = 11 | ComparisonMask | EqualityMask,
Inequality = 12 | ComparisonMask | EqualityMask,
BitwiseMask = 1 << 9,
LogicalMask = 1 << 10,
AdditionMask = 1 << 11,
- SubtractionMask = 1 << 12
+ SubtractionMask = 1 << 12,
+ RelationalMask = 1 << 13
}
readonly Operator oper;
protected Expression left, right;
readonly bool is_compound;
+ Expression enum_conversion;
// This must be kept in sync with Operator!!!
public static readonly string [] oper_names;
name, left, right);
}
- protected void Error_OperatorCannotBeApplied ()
+ protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
{
string l, r;
// TODO: This should be handled as Type of method group in CSharpName
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 void Warning_Constant_Result (Location loc, bool result, Type type)
+ static bool IsFloat (Type t)
{
- Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
- "This operation is undocumented and it is temporary supported for compatibility reasons only",
- TypeManager.CSharpName (type), result ? "true" : "false");
+ return t == TypeManager.float_type || t == TypeManager.double_type;
}
Expression ResolveOperator (EmitContext ec)
{
Type l = left.Type;
Type r = right.Type;
-
- if (oper == Operator.Equality || oper == Operator.Inequality){
- if (right.Type == TypeManager.null_type){
- //
- // 7.9.9 Equality operators and null
- //
- // CSC 2 has this behavior, it allows structs to be compared
- // with the null literal *outside* of a generics context and
- // inlines that as true or false.
- //
- // This is, in my opinion, completely wrong.
- //
- if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType) {
- if (!TypeManager.IsPrimitiveType (l) && !TypeManager.IsEnumType (l)) {
- if (MemberLookup (ec.ContainerType, l, GetOperatorMetadataName (Operator.Equality), MemberTypes.Method, AllBindingFlags, loc) == null &&
- MemberLookup (ec.ContainerType, l, GetOperatorMetadataName (Operator.Inequality), MemberTypes.Method, AllBindingFlags, loc) == null) {
- return null;
- }
- }
-
- Warning_Constant_Result (loc, oper == Operator.Inequality, l);
- return new BoolConstant (oper == Operator.Inequality, loc);
- }
- }
-
- if (left is NullLiteral){
- //
- // 7.9.9 Equality operators and null
- //
- // CSC 2 has this behavior, it allows structs to be compared
- // with the null literal *outside* of a generics context and
- // inlines that as true or false.
- //
- // This is, in my opinion, completely wrong.
- //
- if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
- if (!TypeManager.IsPrimitiveType (r) && !TypeManager.IsEnumType (r)) {
- if (MemberLookup (ec.ContainerType, r, GetOperatorMetadataName (Operator.Equality), MemberTypes.Method, AllBindingFlags, loc) == null &&
- MemberLookup (ec.ContainerType, r, GetOperatorMetadataName (Operator.Inequality), MemberTypes.Method, AllBindingFlags, loc) == null) {
- return null;
- }
- }
-
- Warning_Constant_Result (loc, oper == Operator.Inequality, r);
- return new BoolConstant (oper == Operator.Inequality, loc);
- }
- }
- }
-
Expression expr;
bool primitives_only = false;
+ if (standard_operators == null)
+ CreateStandardOperatorsTable ();
+
//
- // Handle predefined non-primitive types
+ // Handles predefined primitive types
//
if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
if ((oper & Operator.ShiftMask) == 0) {
// Predefined reference types equality
if ((oper & Operator.EqualityMask) != 0) {
- if (!l.IsValueType && !r.IsValueType)
- return ResolveOperatorEqualityRerefence (ec, l, r);
+ expr = ResolveOperatorEqualityRerefence (ec, l, r);
+ if (expr != null)
+ return expr;
}
}
- if (standard_operators == null)
- CreateStandardOperatorsTable ();
-
- return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
+ return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
}
- Constant EnumLiftUp (Constant left, Constant right)
+ // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
+ // if 'left' is not an enumeration constant, create one from the type of 'right'
+ Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
{
switch (oper) {
case Operator.BitwiseOr:
case Operator.LessThanOrEqual:
case Operator.GreaterThan:
case Operator.GreaterThanOrEqual:
- if (left is EnumConstant)
+ if (TypeManager.IsEnumType (left.Type))
return left;
if (left.IsZeroInteger)
- return new EnumConstant (left, right.Type);
+ return left.TryReduce (ec, right.Type, loc);
break;
case Operator.Modulus:
case Operator.LeftShift:
case Operator.RightShift:
- if (right is EnumConstant || left is EnumConstant)
+ if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
break;
return left;
}
- Error_OperatorCannotBeApplied ();
+ Error_OperatorCannotBeApplied (this.left, this.right);
return null;
}
if (ltype != int32) {
Constant c = left as Constant;
if (c != null)
- temp = c.ImplicitConversionRequired (int32, loc);
+ temp = c.ConvertImplicitly (int32);
else
temp = Convert.ImplicitNumericConversion (left, int32);
if (rtype != int32) {
Constant c = right as Constant;
if (c != null)
- temp = c.ImplicitConversionRequired (int32, loc);
+ temp = c.ConvertImplicitly (int32);
else
temp = Convert.ImplicitNumericConversion (right, int32);
// The conversion rules are ignored in enum context but why
if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
- left = lc = EnumLiftUp (lc, rc);
+ left = lc = EnumLiftUp (ec, lc, rc, loc);
if (lc == null)
return null;
- right = rc = EnumLiftUp (rc, lc);
+ right = rc = EnumLiftUp (ec, rc, lc, loc);
if (rc == null)
return null;
}
((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
if ((ResolveOperator (ec)) == null) {
- Error_OperatorCannotBeApplied ();
+ Error_OperatorCannotBeApplied (left, right);
return null;
}
right = left;
lc = rc;
}
-
- // TODO: there must be better way how to check that the expression
- // does not have any mutator
- if (right is MemberExpr)
- return lc;
// The result is a constant with side-effect
return new SideEffectConstant (lc, right, loc);
}
}
-#if GMCS_SOURCE
- if ((left is NullLiteral || left.Type.IsValueType) &&
- (right is NullLiteral || right.Type.IsValueType) &&
- !(left is NullLiteral && right is NullLiteral) &&
- (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
- return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
-#endif
-
// Comparison warnings
- if (oper == Operator.Equality || oper == Operator.Inequality ||
- oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
- oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
+ if ((oper & Operator.ComparisonMask) != 0) {
if (left.Equals (right)) {
Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
}
CheckUselessComparison (rc, left.Type);
}
+ if (RootContext.Version >= LanguageVersion.ISO_2 &&
+ (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
+ (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);
+ }
+
+ protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
+ {
Expression expr = ResolveOperator (ec);
if (expr == null)
- Error_OperatorCannotBeApplied ();
+ Error_OperatorCannotBeApplied (left_orig, right_orig);
if (left == null || right == null)
throw new InternalErrorException ("Invalid conversion");
//
Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
{
- Expression temp;
+ //
+ // bool operator == (E x, E y);
+ // bool operator != (E x, E y);
+ // bool operator < (E x, E y);
+ // bool operator > (E x, E y);
+ // bool operator <= (E x, E y);
+ // bool operator >= (E x, E y);
+ //
+ // E operator & (E x, E y);
+ // E operator | (E x, E y);
+ // E operator ^ (E x, E y);
+ //
+ // U operator - (E e, E f)
+ // E operator - (E e, U x)
+ //
+ // E operator + (U x, E e)
+ // E operator + (E e, U x)
+ //
+ if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
+ (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
+ return null;
- if (lenum || renum) {
- //
- // bool operator == (E x, E y);
- // bool operator != (E x, E y);
- // bool operator < (E x, E y);
- // bool operator > (E x, E y);
- // bool operator <= (E x, E y);
- // bool operator >= (E x, E y);
- //
- if ((oper & Operator.ComparisonMask) != 0) {
- type = TypeManager.bool_type;
- } else if ((oper & Operator.BitwiseMask) != 0) {
- type = ltype;
- }
+ Expression ltemp = left;
+ Expression rtemp = right;
+ Type underlying_type;
- if (type != null) {
- if (!TypeManager.IsEqual (ltype, rtype)) {
- if (!lenum) {
- temp = Convert.ImplicitConversion (ec, left, rtype, loc);
- if (temp == null)
- return null;
- left = temp;
- } else {
- temp = Convert.ImplicitConversion (ec, right, ltype, loc);
- if (temp == null)
- return null;
- right = temp;
- }
- }
+ if (TypeManager.IsEqual (ltype, rtype)) {
+ underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
- return this;
- }
- }
+ if (left is Constant)
+ left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+ else
+ left = EmptyCast.Create (left, underlying_type);
- Type underlying_type;
- if (lenum && !renum) {
- //
- // E operator + (E e, U x)
- // E operator - (E e, U x)
- //
- if (oper == Operator.Addition || oper == Operator.Subtraction) {
- underlying_type = TypeManager.EnumToUnderlying (ltype);
- temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
- if (temp == null)
+ if (right is Constant)
+ right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+ else
+ right = EmptyCast.Create (right, underlying_type);
+ } else if (lenum) {
+ if (oper != Operator.Subtraction && oper != Operator.Addition) {
+ Constant c = right as Constant;
+ if (c == null || !c.IsDefaultValue)
return null;
+ }
- right = temp;
- type = ltype;
- return this;
+ underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
+ if (left is Constant)
+ left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+ else
+ left = EmptyCast.Create (left, underlying_type);
+ } else if (renum) {
+ if (oper != Operator.Addition) {
+ Constant c = left as Constant;
+ if (c == null || !c.IsDefaultValue)
+ return null;
}
+ underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
+ if (right is Constant)
+ right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+ else
+ right = EmptyCast.Create (right, underlying_type);
+ } else {
return null;
}
- if (renum) {
- //
- // E operator + (U x, E e)
- //
- if (oper == Operator.Addition) {
- underlying_type = TypeManager.EnumToUnderlying (rtype);
- temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
- if (temp == null)
- return null;
+ //
+ // C# specification uses explicit cast syntax which means binary promotion
+ // should happen, however it seems that csc does not do that
+ //
+ if (!DoBinaryOperatorPromotion (ec)) {
+ left = ltemp;
+ right = rtemp;
+ return null;
+ }
- left = temp;
- type = rtype;
- return this;
- }
+ Type res_type = null;
+ if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
+ Type promoted_type = lenum ? left.Type : right.Type;
+ enum_conversion = Convert.ExplicitNumericConversion (
+ new EmptyExpression (promoted_type), underlying_type);
+
+ if (oper == Operator.Subtraction && renum && lenum)
+ res_type = underlying_type;
+ else if (oper == Operator.Addition && renum)
+ res_type = rtype;
+ else
+ res_type = ltype;
}
+
+ Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
+ if (!is_compound || expr == null)
+ return expr;
//
- // U operator - (E e, E f)
+ // TODO: Need to corectly implemented Coumpound Assigment for all operators
+ // Section: 7.16.2
//
- if (oper == Operator.Subtraction) {
- if (!TypeManager.IsEqual (ltype, rtype))
- return null;
+ if (Convert.ImplicitConversionExists (ec, left, rtype))
+ return expr;
- type = TypeManager.EnumToUnderlying (ltype);
- return this;
- }
+ if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+ return null;
- return null;
+ expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+ return expr;
}
//
// 7.9.6 Reference type equality operators
//
- Expression ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
+ Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
{
//
// operator != (object a, object b)
if (l == TypeManager.anonymous_method_type)
return null;
+ if (TypeManager.IsValueType (l))
+ return null;
+
return this;
}
return null;
} else if (l.IsInterface) {
l = TypeManager.object_type;
+ } else if (l.IsValueType) {
+ return null;
}
if (rgen) {
return null;
} else if (r.IsInterface) {
r = TypeManager.object_type;
+ } else if (r.IsValueType) {
+ return null;
}
+
const string ref_comparison = "Possible unintended reference comparison. " +
"Consider casting the {0} side of the expression to `string' to compare the values";
if (pointer_operators == null)
CreatePointerOperatorsTable ();
- return ResolveOperatorPredefined (ec, pointer_operators, false);
+ return ResolveOperatorPredefined (ec, pointer_operators, false, null);
}
//
// Build-in operators method overloading
//
- Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
+ protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
{
PredefinedOperator best_operator = null;
Type l = left.Type;
if (best_operator == null)
return null;
- if (primitives_only) {
- type = best_operator.ReturnType;
- return this;
- }
+ Expression expr = best_operator.ConvertResult (ec, this);
+ if (enum_type == null)
+ return expr;
- return best_operator.ConvertResult (ec, this);
+ //
+ // HACK: required by enum_conversion
+ //
+ expr.Type = enum_type;
+ return EmptyCast.Create (expr, enum_type);
}
//
// Performs user-operator overloading
//
- Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
+ protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
{
Operator user_oper;
if (oper == Operator.LogicalAnd)
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)
}
if (((Constant) right).IsZeroInteger) {
- left.Emit (ec);
- if (my_on_true)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
-
+ left.EmitBranchable (ec, target, my_on_true);
return;
- } else if (right is BoolConstant) {
- left.Emit (ec);
- if (my_on_true != ((BoolConstant) right).Value)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
-
+ }
+ if (right.Type == TypeManager.bool_type) {
+ // right is a boolean, and it's not 'false' => it is 'true'
+ left.EmitBranchable (ec, target, !my_on_true);
return;
}
ig.Emit (OpCodes.Blt, target);
break;
default:
- Console.WriteLine (oper);
- throw new Exception ("what is THAT");
+ throw new InternalErrorException (oper.ToString ());
}
}
public override void Emit (EmitContext ec)
+ {
+ EmitOperator (ec, left.Type);
+ }
+
+ protected virtual void EmitOperator (EmitContext ec, Type l)
{
ILGenerator ig = ec.ig;
- Type l = left.Type;
- OpCode opcode;
//
// Handle short-circuit operators differently
// than the rest
//
- if (oper == Operator.LogicalAnd) {
- Label load_zero = ig.DefineLabel ();
- Label end = ig.DefineLabel ();
-
- left.EmitBranchable (ec, load_zero, false);
- right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
-
- ig.MarkLabel (load_zero);
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.MarkLabel (end);
- return;
- } else if (oper == Operator.LogicalOr) {
- Label load_one = ig.DefineLabel ();
+ if ((oper & Operator.LogicalMask) != 0) {
+ Label load_result = ig.DefineLabel ();
Label end = ig.DefineLabel ();
- left.EmitBranchable (ec, load_one, true);
+ bool is_or = oper == Operator.LogicalOr;
+ left.EmitBranchable (ec, load_result, is_or);
right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
+ ig.Emit (OpCodes.Br_S, end);
- ig.MarkLabel (load_one);
- ig.Emit (OpCodes.Ldc_I4_1);
+ ig.MarkLabel (load_result);
+ ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
ig.MarkLabel (end);
return;
}
left.Emit (ec);
+
+ //
+ // Optimize zero-based operations
+ //
+ // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
+ //
+ if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
+ Constant rc = right as Constant;
+ if (rc != null && rc.IsDefaultValue) {
+ return;
+ }
+ }
+
right.Emit (ec);
- bool is_unsigned = IsUnsigned (left.Type);
+ OpCode opcode;
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);
opcode = OpCodes.Xor;
break;
- default:
- throw new Exception ("This should not happen: Operator = "
- + oper.ToString ());
+ default:
+ throw new InternalErrorException (oper.ToString ());
+ }
+
+ ig.Emit (opcode);
+
+ //
+ // Nullable enum could require underlying type cast and we cannot simply wrap binary
+ // expression because that would wrap lifted binary operation
+ //
+ if (enum_conversion != null)
+ enum_conversion.Emit (ec);
+ }
+
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ if ((oper & Operator.LogicalMask) != 0 ||
+ (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
+ base.EmitSideEffect (ec);
+ } else {
+ left.EmitSideEffect (ec);
+ right.EmitSideEffect (ec);
}
-
- ig.Emit (opcode);
}
protected override void CloneTo (CloneContext clonectx, Expression t)
switch (oper) {
case Operator.Addition:
- if (method == null && ec.CheckState)
+ if (method == null && ec.CheckState && !IsFloat (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 (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 (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);
}
Append (ec, left);
Append (ec, right);
}
-
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Argument arg = (Argument) arguments [0];
+ return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
+ }
+
+ //
+ // Creates nested calls tree from an array of arguments used for IL emit
+ //
+ Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
+ {
+ ArrayList concat_args = new ArrayList (2);
+ ArrayList add_args = new ArrayList (3);
+
+ concat_args.Add (left);
+ add_args.Add (new Argument (left_etree));
+
+ concat_args.Add (arguments [pos]);
+ add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
+
+ MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
+ if (method == null)
+ return null;
+
+ method = method.OverloadResolve (ec, ref concat_args, false, loc);
+ if (method == null)
+ return null;
+
+ add_args.Add (new Argument (method.CreateExpressionTree (ec)));
+
+ Expression expr = CreateExpressionFactoryCall ("Add", add_args);
+ if (++pos == arguments.Count)
+ return expr;
+
+ left = new Argument (new EmptyExpression (method.Type));
+ return CreateExpressionAddCall (ec, left, expr, pos);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
return this;
arguments.Add (new Argument (operand));
}
- Expression CreateConcatInvocation ()
+ Expression CreateConcatMemberExpression ()
{
- return new Invocation (
- new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
- arguments, true);
+ return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
}
public override void Emit (EmitContext ec)
{
- Expression concat = CreateConcatInvocation ();
+ Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
concat = concat.Resolve (ec);
if (concat != null)
concat.Emit (ec);
//
// 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);
}
}
is_add = is_addition;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
eclass = ExprClass.Variable;
Emit (ec, false);
}
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ // do nothing
+ }
+
//
// This method is used by parameters that are references, that are
// being passed as references: we only want to pass the pointer (that
source.Emit (ec);
// HACK: variable is already emitted when source is an initializer
- if (source is NewInitialize)
+ if (source is NewInitialize) {
+ if (leave_copy) {
+ Variable.EmitInstance (ec);
+ Variable.Emit (ec);
+ }
return;
+ }
if (leave_copy) {
ig.Emit (OpCodes.Dup);
}
}
+ 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;
if (type == null) {
VarExpr ve = local_info.Type as VarExpr;
if (ve != null) {
- ve.DoResolveLValue (ec, right_side);
+ if (!ve.InferType (ec, right_side))
+ return null;
type = local_info.VariableType = ve.Type;
}
}
public bool Resolve (EmitContext ec, Location loc)
{
+ if (Expr == null)
+ return false;
+
using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
// Verify that the argument is readable
if (ArgType != AType.Out)
/// </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 CreateExpressionFactoryCall ("Quote", args);
}
- args = new ArrayList (Arguments.Count + 3);
+ args = new ArrayList (Arguments == null ? 2 : Arguments.Count + 2);
if (mg.IsInstance)
args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
else
- args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
+ args.Add (new Argument (new NullLiteral (loc)));
args.Add (new Argument (mg.CreateExpressionTree (ec)));
- foreach (Argument a in Arguments) {
- Expression e = a.Expr.CreateExpressionTree (ec);
- if (e != null)
- args.Add (new Argument (e));
+ if (Arguments != null) {
+ foreach (Argument a in Arguments) {
+ Expression e = a.Expr.CreateExpressionTree (ec);
+ if (e != null)
+ args.Add (new Argument (e));
+ }
}
return CreateExpressionFactoryCall ("Call", args);
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 ());
if (t == TypeManager.decimal_type)
return new DecimalConstant (0, Location.Null);
if (TypeManager.IsEnumType (t))
- return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
+ return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
return null;
}
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);
+
+ if (method == null) {
+ args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ } else {
+ 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)
{
/// specified but where initialization data is mandatory.
/// </remarks>
public class ArrayCreation : Expression {
- Expression requested_base_type;
+ FullNamedExpression requested_base_type;
ArrayList initializers;
//
int const_initializers_count;
bool only_constant_initializers;
- public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
+ public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
{
this.requested_base_type = requested_base_type;
this.initializers = initializers;
}
}
- public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
+ public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
{
this.requested_base_type = requested_base_type;
this.initializers = initializers;
expect_initializers = true;
}
- public Expression FormArrayType (Expression base_type, int idx_count, string rank)
- {
- StringBuilder sb = new StringBuilder (rank);
-
- sb.Append ("[");
- for (int i = 1; i < idx_count; i++)
- sb.Append (",");
-
- sb.Append ("]");
-
- return new ComposedCast (base_type, sb.ToString (), loc);
- }
-
void Error_IncorrectArrayInitializer ()
{
Error (178, "Invalid rank specifier: expected `,' or `]'");
public override Expression CreateExpressionTree (EmitContext ec)
{
+ ArrayList args;
+
if (dimensions != 1) {
- Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
- return null;
+ if (initializers != null) {
+ Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+ return null;
+ }
+
+ args = new ArrayList (arguments.Count + 1);
+ args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
+ foreach (Argument a in arguments)
+ args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+ return CreateExpressionFactoryCall ("NewArrayBounds", args);
}
- ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
+ args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
if (array_data != null) {
foreach (Expression e in array_data)
}
+ Expression first_emit;
+ LocalTemporary first_emit_temp;
+
protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
{
element = element.Resolve (ec);
if (element == null)
return null;
+ if (element is CompoundAssign.Helper) {
+ if (first_emit != null)
+ throw new InternalErrorException ("Can only handle one mutator at a time");
+ first_emit = element;
+ element = first_emit_temp = new LocalTemporary (element.Type);
+ }
+
return Convert.ImplicitConversionRequired (
ec, element, array_element_type, loc);
}
byte [] element;
int count = array_data.Count;
- if (array_element_type.IsEnum)
- array_element_type = TypeManager.EnumToUnderlying (array_element_type);
+ if (TypeManager.IsEnumType (array_element_type))
+ array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
factor = GetTypeSize (array_element_type);
if (factor == 0)
{
ILGenerator ig = ec.ig;
+ if (first_emit != null) {
+ first_emit.Emit (ec);
+ first_emit_temp.Store (ec);
+ }
+
foreach (Argument a in arguments)
a.Emit (ec);
EmitDynamicInitializers (ec, false);
} else {
EmitDynamicInitializers (ec, true);
- }
+ }
+
+ if (first_emit_temp != null)
+ first_emit_temp.Release (ec);
}
public override bool GetAttributableValue (Type value_type, out object value)
ArrayCreation target = (ArrayCreation) t;
if (requested_base_type != null)
- target.requested_base_type = requested_base_type.Clone (clonectx);
+ target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
if (arguments != null){
target.arguments = new ArrayList (arguments.Count);
this.loc = loc;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
eclass = ExprClass.Variable;
}
}
- //
- // This produces the value that renders an instance, used by the iterators code
- //
- public class ProxyInstance : Expression, IMemoryLocation {
- public override Expression DoResolve (EmitContext ec)
- {
- eclass = ExprClass.Variable;
- type = ec.ContainerType;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
-
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
- }
- }
-
/// <summary>
/// Implements the typeof operator
/// </summary>
loc = l;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (this));
+ args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ return CreateExpressionFactoryCall ("Constant", args);
+ }
+
public override Expression DoResolve (EmitContext ec)
{
+ if (eclass != ExprClass.Invalid)
+ return this;
+
TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
if (texpr == null)
return null;
type = TypeManager.type_type;
+ return DoResolveBase ();
+ }
+
+ protected Expression DoResolveBase ()
+ {
if (TypeManager.system_type_get_type_from_handle == null) {
TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
protected override void CloneTo (CloneContext clonectx, Expression t)
{
TypeOf target = (TypeOf) t;
-
- target.QueriedType = QueriedType.Clone (clonectx);
+ if (QueriedType != null)
+ target.QueriedType = QueriedType.Clone (clonectx);
}
}
loc = l;
}
- public override Expression DoResolve (EmitContext ec)
- {
- type = TypeManager.type_type;
- typearg = TypeManager.void_type;
- // See description in TypeOf.
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = TypeManager.type_type;
+ typearg = TypeManager.void_type;
+
+ return DoResolveBase ();
+ }
+ }
+
+ class TypeOfMethodInfo : TypeOfMethod
+ {
+ public TypeOfMethodInfo (MethodBase method, Location loc)
+ : base (method, loc)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = typeof (MethodInfo);
+ return base.DoResolve (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
+ base.Emit (ec);
+ ec.ig.Emit (OpCodes.Castclass, type);
+ }
+ }
+
+ class TypeOfConstructorInfo : TypeOfMethod
+ {
+ public TypeOfConstructorInfo (MethodBase method, Location loc)
+ : base (method, loc)
+ {
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = typeof (ConstructorInfo);
+ return base.DoResolve (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
+ base.Emit (ec);
+ ec.ig.Emit (OpCodes.Castclass, type);
+ }
+ }
+
+ abstract class TypeOfMethod : Expression
+ {
+ protected readonly MethodBase method;
+
+ protected TypeOfMethod (MethodBase method, Location loc)
+ {
+ this.method = method;
+ this.loc = loc;
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (this));
+ args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ return CreateExpressionFactoryCall ("Constant", args);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ 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)
+ 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;
+ }
+
eclass = ExprClass.Value;
return this;
}
+
+ public override void Emit (EmitContext ec)
+ {
+ 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 TypeOfMethod : Expression
+ internal class TypeOfField : Expression
{
- readonly MethodInfo method;
+ readonly FieldInfo field;
- public TypeOfMethod (MethodInfo method, Location loc)
+ public TypeOfField (FieldInfo field, Location loc)
{
- this.method = method;
+ this.field = field;
this.loc = loc;
}
public override Expression DoResolve (EmitContext ec)
{
- if (TypeManager.methodbase_get_type_from_handle == null) {
- Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
- Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
+ 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.methodbase_get_type_from_handle = TypeManager.GetPredefinedMethod (t,
- "GetMethodFromHandle", loc, handle_type);
+ TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
+ "GetFieldFromHandle", loc, handle_type);
}
- type = typeof (MethodBase);
+ type = typeof (FieldInfo);
eclass = ExprClass.Value;
return this;
}
public override void Emit (EmitContext ec)
{
- ec.ig.Emit (OpCodes.Ldtoken, method);
- ec.ig.Emit (OpCodes.Call, TypeManager.methodbase_get_type_from_handle);
+ ec.ig.Emit (OpCodes.Ldtoken, field);
+ ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
}
}
loc = l;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
if (texpr == null)
return null;
-#if GMCS_SOURCE
- if (texpr is TypeParameterExpr){
- ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
- return null;
- }
-#endif
-
type_queried = texpr.Type;
- if (type_queried.IsEnum)
- type_queried = TypeManager.EnumToUnderlying (type_queried);
+ if (TypeManager.IsEnumType (type_queried))
+ type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
if (type_queried == TypeManager.void_type) {
Expression.Error_VoidInvalidInTheContext (loc);
return new IntConstant (size_of, loc);
}
- if (!ec.InUnsafe) {
- Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
- TypeManager.CSharpName (type_queried));
+ if (!TypeManager.VerifyUnManaged (type_queried, loc)){
return null;
}
- if (!TypeManager.VerifyUnManaged (type_queried, loc)){
- return null;
+ if (!ec.InUnsafe) {
+ Report.Error (233, loc,
+ "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
+ TypeManager.CSharpName (type_queried));
}
type = TypeManager.int32_type;
/// <summary>
/// Implements the qualified-alias-member (::) expression.
/// </summary>
- public class QualifiedAliasMember : Expression
+ public class QualifiedAliasMember : MemberAccess
{
- string alias, identifier;
+ readonly string alias;
+
+ public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
+ : base (null, identifier, targs, l)
+ {
+ this.alias = alias;
+ }
public QualifiedAliasMember (string alias, string identifier, Location l)
+ : base (null, identifier, l)
{
this.alias = alias;
- this.identifier = identifier;
- loc = l;
}
public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
{
- if (alias == "global")
- return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
+ if (alias == "global") {
+ expr = RootNamespace.Global;
+ return base.ResolveAsTypeStep (ec, silent);
+ }
int errors = Report.Errors;
- FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
- if (fne == null) {
+ expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
+ if (expr == null) {
if (errors == Report.Errors)
Report.Error (432, loc, "Alias `{0}' not found", alias);
return null;
}
- if (fne.eclass != ExprClass.Namespace) {
- if (!silent)
- Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
- return null;
- }
- return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- FullNamedExpression fne;
- if (alias == "global") {
- fne = RootNamespace.Global;
- } else {
- int errors = Report.Errors;
- fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
- if (fne == null) {
- if (errors == Report.Errors)
- Report.Error (432, loc, "Alias `{0}' not found", alias);
- return null;
- }
- }
- Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
- if (retval == null)
+ FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
+ if (fne == null)
return null;
- if (!(retval is FullNamedExpression)) {
- Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
+ if (expr.eclass == ExprClass.Type) {
+ if (!silent) {
+ Report.Error (431, loc,
+ "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
+ }
return null;
}
- // We defer this check till the end to match the behaviour of CSC
- if (fne.eclass != ExprClass.Namespace) {
- Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
- return null;
- }
- return retval;
+ return fne;
}
- public override void Emit (EmitContext ec)
+ public override Expression DoResolve (EmitContext ec)
{
- throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
+ return ResolveAsTypeStep (ec, false);
}
-
- public override string ToString ()
+ protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
{
- return alias + "::" + identifier;
+ Report.Error (687, loc,
+ "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
+ GetSignatureForError ());
}
public override string GetSignatureForError ()
{
- return ToString ();
+ string name = Name;
+ if (targs != null) {
+ name = TypeManager.RemoveGenericArity (Name) + "<" +
+ targs.GetSignatureForError () + ">";
+ }
+
+ return alias + "::" + name;
}
protected override void CloneTo (CloneContext clonectx, Expression t)
/// <summary>
/// Implements the member access expression
/// </summary>
- public class MemberAccess : Expression {
- public readonly string Identifier;
- Expression expr;
- readonly TypeArguments args;
+ public class MemberAccess : ATypeNameExpression {
+ protected Expression expr;
public MemberAccess (Expression expr, string id)
- : this (expr, id, expr.Location)
+ : base (id, expr.Location)
{
+ this.expr = expr;
}
public MemberAccess (Expression expr, string identifier, Location loc)
+ : base (identifier, loc)
{
this.expr = expr;
- Identifier = identifier;
- this.loc = loc;
}
public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
- : this (expr, identifier, loc)
+ : base (identifier, args, loc)
{
- this.args = args;
- }
-
- protected string LookupIdentifier {
- get { return MemberName.MakeName (Identifier, args); }
+ this.expr = expr;
}
// TODO: this method has very poor performace for Enum fields and
if (expr_resolved == null)
return null;
+ string LookupIdentifier = MemberName.MakeName (Name, targs);
+
if (expr_resolved is Namespace) {
Namespace ns = (Namespace) expr_resolved;
FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
#if GMCS_SOURCE
- if ((retval != null) && (args != null))
- retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
+ if ((retval != null) && (targs != null))
+ retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
#endif
if (retval == null)
- ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
+ ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
return retval;
}
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) {
"System.NullReferenceException");
}
- if (args != null) {
- if (!args.Resolve (ec))
+ if (targs != null) {
+ if (!targs.Resolve (ec))
return null;
}
Expression member_lookup;
member_lookup = MemberLookup (
- ec.ContainerType, expr_type, expr_type, Identifier, loc);
+ ec.ContainerType, expr_type, expr_type, Name, loc);
#if GMCS_SOURCE
- if ((member_lookup == null) && (args != null)) {
+ if ((member_lookup == null) && (targs != null)) {
member_lookup = MemberLookup (
ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
}
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, Name, loc);
if (ex_method_lookup != null) {
ex_method_lookup.ExtensionExpression = expr_resolved;
- if (args != null) {
- ex_method_lookup.SetTypeArguments (args);
+ if (targs != null) {
+ ex_method_lookup.SetTypeArguments (targs);
}
return ex_method_lookup.DoResolve (ec);
expr = expr_resolved;
Error_MemberLookupFailed (
- ec.ContainerType, expr_type, expr_type, Identifier, null,
+ ec.ContainerType, expr_type, expr_type, Name, null,
AllMemberTypes, AllBindingFlags);
return null;
}
if (!(expr_resolved is TypeExpr) &&
(original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
- Identifier, member_lookup.GetSignatureForError ());
+ Name, member_lookup.GetSignatureForError ());
return null;
}
if (me == null)
return null;
- if (args != null) {
- me.SetTypeArguments (args);
+ if (targs != null) {
+ me.SetTypeArguments (targs);
}
if (original != null && !TypeManager.IsValueType (expr_type)) {
if (new_expr == null)
return null;
+ string LookupIdentifier = MemberName.MakeName (Name, targs);
+
if (new_expr is Namespace) {
Namespace ns = (Namespace) new_expr;
FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
#if GMCS_SOURCE
- if ((retval != null) && (args != null))
- retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
+ if ((retval != null) && (targs != null))
+ retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
#endif
if (!silent && retval == null)
ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
if (silent)
return null;
- member_lookup = MemberLookup (
- rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
- MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
-
- if (member_lookup != null) {
- tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
- if (tnew_expr == null)
- return null;
-
- Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
- return null;
- }
-
- member_lookup = MemberLookup (
- rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
- MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
-
- if (member_lookup == null) {
- Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
- Identifier, new_expr.GetSignatureForError ());
- } else {
- // TODO: Report.SymbolRelatedToPreviousError
- member_lookup.Error_UnexpectedKind (null, "type", loc);
- }
+ Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
return null;
}
return null;
#if GMCS_SOURCE
- TypeArguments the_args = args;
+ TypeArguments the_args = targs;
Type declaring_type = texpr.Type.DeclaringType;
if (TypeManager.HasGenericArguments (declaring_type)) {
while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
new_args.Add (new TypeExpression (decl, loc));
- if (args != null)
- new_args.Add (args);
+ if (targs != null)
+ new_args.Add (targs);
the_args = new_args;
}
return texpr;
}
- public override void Emit (EmitContext ec)
+ protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
{
- throw new Exception ("Should not happen");
+ Expression member_lookup = MemberLookup (
+ rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
+ MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
+
+ if (member_lookup != null) {
+ expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
+ if (expr_type == null)
+ return;
+
+ Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
+ return;
+ }
+
+ member_lookup = MemberLookup (
+ rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
+ MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
+
+ if (member_lookup == null) {
+ Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
+ Name, expr_type.GetSignatureForError ());
+ } else {
+ // TODO: Report.SymbolRelatedToPreviousError
+ member_lookup.Error_UnexpectedKind (null, "type", loc);
+ }
}
protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
base.Error_TypeDoesNotContainDefinition (type, name);
}
- public override string ToString ()
- {
- return expr + "." + MemberName.MakeName (Identifier, args);
- }
-
public override string GetSignatureForError ()
{
- return expr.GetSignatureForError () + "." + Identifier;
+ return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
}
protected override void CloneTo (CloneContext clonectx, Expression t)
ElementAccess ea;
LocalTemporary temp;
- LocalTemporary prepared_value;
bool prepared;
else if (type == TypeManager.intptr_type)
ig.Emit (OpCodes.Ldelem_I);
else if (TypeManager.IsEnumType (type)){
- EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
+ EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
} else if (type.IsValueType){
ig.Emit (OpCodes.Ldelema, type);
ig.Emit (OpCodes.Ldobj, type);
has_type_arg = false; is_stobj = false;
t = TypeManager.TypeToCoreType (t);
if (TypeManager.IsEnumType (t))
- t = TypeManager.EnumToUnderlying (t);
+ t = TypeManager.GetEnumUnderlyingType (t);
if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
t == TypeManager.bool_type)
return OpCodes.Stelem_I1;
//
// Load the array arguments into the stack.
//
- // If we have been requested to cache the values (cached_locations array
- // initialized), then load the arguments the first time and store them
- // in locals. otherwise load from local variables.
- //
- // prepare_for_load is used in compound assignments to cache original index
- // values ( label[idx++] += s )
- //
- LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
+ void LoadArrayAndArguments (EmitContext ec)
{
ea.Expr.Emit (ec);
- LocalTemporary[] indexes = null;
- if (prepare_for_load) {
- ec.ig.Emit (OpCodes.Dup);
- indexes = new LocalTemporary [ea.Arguments.Count];
- }
-
for (int i = 0; i < ea.Arguments.Count; ++i) {
((Argument)ea.Arguments [i]).Emit (ec);
- if (!prepare_for_load)
- continue;
-
- // Keep original array index value on the stack
- ec.ig.Emit (OpCodes.Dup);
-
- indexes [i] = new LocalTemporary (TypeManager.intptr_type);
- indexes [i].Store (ec);
}
-
- return indexes;
}
public void Emit (EmitContext ec, bool leave_copy)
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
- if (prepared_value != null) {
- prepared_value.Emit (ec);
- } else if (prepared) {
+ if (prepared) {
LoadFromPtr (ig, this.type);
} else {
- LoadArrayAndArguments (ec, false);
+ LoadArrayAndArguments (ec);
EmitLoadOpcode (ig, type, rank);
}
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
Type t = source.Type;
- prepared = prepare_for_load && !(source is StringConcat);
+ prepared = prepare_for_load;
if (prepared) {
AddressOf (ec, AddressOp.LoadStore);
ec.ig.Emit (OpCodes.Dup);
} else {
- LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
- prepare_for_load && (source is StringConcat));
-
- if (original_indexes_values != null) {
- prepared_value = new LocalTemporary (type);
- EmitLoadOpcode (ig, type, rank);
- prepared_value.Store (ec);
- foreach (LocalTemporary lt in original_indexes_values) {
- lt.Emit (ec);
- lt.Release (ec);
- }
- }
+ LoadArrayAndArguments (ec);
}
if (rank == 1) {
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
- LoadArrayAndArguments (ec, false);
+ LoadArrayAndArguments (ec);
if (rank == 1){
ig.Emit (OpCodes.Ldelema, type);
}
}
- type = pi.PropertyType;
+ type = TypeManager.TypeToCoreType (pi.PropertyType);
if (type.IsPointer && !ec.InUnsafe)
UnsafeError (loc);
// nothing, as we only exist to not do anything.
}
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ }
+
//
// This is just because we might want to reuse this bad boy
// instead of creating gazillions of EmptyExpressions.
{
this.method = method;
this.source = source;
- type = method.ReturnType;
+ type = TypeManager.TypeToCoreType (method.ReturnType);
eclass = ExprClass.Value;
loc = l;
}
ArrayList args = new ArrayList (2);
args.Add (new Argument (source.CreateExpressionTree (ec)));
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
- args.Add (new Argument (new Cast (new TypeExpression (typeof (MethodInfo), loc),
- new TypeOfMethod (method, loc))));
+ args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
return CreateExpressionFactoryCall ("Convert", args);
}
// one bit at a time.
// </summary>
public class ComposedCast : TypeExpr {
- Expression left;
+ FullNamedExpression left;
string dim;
- public ComposedCast (Expression left, string dim)
+ public ComposedCast (FullNamedExpression left, string dim)
: this (left, dim, left.Location)
{
}
- public ComposedCast (Expression left, string dim, Location l)
+ public ComposedCast (FullNamedExpression left, string dim, Location l)
{
this.left = left;
this.dim = dim;
#if GMCS_SOURCE
if ((dim.Length > 0) && (dim [0] == '?')) {
- TypeExpr nullable = new NullableType (left, loc);
+ TypeExpr nullable = new Nullable.NullableType (left, loc);
if (dim.Length > 1)
nullable = new ComposedCast (nullable, dim.Substring (1), loc);
return nullable.ResolveAsTypeTerminal (ec, false);
return this;
}
- public override string Name {
- get { return left + dim; }
- }
-
- public override string FullName {
- get { return type.FullName; }
- }
-
public override string GetSignatureForError ()
{
return left.GetSignatureForError () + dim;
{
ComposedCast target = (ComposedCast) t;
- target.left = left.Clone (clonectx);
+ target.left = (FullNamedExpression)left.Clone (clonectx);
}
}
eclass = ExprClass.Value;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
public override void Emit(EmitContext ec)
{
array.Emit (ec);
//
// Encapsulates a conversion rules required for array indexes
//
- public class ArrayIndexCast : Expression
+ public class ArrayIndexCast : TypeCast
{
- Expression expr;
-
public ArrayIndexCast (Expression expr)
+ : base (expr, expr.Type)
{
- this.expr = expr;
- this.loc = expr.Location;
}
public override Expression CreateExpressionTree (EmitContext ec)
{
ArrayList args = new ArrayList (2);
- args.Add (new Argument (expr.CreateExpressionTree (ec)));
+ args.Add (new Argument (child.CreateExpressionTree (ec)));
args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
return CreateExpressionFactoryCall ("ConvertChecked", args);
}
- public override Expression DoResolve (EmitContext ec)
- {
- type = expr.Type;
- eclass = expr.eclass;
- return this;
- }
-
public override void Emit (EmitContext ec)
{
- expr.Emit (ec);
+ child.Emit (ec);
if (type == TypeManager.int32_type)
return;
}
}
- //
- // Used by the fixed statement
- //
- public class StringPtr : Expression {
- LocalBuilder b;
-
- public StringPtr (LocalBuilder b, Location l)
- {
- this.b = b;
- eclass = ExprClass.Value;
- type = TypeManager.char_ptr_type;
- loc = l;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- // This should never be invoked, we are born in fully
- // initialized state.
-
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- if (TypeManager.int_get_offset_to_string_data == null) {
- // TODO: Move to resolve !!
- TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
- TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
- }
-
- ILGenerator ig = ec.ig;
-
- ig.Emit (OpCodes.Ldloc, b);
- ig.Emit (OpCodes.Conv_I);
- ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
- ig.Emit (OpCodes.Add);
- }
- }
-
//
// Implements the `stackalloc' keyword
//
loc = l;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
count = count.Resolve (ec);
//
// 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)
{
- if (initializer == null)
- return;
-
ElementInitializer target = (ElementInitializer) t;
- target.initializer = initializer.Clone (clonectx);
+ target.source = source.Clone (clonectx);
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ 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 ()));
+
+ 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;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ 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);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
CollectionElementInitializer target = (CollectionElementInitializer) t;
- ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
- foreach (Expression e in arguments)
- t_arguments.Add (e.Clone (clonectx));
+
+ target.Arguments = new ArrayList (Arguments.Count);
+ foreach (Expression e in Arguments)
+ target.Arguments.Add (e.Clone (clonectx));
}
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 ("ET");
+ }
+
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)
t.initializer = initializer.Clone (clonectx);
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override bool Equals (object o)
{
AnonymousTypeParameter other = o as AnonymousTypeParameter;