// 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
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 ()
+ 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)
{
- return "Unary (" + Oper + ", " + 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;
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;
Expression expr;
bool primitives_only = false;
+ if (standard_operators == null)
+ CreateStandardOperatorsTable ();
+
//
// Handles predefined primitive types
//
}
}
- 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;
}
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;
}
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);
CheckUselessComparison (rc, left.Type);
}
- if ((TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.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);
//
// Enumeration operators
//
- Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
+ 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.GetEnumUnderlyingType (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;
+ }
+
+ //
+ // 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;
}
- if (renum) {
- //
- // E operator + (U x, E e)
- //
- if (oper == Operator.Addition) {
- underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
- temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
- if (temp == null)
- return null;
+ 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);
- left = temp;
- type = rtype;
- return this;
- }
+ 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.GetEnumUnderlyingType (ltype);
- return this;
- }
+ if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+ return null;
- return null;
+ expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+ return expr;
}
//
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
//
- protected virtual 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;
- return best_operator.ConvertResult (ec, this);
+ Expression expr = best_operator.ConvertResult (ec, this);
+ if (enum_type == null)
+ return expr;
+
+ //
+ // HACK: required by enum_conversion
+ //
+ expr.Type = enum_type;
+ return EmptyCast.Create (expr, enum_type);
}
//
}
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;
}
public override void Emit (EmitContext ec)
{
- EmitOperator (ec);
+ EmitOperator (ec, left.Type);
}
- protected void EmitOperator (EmitContext ec)
+ protected virtual void EmitOperator (EmitContext ec, Type l)
{
ILGenerator ig = ec.ig;
right.Emit (ec);
- Type l = left.Type;
OpCode opcode;
switch (oper){
}
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);
+ }
}
protected override void CloneTo (CloneContext clonectx, Expression t)
switch (oper) {
case Operator.Addition:
- if (method == null && ec.CheckState && !IsFloat (left.Type))
+ if (method == null && ec.CheckState && !IsFloat (type))
method_name = "AddChecked";
else
method_name = "Add";
method_name = "Modulo";
break;
case Operator.Multiply:
- if (method == null && ec.CheckState && !IsFloat (left.Type))
+ if (method == null && ec.CheckState && !IsFloat (type))
method_name = "MultiplyChecked";
else
method_name = "Multiply";
method_name = "RightShift";
break;
case Operator.Subtraction:
- if (method == null && ec.CheckState && !IsFloat (left.Type))
+ if (method == null && ec.CheckState && !IsFloat (type))
method_name = "SubtractChecked";
else
method_name = "Subtract";
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 ());
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);
}
{
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;
protected override void CloneTo (CloneContext clonectx, Expression t)
{
TypeOf target = (TypeOf) t;
+ if (QueriedType != null)
+ target.QueriedType = QueriedType.Clone (clonectx);
+ }
+ }
+
+ /// <summary>
+ /// Implements the `typeof (void)' operator
+ /// </summary>
+ public class TypeOfVoid : TypeOf {
+ public TypeOfVoid (Location l) : base (null, l)
+ {
+ loc = l;
+ }
+
+ 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);
+ }
- target.QueriedType = QueriedType.Clone (clonectx);
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
+ base.Emit (ec);
+ ec.ig.Emit (OpCodes.Castclass, type);
}
}
- /// <summary>
- /// Implements the `typeof (void)' operator
- /// </summary>
- public class TypeOfVoid : TypeOf {
- public TypeOfVoid (Location l) : base (null, l)
- {
- loc = l;
+ 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 Expression DoResolve (EmitContext ec)
+ public override void Emit (EmitContext ec)
{
- type = TypeManager.type_type;
- typearg = TypeManager.void_type;
+ 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;
+ }
- return DoResolveBase ();
+ 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 (TypeManager.IsEnumType (type_queried))
type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
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;
//
// 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);
// 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.
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;
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;