}
if (expr.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
// Holds the real operation
Expression operation;
+ static TypeSpec[] predefined;
+
public UnaryMutator (Mode m, Expression e, Location loc)
{
mode = m;
return new SimpleAssign (this, this).CreateExpressionTree (ec);
}
+ void CreatePredefinedOperators ()
+ {
+ //
+ // Predefined ++ and -- operators exist for the following types:
+ // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
+ //
+ predefined = new TypeSpec[] {
+ TypeManager.int32_type,
+
+ TypeManager.sbyte_type,
+ TypeManager.byte_type,
+ TypeManager.short_type,
+ TypeManager.ushort_type,
+ TypeManager.uint32_type,
+ TypeManager.int64_type,
+ TypeManager.uint64_type,
+ TypeManager.char_type,
+ TypeManager.float_type,
+ TypeManager.double_type,
+ TypeManager.decimal_type
+ };
+ }
+
protected override Expression DoResolve (ResolveContext ec)
{
expr = expr.Resolve (ec);
eclass = ExprClass.Value;
type = expr.Type;
- return ResolveOperator (ec);
+
+ if (expr is RuntimeValueExpression) {
+ operation = expr;
+ } else {
+ // Use itself at the top of the stack
+ operation = new EmptyExpression (type);
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ // TODO: Move to parser, expr is ATypeNameExpression
+ if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+ expr = expr.ResolveLValue (ec, expr);
+ } else {
+ ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
+ }
+
+ //
+ // Step 1: Try to find a user operator, it has priority over predefined ones
+ //
+ var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
+ var methods = MemberCache.GetUserOperator (type, user_op, false);
+
+ if (methods != null) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var method = res.ResolveOperator (ec, ref args);
+ if (method == null)
+ return null;
+
+ args[0].Expr = operation;
+ operation = new UserOperatorCall (method, args, null, loc);
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ return this;
+ }
+
+ //
+ // Step 2: Try predefined types
+ //
+ if (predefined == null)
+ CreatePredefinedOperators ();
+
+ // Predefined without user conversion first for speed-up
+ Expression source = null;
+ bool primitive_type = false;
+ foreach (var t in predefined) {
+ if (t == type) {
+ source = operation;
+ primitive_type = true;
+ break;
+ }
+ }
+
+ // ++/-- on pointer variables of all types except void*
+ if (source == null && type.IsPointer) {
+ if (type == TypeManager.void_ptr_type) {
+ Error_VoidPointerOperation (ec);
+ return null;
+ }
+
+ source = operation;
+ }
+
+ if (source == null) {
+ // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
+ foreach (var t in predefined) {
+ source = Convert.ImplicitUserConversion (ec, operation, t, loc);
+ if (source != null) {
+ break;
+ }
+ }
+ }
+
+ // ++/-- on enum types
+ if (source == null && type.IsEnum)
+ source = operation;
+
+ if (source == null) {
+ Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
+ return null;
+ }
+
+ var one = new IntConstant (1, loc);
+ var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+ operation = new Binary (op, source, one, loc);
+ operation = operation.Resolve (ec);
+ if (operation == null)
+ throw new NotImplementedException ("should not be reached");
+
+ if (operation.Type != type) {
+ if (primitive_type)
+ operation = Convert.ExplicitNumericConversion (operation, type);
+ else
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ }
+
+ return this;
}
void EmitCode (EmitContext ec, bool is_expr)
get { return (mode & Mode.IsDecrement) != 0; }
}
- //
- // Returns whether an object of type `t' can be incremented
- // or decremented with add/sub (ie, basically whether we can
- // use pre-post incr-decr operations on it, but it is not a
- // System.Decimal, which we require operator overloading to catch)
- //
- static bool IsPredefinedOperator (TypeSpec t)
- {
- return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
- TypeManager.IsEnumType (t) ||
- t.IsPointer && t != TypeManager.void_ptr_type;
- }
#if NET_4_0
public override SLE.Expression MakeExpression (BuilderContext ctx)
}
#endif
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public static void Reset ()
{
- UnaryMutator target = (UnaryMutator) t;
-
- target.expr = expr.Clone (clonectx);
+ predefined = null;
}
- Expression ResolveOperator (ResolveContext ec)
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- if (expr is RuntimeValueExpression) {
- operation = expr;
- } else {
- // Use itself at the top of the stack
- operation = new EmptyExpression (type);
- }
-
- //
- // The operand of the prefix/postfix increment decrement operators
- // should be an expression that is classified as a variable,
- // a property access or an indexer access
- //
- if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
- expr = expr.ResolveLValue (ec, expr);
- } else {
- ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
- }
-
- //
- // 1. Check predefined types
- //
- if (IsPredefinedOperator (type)) {
- // TODO: Move to IntConstant once I get rid of int32_type
- var one = new IntConstant (1, loc);
-
- // TODO: Cache this based on type when using EmptyExpression in
- // context cache
- Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
- operation = new Binary (op, operation, one, loc);
- operation = operation.Resolve (ec);
- if (operation != null && operation.Type != type)
- operation = Convert.ExplicitNumericConversion (operation, type);
-
- return this;
- }
-
- //
- // Step 2: Perform Operator overload resolution
- //
- var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
- var methods = MemberCache.GetUserOperator (type, user_op, false);
-
- if (methods != null) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
-
- var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
- var op = res.ResolveOperator (ec, ref args);
- if (op == null)
- return null;
-
- args[0].Expr = operation;
- operation = new UserOperatorCall (op, args, null, loc);
- operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
- return this;
- }
-
- string name = IsDecrement ?
- Operator.GetName (Operator.OpType.Decrement) :
- Operator.GetName (Operator.OpType.Increment);
+ UnaryMutator target = (UnaryMutator) t;
- Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
- return null;
+ target.expr = expr.Clone (clonectx);
}
}
if (TypeManager.IsReferenceType (type))
return new NullConstant (type, loc);
- Constant c = New.Constantify (type);
+ Constant c = New.Constantify (type, expr.Location);
if (c != null)
return c.Resolve (ec);
var c = b.right as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.left, b).Resolve (ec);
if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
return ReducedExpression.Create (b.left, b).Resolve (ec);
c = b.left as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (b.oper == Operator.Multiply && c.IsOneInteger)
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
Constant rc = right as Constant;
Constant lc = left as Constant;
- if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
+ if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
//
// The result is a constant with side-effect
//
eclass = ExprClass.Variable;
if (left.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
}
}
- /// <summary>
- /// Implements the new expression
- /// </summary>
- public class New : ExpressionStatement, IMemoryLocation {
- protected Arguments Arguments;
+ //
+ // Implements simple new expression
+ //
+ public class New : ExpressionStatement, IMemoryLocation
+ {
+ protected Arguments arguments;
//
// During bootstrap, it contains the RequestedType,
public New (Expression requested_type, Arguments arguments, Location l)
{
RequestedType = requested_type;
- Arguments = arguments;
+ this.arguments = arguments;
loc = l;
}
+ #region Properties
+ public Arguments Arguments {
+ get {
+ return arguments;
+ }
+ }
+
+ //
+ // Returns true for resolved `new S()'
+ //
+ public bool IsDefaultStruct {
+ get {
+ return arguments == null && type.IsStruct && GetType () == typeof (New);
+ }
+ }
+
+ #endregion
+
/// <summary>
/// Converts complex core type syntax like 'new int ()' to simple constant
/// </summary>
- public static Constant Constantify (TypeSpec t)
+ public static Constant Constantify (TypeSpec t, Location loc)
{
if (t == TypeManager.int32_type)
- return new IntConstant (0, Location.Null);
+ return new IntConstant (0, loc);
if (t == TypeManager.uint32_type)
- return new UIntConstant (0, Location.Null);
+ return new UIntConstant (0, loc);
if (t == TypeManager.int64_type)
- return new LongConstant (0, Location.Null);
+ return new LongConstant (0, loc);
if (t == TypeManager.uint64_type)
- return new ULongConstant (0, Location.Null);
+ return new ULongConstant (0, loc);
if (t == TypeManager.float_type)
- return new FloatConstant (0, Location.Null);
+ return new FloatConstant (0, loc);
if (t == TypeManager.double_type)
- return new DoubleConstant (0, Location.Null);
+ return new DoubleConstant (0, loc);
if (t == TypeManager.short_type)
- return new ShortConstant (0, Location.Null);
+ return new ShortConstant (0, loc);
if (t == TypeManager.ushort_type)
- return new UShortConstant (0, Location.Null);
+ return new UShortConstant (0, loc);
if (t == TypeManager.sbyte_type)
- return new SByteConstant (0, Location.Null);
+ return new SByteConstant (0, loc);
if (t == TypeManager.byte_type)
- return new ByteConstant (0, Location.Null);
+ return new ByteConstant (0, loc);
if (t == TypeManager.char_type)
- return new CharConstant ('\0', Location.Null);
+ return new CharConstant ('\0', loc);
if (t == TypeManager.bool_type)
- return new BoolConstant (false, Location.Null);
+ return new BoolConstant (false, loc);
if (t == TypeManager.decimal_type)
- return new DecimalConstant (0, Location.Null);
+ return new DecimalConstant (0, loc);
if (TypeManager.IsEnumType (t))
- return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t)), t);
+ return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
if (TypeManager.IsNullableType (t))
- return Nullable.LiftedNull.Create (t, Location.Null);
+ return Nullable.LiftedNull.Create (t, loc);
return null;
}
if (real_class == null)
return null;
- New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
+ New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
return cast.Resolve (ec);
}
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
} else {
args = Arguments.CreateForExpressionTree (ec,
- Arguments, new TypeOfMethod (method, loc));
+ arguments, new TypeOfMethod (method, loc));
}
return CreateExpressionFactoryCall (ec, "New", args);
return null;
}
- if (Arguments == null) {
- Constant c = Constantify (type);
+ if (arguments == null) {
+ Constant c = Constantify (type, RequestedType.Location);
if (c != null)
return ReducedExpression.Create (c.Resolve (ec), this);
}
if (TypeManager.IsDelegateType (type)) {
- return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+ return (new NewDelegate (type, arguments, loc)).Resolve (ec);
}
var tparam = type as TypeParameterSpec;
TypeManager.CSharpName (type));
}
- if ((Arguments != null) && (Arguments.Count != 0)) {
+ if ((arguments != null) && (arguments.Count != 0)) {
ec.Report.Error (417, loc,
"`{0}': cannot provide arguments when creating an instance of a variable type",
TypeManager.CSharpName (type));
//
// Any struct always defines parameterless constructor
//
- if (type.IsStruct && Arguments == null)
+ if (type.IsStruct && arguments == null)
return this;
bool dynamic;
- if (Arguments != null) {
- Arguments.Resolve (ec, out dynamic);
+ if (arguments != null) {
+ arguments.Resolve (ec, out dynamic);
} else {
dynamic = false;
}
- method = ConstructorLookup (ec, type, ref Arguments, loc);
+ method = ConstructorLookup (ec, type, ref arguments, loc);
if (dynamic) {
- Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
- return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
+ arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
+ return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
}
return this;
vr.EmitLoad (ec);
}
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
if (is_value_type) {
if (method == null) {
ec.Emit (OpCodes.Pop);
}
- public virtual bool HasInitializer {
- get {
- return false;
- }
- }
-
public void AddressOf (EmitContext ec, AddressOp mode)
{
EmitAddressOf (ec, mode);
if (method == null) {
ec.Emit (OpCodes.Initobj, type);
} else {
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
ec.Emit (OpCodes.Call, method);
}
New target = (New) t;
target.RequestedType = RequestedType.Clone (clonectx);
- if (Arguments != null){
- target.Arguments = Arguments.Clone (clonectx);
+ if (arguments != null){
+ target.arguments = arguments.Clone (clonectx);
}
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (Arguments, ctx));
+ return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
}
}
initializer.Resolve (ec);
throw new InternalErrorException ("This line should never be reached");
} else {
- if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type, false)) {
+ var t = ec.CurrentInitializerVariable.Type;
+ // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
+ if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
"object initializer because type `{1}' does not implement `{2}' interface",
ec.CurrentInitializerVariable.GetSignatureForError (),
return left_on_stack;
}
-
- public override bool HasInitializer {
- get {
- return !initializers.IsEmpty;
- }
- }
}
public class NewAnonymousType : New
foreach (Property p in anonymous_type.Properties)
init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
- var ctor_args = new ArrayInitializer (Arguments.Count, loc);
- foreach (Argument a in Arguments)
+ var ctor_args = new ArrayInitializer (arguments.Count, loc);
+ foreach (Argument a in arguments)
ctor_args.Add (a.CreateExpressionTree (ec));
Arguments args = new Arguments (3);
}
bool error = false;
- Arguments = new Arguments (parameters.Count);
+ arguments = new Arguments (parameters.Count);
TypeExpression [] t_args = new TypeExpression [parameters.Count];
for (int i = 0; i < parameters.Count; ++i) {
Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
continue;
}
- Arguments.Add (new Argument (e));
+ arguments.Add (new Argument (e));
t_args [i] = new TypeExpression (e.Type, e.Location);
}