Reapply Marek's patch after tagging 1-2-2
authorMiguel de Icaza <miguel@gnome.org>
Fri, 1 Dec 2006 15:29:30 +0000 (15:29 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 1 Dec 2006 15:29:30 +0000 (15:29 -0000)
2006-11-30  Marek Safar  <marek.safar@gmail.com>

        Correct unary operators implementation (part I)
        Also fixes #80026

        * cfold.cs (Error_CompileTimeOverflow): Made internal

        * const.cs (IConstant): Changed to use reference to constant and
        not constant itself.
        Updated IConstant implementations.

        * constant.cs (CreateConstant): New factory method.
        Updated IConstant implementation.

        * convert.cs (ImplicitStandardConversionExists): Uses compiler Equals.

        * ecore.cs: Updated to use CreateConstantReference.

        * enum.cs: Reflects IConstant changes.

        * expression.cs (Unary): Reimplemented +,-,~ to conform C# standard.

        * literal.cs (NullConstant): Change to be independently usable.

svn path=/trunk/mcs/; revision=68831

14 files changed:
mcs/errors/gcs0403-2.cs
mcs/errors/gcs0403.cs
mcs/errors/known-issues-gmcs
mcs/errors/known-issues-mcs
mcs/mcs/ChangeLog
mcs/mcs/cfold.cs
mcs/mcs/const.cs
mcs/mcs/constant.cs
mcs/mcs/convert.cs
mcs/mcs/ecore.cs
mcs/mcs/enum.cs
mcs/mcs/expression.cs
mcs/mcs/literal.cs
mcs/tests/known-issues-mcs

index 66502e5adc20dd83f4f0696d8467ee00b365f65c..dda9fd93d566cb152c395fb15225f388ba0ecbe6 100644 (file)
@@ -1,4 +1,4 @@
-// CS0403: Cannot convert null to the type parameter `T' becaues it could be a value type. Consider using `default (T)' instead\r
+// CS0403: Cannot convert null to the type parameter `T' because it could be a value type. Consider using `default (T)' instead\r
 // Line: 8\r
 \r
 struct S\r
index de4610a20752921095d80b16115682eb9bb22811..3e73bc7dd0458dca7aa7cda9d09e24577f61e6be 100644 (file)
@@ -1,4 +1,4 @@
-// CS0403: Cannot convert null to the type parameter `T' becaues it could be a value type. Consider using `default (T)' instead
+// CS0403: Cannot convert null to the type parameter `T' because it could be a value type. Consider using `default (T)' instead
 // Line: 7
 class Test<T>
 {
index 1309ebc2d3a1f28cd7a09aa426a691c683c062a6..59a8b9d5a14e5c19c51f179e07f041b67fc4b177 100644 (file)
@@ -35,3 +35,10 @@ cs1540-9.cs
 cs1586.cs
 cs1641.cs
 cs1670-2.cs
+
+# Unary operators
+cs0035.cs
+cs0266-11.cs
+cs0266-9.cs
+cs0457-2.cs
+cs0457.cs
index e206110a08f38f63b2d7ccfc0f2c5d56aab8928b..6689cd7e5a9ccfb896313616dd2430c63787a3c8 100644 (file)
@@ -32,3 +32,10 @@ cs1540-9.cs
 cs1586.cs
 cs1641.cs
 cs1670-2.cs
+
+# Unary operators
+cs0035.cs
+cs0266-11.cs
+cs0266-9.cs
+cs0457-2.cs
+cs0457.cs
index b7accf51d372686eee40915294d8ac61fe26cc49..274ef071be24fe92b56039619ce89be8a7f5f94b 100644 (file)
@@ -1,3 +1,27 @@
+2006-11-30  Marek Safar  <marek.safar@gmail.com>
+
+       Correct unary operators implementation (part I)
+       Also fixes #80026
+
+       * cfold.cs (Error_CompileTimeOverflow): Made internal
+
+       * const.cs (IConstant): Changed to use reference to constant and
+       not constant itself.
+       Updated IConstant implementations.
+
+       * constant.cs (CreateConstant): New factory method.
+       Updated IConstant implementation.
+
+       * convert.cs (ImplicitStandardConversionExists): Uses compiler Equals.
+
+       * ecore.cs: Updated to use CreateConstantReference.
+
+       * enum.cs: Reflects IConstant changes.
+
+       * expression.cs (Unary): Reimplemented +,-,~ to conform C# standard.
+
+       * literal.cs (NullConstant): Change to be independently usable.
+
 2006-11-29  Martin Baulig  <martin@ximian.com>
 
        * class.cs (Constructor.Emit): Correctly handle anonymous methods;
index 9986c418e0fdf923609d4f6b2be772e19d96aab5..f8d1f424a9bf4ae9b95e2b4f40a8336ba7c6c171 100644 (file)
@@ -162,7 +162,7 @@ namespace Mono.CSharp {
                        return;
                }
 
-               static void Error_CompileTimeOverflow (Location loc)
+               internal static void Error_CompileTimeOverflow (Location loc)
                {
                        Report.Error (220, loc, "The operation overflows at compile time in checked mode");
                }
index 7422b492b3f23be40c2771edca882855dc315718..b947e4d68f5485ee6552e1e4abb33d32d71d8459 100644 (file)
@@ -20,7 +20,7 @@ namespace Mono.CSharp {
        {
                void CheckObsoleteness (Location loc);
                bool ResolveValue ();
-               Constant Value { get; }
+               Constant CreateConstantReference (Location loc);
        }
 
        public class Const : FieldMember, IConstant {
@@ -189,10 +189,12 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public Constant Value {
-                       get {
-                               return value;
-                       }
+               public Constant CreateConstantReference (Location loc)
+               {
+                       if (value == null)
+                               return null;
+
+                       return Constant.CreateConstant (value.Type, value.GetValue(), loc);
                }
 
                #endregion
@@ -201,14 +203,14 @@ namespace Mono.CSharp {
        public class ExternalConstant : IConstant
        {
                FieldInfo fi;
-               Constant value;
+               object value;
 
                public ExternalConstant (FieldInfo fi)
                {
                        this.fi = fi;
                }
 
-               private ExternalConstant (FieldInfo fi, Constant value):
+               private ExternalConstant (FieldInfo fi, object value):
                        this (fi)
                {
                        this.value = value;
@@ -229,7 +231,7 @@ namespace Mono.CSharp {
                                return null;
 
                        IConstant ic = new ExternalConstant (fi,
-                               new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null));
+                               ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
 
                        return ic;
                }
@@ -251,20 +253,13 @@ namespace Mono.CSharp {
                        if (value != null)
                                return true;
 
-                       if (fi.DeclaringType.IsEnum) {
-                               value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType));
-                               value = new EnumConstant (value, fi.DeclaringType);
-                               return true;
-                       }
-
-                       value = Expression.Constantify (fi.GetValue (fi), fi.FieldType);
+                       value = fi.GetValue (fi);
                        return true;
                }
 
-               public Constant Value {
-                       get {
-                               return value;
-                       }
+               public Constant CreateConstantReference (Location loc)
+               {
+                       return Constant.CreateConstant (fi.FieldType, value, loc);
                }
 
                #endregion
index 517d778a1db3c90844b23697b6ed7adbef605d5f..8ea18f3c74d842f9d4d26334ac75c89826222d9d 100644 (file)
@@ -188,39 +188,52 @@ namespace Mono.CSharp {
                                        String.Format ("LookupConstantValue: This should never be reached {0} {1}", Type, type));
                        }
 
-                       Constant retval;
-                       if (type == TypeManager.int32_type)
-                               retval = new IntConstant ((int) constant_value, loc);
-                       else if (type == TypeManager.uint32_type)
-                               retval = new UIntConstant ((uint) constant_value, loc);
-                       else if (type == TypeManager.int64_type)
-                               retval = new LongConstant ((long) constant_value, loc);
-                       else if (type == TypeManager.uint64_type)
-                               retval = new ULongConstant ((ulong) constant_value, loc);
-                       else if (type == TypeManager.float_type)
-                               retval = new FloatConstant ((float) constant_value, loc);
-                       else if (type == TypeManager.double_type)
-                               retval = new DoubleConstant ((double) constant_value, loc);
-                       else if (type == TypeManager.string_type)
-                               retval = new StringConstant ((string) constant_value, loc);
-                       else if (type == TypeManager.short_type)
-                               retval = new ShortConstant ((short) constant_value, loc);
-                       else if (type == TypeManager.ushort_type)
-                               retval = new UShortConstant ((ushort) constant_value, loc);
-                       else if (type == TypeManager.sbyte_type)
-                               retval = new SByteConstant ((sbyte) constant_value, loc);
-                       else if (type == TypeManager.byte_type)
-                               retval = new ByteConstant ((byte) constant_value, loc);
-                       else if (type == TypeManager.char_type)
-                               retval = new CharConstant ((char) constant_value, loc);
-                       else if (type == TypeManager.bool_type)
-                               retval = new BoolConstant ((bool) constant_value, loc);
-                       else if (type == TypeManager.decimal_type)
-                               retval = new DecimalConstant ((decimal) constant_value, loc);
-                       else
-                               throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
-                       
-                       return retval;
+                       return CreateConstant (type, constant_value, loc);
+               }
+
+               ///  Returns a constant instance based on Type
+               ///  The returned value is already resolved.
+               public static Constant CreateConstant (Type t, object v, Location loc)
+               {
+                       if (t == TypeManager.int32_type)
+                               return new IntConstant ((int) v, loc);
+                       if (t == TypeManager.string_type)
+                               return new StringConstant ((string) v, loc);
+                       if (t == TypeManager.uint32_type)
+                               return new UIntConstant ((uint) v, loc);
+                       if (t == TypeManager.int64_type)
+                               return new LongConstant ((long) v, loc);
+                       if (t == TypeManager.uint64_type)
+                               return new ULongConstant ((ulong) v, loc);
+                       if (t == TypeManager.float_type)
+                               return new FloatConstant ((float) v, loc);
+                       if (t == TypeManager.double_type)
+                               return new DoubleConstant ((double) v, loc);
+                       if (t == TypeManager.short_type)
+                               return new ShortConstant ((short)v, loc);
+                       if (t == TypeManager.ushort_type)
+                               return new UShortConstant ((ushort)v, loc);
+                       if (t == TypeManager.sbyte_type)
+                               return new SByteConstant ((sbyte)v, loc);
+                       if (t == TypeManager.byte_type)
+                               return new ByteConstant ((byte)v, loc);
+                       if (t == TypeManager.char_type)
+                               return new CharConstant ((char)v, loc);
+                       if (t == TypeManager.bool_type)
+                               return new BoolConstant ((bool) v, loc);
+                       if (t == TypeManager.decimal_type)
+                               return new DecimalConstant ((decimal) v, loc);
+                       if (TypeManager.IsEnumType (t)) {
+                               Type real_type = TypeManager.TypeToCoreType (v.GetType ());
+                               if (real_type == t)
+                                       real_type = System.Enum.GetUnderlyingType (real_type);
+                               return new EnumConstant (CreateConstant (real_type, v, loc), t);
+                       } 
+                       if (v == null && !TypeManager.IsValueType (t))
+                               return new EmptyConstantCast (new NullConstant (loc), t);
+
+                       throw new Exception ("Unknown type for constant (" + t +
+                                       "), details: " + v);
                }
 
                protected static void CheckRange (bool inCheckedContext, ulong value, ulong max)
@@ -381,7 +394,7 @@ namespace Mono.CSharp {
                                Reduce (true, target);
                                base.Error_ValueCannotBeConverted (loc, target, expl);
                        }
-                       catch 
+                       catch
                        {
                                Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
                                        GetValue ().ToString (), TypeManager.CSharpName (target));
@@ -1612,7 +1625,7 @@ namespace Mono.CSharp {
        }
 
        public class FloatConstant : Constant {
-               public readonly float Value;
+               public float Value;
 
                public FloatConstant (float v, Location loc):
                        base (loc)
@@ -1728,7 +1741,7 @@ namespace Mono.CSharp {
        }
 
        public class DoubleConstant : Constant {
-               public readonly double Value;
+               public double Value;
 
                public DoubleConstant (double v, Location loc):
                        base (loc)
index a35cc845bf27230694ce6f9c77874c6050ea1bf6..16e16ac006de1d6b920d34e7d55a428f8721d7fa 100644 (file)
@@ -666,7 +666,7 @@ namespace Mono.CSharp {
 
                        //Console.WriteLine ("Expr is {0}", expr);
                        //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
-                       if (expr_type.Equals (target_type))
+                       if (TypeManager.IsEqual (expr_type, target_type))
                                return true;
 
 
index 6f51d611fb2631a48ff5cbd55d79afb8d9d0cac8..8f5398ecae40462e50a8ee6fdc5687452b9491c3 100644 (file)
@@ -538,64 +538,6 @@ namespace Mono.CSharp {
                        type = null;
                }
 
-               /// <summary>
-               ///   Returns a literalized version of a literal FieldInfo
-               /// </summary>
-               ///
-               /// <remarks>
-               ///   The possible return values are:
-               ///      IntConstant, UIntConstant
-               ///      LongLiteral, ULongConstant
-               ///      FloatConstant, DoubleConstant
-               ///      StringConstant
-               ///
-               ///   The value returned is already resolved.
-               /// </remarks>
-               public static Constant Constantify (object v, Type t)
-               {
-                       if (t == TypeManager.int32_type)
-                               return new IntConstant ((int) v, Location.Null);
-                       else if (t == TypeManager.uint32_type)
-                               return new UIntConstant ((uint) v, Location.Null);
-                       else if (t == TypeManager.int64_type)
-                               return new LongConstant ((long) v, Location.Null);
-                       else if (t == TypeManager.uint64_type)
-                               return new ULongConstant ((ulong) v, Location.Null);
-                       else if (t == TypeManager.float_type)
-                               return new FloatConstant ((float) v, Location.Null);
-                       else if (t == TypeManager.double_type)
-                               return new DoubleConstant ((double) v, Location.Null);
-                       else if (t == TypeManager.string_type)
-                               return new StringConstant ((string) v, Location.Null);
-                       else if (t == TypeManager.short_type)
-                               return new ShortConstant ((short)v, Location.Null);
-                       else if (t == TypeManager.ushort_type)
-                               return new UShortConstant ((ushort)v, Location.Null);
-                       else if (t == TypeManager.sbyte_type)
-                               return new SByteConstant ((sbyte)v, Location.Null);
-                       else if (t == TypeManager.byte_type)
-                               return new ByteConstant ((byte)v, Location.Null);
-                       else if (t == TypeManager.char_type)
-                               return new CharConstant ((char)v, Location.Null);
-                       else if (t == TypeManager.bool_type)
-                               return new BoolConstant ((bool) v, Location.Null);
-                       else if (t == TypeManager.decimal_type)
-                               return new DecimalConstant ((decimal) v, Location.Null);
-                       else if (TypeManager.IsEnumType (t)){
-                               Type real_type = TypeManager.TypeToCoreType (v.GetType ());
-                               if (real_type == t)
-                                       real_type = System.Enum.GetUnderlyingType (real_type);
-
-                               Constant e = Constantify (v, real_type);
-
-                               return new EnumConstant (e, t);
-                       } else if (v == null && !TypeManager.IsValueType (t))
-                               return new NullLiteral (Location.Null);
-                       else
-                               throw new Exception ("Unknown type for constant (" + t +
-                                                    "), details: " + v);
-               }
-
                /// <summary>
                ///   Returns a fully formed expression after a MemberLookup
                /// </summary>
@@ -3195,7 +3137,7 @@ namespace Mono.CSharp {
                                                ic.CheckObsoleteness (loc);
                                }
 
-                               return ic.Value;
+                               return ic.CreateConstantReference (loc);
                        }
                        
                        if (t.IsPointer && !ec.InUnsafe) {
index 6067a8acfa3fa093b1eac3f098efb091b2359ed8..75a9dbd7d5e404500be0829063d4d56711ad8a6b 100644 (file)
@@ -28,7 +28,7 @@ namespace Mono.CSharp {
                readonly Expression ValueExpr;
                readonly EnumMember prev_member;
 
-               Constant value;
+               EnumConstant value;
                bool in_transit;
 
                // TODO: remove or simplify
@@ -149,7 +149,7 @@ namespace Mono.CSharp {
                        in_transit = true;
 
                        try {
-                               value = prev_member.value.Increment ();
+                               value = (EnumConstant)prev_member.value.Increment ();
                        }
                        catch (OverflowException) {
                                Report.Error (543, Location, "The enumerator value `{0}' is too large to fit in its type `{1}'",
@@ -193,10 +193,13 @@ namespace Mono.CSharp {
 
                #region IConstant Members
 
-               public Constant Value {
-                       get {
-                               return value;
-                       }
+               public Constant CreateConstantReference (Location loc)
+               {
+                       if (value == null)
+                               return null;
+
+                       return new EnumConstant (Constant.CreateConstant (value.Child.Type, value.Child.GetValue(), loc),
+                               value.Type);
                }
 
                #endregion
index 48ffb536930ed371971eca545d75e17f4e6a3a99..755690029f9e1abff4e4ffb4add89e877080620f 100644 (file)
@@ -194,154 +194,159 @@ namespace Mono.CSharp {
                        Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
                }
 
-               /// <remarks>
-               ///   The result has been already resolved:
-               ///
-               ///   FIXME: a minus constant -128 sbyte cant be turned into a
-               ///   constant byte.
-               /// </remarks>
-               static Expression TryReduceNegative (Constant expr)
-               {
-                       Expression e = null;
-
-                       if (expr is IntConstant)
-                               e = new IntConstant (-((IntConstant) expr).Value, expr.Location);
-                       else if (expr is UIntConstant){
-                               uint value = ((UIntConstant) expr).Value;
-
-                               if (value < 2147483649)
-                                       return new IntConstant (-(int)value, expr.Location);
-                               else
-                                       e = new LongConstant (-value, expr.Location);
-                       }
-                       else if (expr is LongConstant)
-                               e = new LongConstant (-((LongConstant) expr).Value, expr.Location);
-                       else if (expr is ULongConstant){
-                               ulong value = ((ULongConstant) expr).Value;
-
-                               if (value < 9223372036854775809)
-                                       return new LongConstant(-(long)value, expr.Location);
-                       }
-                       else if (expr is FloatConstant)
-                               e = new FloatConstant (-((FloatConstant) expr).Value, expr.Location);
-                       else if (expr is DoubleConstant)
-                               e = new DoubleConstant (-((DoubleConstant) expr).Value, expr.Location);
-                       else if (expr is DecimalConstant)
-                               e = new DecimalConstant (-((DecimalConstant) expr).Value, expr.Location);
-                       else if (expr is ShortConstant)
-                               e = new IntConstant (-((ShortConstant) expr).Value, expr.Location);
-                       else if (expr is UShortConstant)
-                               e = new IntConstant (-((UShortConstant) expr).Value, expr.Location);
-                       else if (expr is SByteConstant)
-                               e = new IntConstant (-((SByteConstant) expr).Value, expr.Location);
-                       else if (expr is ByteConstant)
-                               e = new IntConstant (-((ByteConstant) expr).Value, expr.Location);
-                       return e;
-               }
-
                // <summary>
                //   This routine will attempt to simplify the unary expression when the
-               //   argument is a constant.  The result is returned in `result' and the
-               //   function returns true or false depending on whether a reduction
-               //   was performed or not
+               //   argument is a constant.
                // </summary>
-               bool Reduce (EmitContext ec, Constant e, out Expression result)
+               Constant TryReduceConstant (EmitContext ec, Constant e)
                {
                        Type expr_type = e.Type;
                        
                        switch (Oper){
-                       case Operator.UnaryPlus:
-                               if (expr_type == TypeManager.bool_type){
-                                       result = null;
-                                       Error23 (expr_type);
-                                       return false;
-                               }
-                               
-                               result = e;
-                               return true;
-                               
-                       case Operator.UnaryNegation:
-                               result = TryReduceNegative (e);
-                               return result != null;
-                               
-                       case Operator.LogicalNot:
-                               if (expr_type != TypeManager.bool_type) {
-                                       result = null;
-                                       Error23 (expr_type);
-                                       return false;
-                               }
-                               
-                               BoolConstant b = (BoolConstant) e;
-                               result = new BoolConstant (!(b.Value), b.Location);
-                               return true;
+                               case Operator.UnaryPlus:
+                                       // Unary numeric promotions
+                                       if (expr_type == TypeManager.byte_type)
+                                               return new IntConstant (((ByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.sbyte_type)
+                                               return new IntConstant (((SByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.short_type)
+                                               return new IntConstant (((ShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.ushort_type)
+                                               return new IntConstant (((UShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.char_type)
+                                               return new IntConstant (((CharConstant)e).Value, e.Location);
+
+                                       // 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 e;
+                                       }
+
+                                       return null;
                                
-                       case Operator.OnesComplement:
-                               if (!((expr_type == TypeManager.int32_type) ||
-                                     (expr_type == TypeManager.uint32_type) ||
-                                     (expr_type == TypeManager.int64_type) ||
-                                     (expr_type == TypeManager.uint64_type) ||
-                                     (expr_type.IsSubclassOf (TypeManager.enum_type)))){
-
-                                       result = null;
-                                       if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
-                                               result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
-                                               result = result.Resolve (ec);
-                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
-                                               result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
-                                               result = result.Resolve (ec);
-                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
-                                               result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
-                                               result = result.Resolve (ec);
-                                       } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
-                                               result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
-                                               result = result.Resolve (ec);
+                               case Operator.UnaryNegation:
+                                       // Unary numeric promotions
+                                       if (expr_type == TypeManager.byte_type)
+                                               return new IntConstant (-((ByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.sbyte_type)
+                                               return new IntConstant (-((SByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.short_type)
+                                               return new IntConstant (-((ShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.ushort_type)
+                                               return new IntConstant (-((UShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.char_type)
+                                               return new IntConstant (-((CharConstant)e).Value, e.Location);
+
+                                       // Predefined operators
+                                       if (expr_type == TypeManager.int32_type) {
+                                               int value = ((IntConstant)e).Value;
+                                               if (value == int.MinValue) {
+                                                       if (ec.ConstantCheckState) {
+                                                               ConstantFold.Error_CompileTimeOverflow (loc);
+                                                               return null;
+                                                       }
+                                                       return e;
+                                               }
+                                               return new IntConstant (-value, e.Location);
+                                       }
+                                       if (expr_type == TypeManager.int64_type) {
+                                               long value = ((LongConstant)e).Value;
+                                               if (value == long.MinValue) {
+                                                       if (ec.ConstantCheckState) {
+                                                               ConstantFold.Error_CompileTimeOverflow (loc);
+                                                               return null;
+                                                       }
+                                                       return e;
+                                               }
+                                               return new LongConstant (-value, e.Location);
                                        }
 
-                                       if (result == null || !(result is Constant)){
-                                               result = null;
-                                               Error23 (expr_type);
-                                               return false;
+                                       if (expr_type == TypeManager.uint32_type) {
+                                               UIntLiteral uil = e as UIntLiteral;
+                                               if (uil != null) {
+                                                       if (uil.Value == 2147483648)
+                                                               return new IntLiteral (int.MinValue, e.Location);
+                                                       return new LongLiteral (-uil.Value, e.Location);
+                                               }
+                                               return new LongConstant (-((UIntConstant)e).Value, e.Location);
                                        }
 
-                                       expr_type = result.Type;
-                                       e = (Constant) result;
-                               }
+                                       if (expr_type == TypeManager.uint64_type) {
+                                               ULongLiteral ull = e as ULongLiteral;
+                                               if (ull != null && ull.Value == 9223372036854775808)
+                                                       return new LongLiteral (long.MinValue, e.Location);
+                                               return null;
+                                       }
 
-                               if (e is EnumConstant){
-                                       EnumConstant enum_constant = (EnumConstant) e;
-                                       Expression reduced;
-                                       
-                                       if (Reduce (ec, enum_constant.Child, out reduced)){
-                                               result = new EnumConstant ((Constant) reduced, enum_constant.Type);
-                                               return true;
-                                       } else {
-                                               result = null;
-                                               return false;
+                                       if (expr_type == TypeManager.float_type) {
+                                               FloatLiteral fl = e as FloatLiteral;
+                                               // For better error reporting
+                                               if (fl != null) {
+                                                       fl.Value = -fl.Value;
+                                                       return fl;
+                                               }
+                                               return new FloatConstant (-((FloatConstant)e).Value, e.Location);
                                        }
-                               }
+                                       if (expr_type == TypeManager.double_type) {
+                                               DoubleLiteral dl = e as DoubleLiteral;
+                                               // For better error reporting
+                                               if (dl != null) {
+                                                       dl.Value = -dl.Value;
+                                                       return dl;
+                                               }
 
-                               if (expr_type == TypeManager.int32_type){
-                                       result = new IntConstant (~ ((IntConstant) e).Value, e.Location);
-                               } else if (expr_type == TypeManager.uint32_type){
-                                       result = new UIntConstant (~ ((UIntConstant) e).Value, e.Location);
-                               } else if (expr_type == TypeManager.int64_type){
-                                       result = new LongConstant (~ ((LongConstant) e).Value, e.Location);
-                               } else if (expr_type == TypeManager.uint64_type){
-                                       result = new ULongConstant (~ ((ULongConstant) e).Value, e.Location);
-                               } else {
-                                       result = null;
-                                       Error23 (expr_type);
-                                       return false;
-                               }
-                               return true;
+                                               return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
+                                       }
+                                       if (expr_type == TypeManager.decimal_type)
+                                               return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
 
-                       case Operator.AddressOf:
-                               result = this;
-                               return false;
+                                       return null;
+                               
+                               case Operator.LogicalNot:
+                                       if (expr_type != TypeManager.bool_type)
+                                               return null;
+                                       
+                                       BoolConstant b = (BoolConstant) e;
+                                       return new BoolConstant (!(b.Value), b.Location);
+                               
+                               case Operator.OnesComplement:
+                                       // Unary numeric promotions
+                                       if (expr_type == TypeManager.byte_type)
+                                               return new IntConstant (~((ByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.sbyte_type)
+                                               return new IntConstant (~((SByteConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.short_type)
+                                               return new IntConstant (~((ShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.ushort_type)
+                                               return new IntConstant (~((UShortConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.char_type)
+                                               return new IntConstant (~((CharConstant)e).Value, e.Location);
+
+                                       // Predefined operators
+                                       if (expr_type == TypeManager.int32_type)
+                                               return new IntConstant (~((IntConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.uint32_type)
+                                               return new UIntConstant (~((UIntConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.int64_type)
+                                               return new LongConstant (~((LongConstant)e).Value, e.Location);
+                                       if (expr_type == TypeManager.uint64_type)
+                                               return new ULongConstant (~((UIntConstant)e).Value, e.Location);
+                                       if (e is EnumConstant) {
+                                               e = TryReduceConstant (ec, ((EnumConstant)e).Child);
+                                               if (e != null)
+                                                       e = new EnumConstant (e, expr_type);
+                                               return e;
+                                       }
+                                       return null;
 
-                       case Operator.Indirection:
-                               result = this;
-                               return false;
+                               case Operator.AddressOf:
+                                       return e;
+
+                               case Operator.Indirection:
+                                       return e;
                        }
                        throw new Exception ("Can not constant fold: " + Oper.ToString());
                }
@@ -353,24 +358,21 @@ namespace Mono.CSharp {
                        //
 
                        // Attempt to use a constant folding operation.
-                       if (Expr is Constant){
-                               Expression result;
-                               
-                               if (Reduce (ec, (Constant) Expr, out result))
-                                       return result;
+                       Constant cexpr = Expr as Constant;
+                       if (cexpr != null) {
+                               cexpr = TryReduceConstant (ec, cexpr);
+                               if (cexpr != null) {
+                                       return cexpr;
+                               }
                        }
 
                        //
                        // Step 2: Perform Operator Overload location
                        //
                        Type expr_type = Expr.Type;
-                       Expression mg;
-                       string op_name;
-                       
-                       op_name = oper_names [(int) Oper];
+                       string op_name = oper_names [(int) Oper];
 
-                       mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
-                       
+                       Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
                        if (mg != null) {
                                Expression e = StaticCallExpr.MakeSimpleCall (
                                        ec, (MethodGroupExpr) mg, Expr, loc);
@@ -383,12 +385,6 @@ namespace Mono.CSharp {
                                return e;
                        }
 
-                       // Only perform numeric promotions on:
-                       // +, - 
-
-                       if (expr_type == null)
-                               return null;
-                       
                        switch (Oper){
                        case Operator.LogicalNot:
                                if (expr_type != TypeManager.bool_type) {
@@ -403,34 +399,31 @@ namespace Mono.CSharp {
                                return this;
 
                        case Operator.OnesComplement:
-                               if (!((expr_type == TypeManager.int32_type) ||
-                                     (expr_type == TypeManager.uint32_type) ||
-                                     (expr_type == TypeManager.int64_type) ||
-                                     (expr_type == TypeManager.uint64_type) ||
-                                     (expr_type.IsSubclassOf (TypeManager.enum_type)))){
-                                       Expression e;
-
-                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
-                                       if (e != null)
-                                               goto ok;
-                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
-                                       if (e != null)
-                                               goto ok;
-                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
-                                       if (e != null)
-                                               goto ok;
-                                       e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
-                                       if (e != null)
-                                               goto ok;
-                                       Error23 (expr_type);
-                                       return null;
-                               ok:
-                                       Expr = e;
-                                       expr_type = e.Type;
+                               // 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 new EmptyCast (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 = 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) {
@@ -499,90 +492,75 @@ namespace Mono.CSharp {
                                return new Indirection (Expr, loc);
                        
                        case Operator.UnaryPlus:
-                               //
-                               // A plus in front of something is just a no-op, so return the child.
-                               //
-                               return 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) 
+                               {
+                                       return new EmptyCast (Expr, TypeManager.int32_type);
+                               }
 
-                       case Operator.UnaryNegation:
-                               //
-                               // Deals with -literals
-                               // int     operator- (int x)
-                               // long    operator- (long x)
-                               // float   operator- (float f)
-                               // double  operator- (double d)
-                               // decimal operator- (decimal d)
-                               //
-                               Expression expr = null;
+                               // 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
                                //
-                               if (Expr is Unary){
-                                       Unary unary = (Unary) Expr;
-                                       
-                                       if (unary.Oper == Operator.UnaryNegation)
-                                               return unary.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 new EmptyCast (this, type);
                                }
 
                                //
-                               // perform numeric promotions to int,
-                               // long, double.
-                               //
-                               //
-                               // The following is inneficient, because we call
-                               // ImplicitConversion too many times.
-                               //
-                               // It is also not clear if we should convert to Float
-                               // or Double initially.
+                               // Predefined operators
                                //
-                               if (expr_type == TypeManager.uint32_type){
-                                       //
-                                       // FIXME: handle exception to this rule that
-                                       // permits the int value -2147483648 (-2^31) to
-                                       // bt wrote as a decimal interger literal
-                                       //
+                               if (expr_type == TypeManager.uint32_type) {
                                        type = TypeManager.int64_type;
-                                       Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
+                                       Expr = Convert.ImplicitNumericConversion (Expr, type);
                                        return this;
                                }
 
-                               if (expr_type == TypeManager.uint64_type){
-                                       //
-                                       // FIXME: Handle exception of `long value'
-                                       // -92233720368547758087 (-2^63) to be wrote as
-                                       // decimal integer literal.
-                                       //
-                                       Error23 (expr_type);
-                                       return null;
-                               }
-
-                               if (expr_type == TypeManager.float_type){
+                               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;
                                }
-                               
-                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
-                               if (expr != null){
-                                       Expr = expr;
-                                       type = expr.Type;
-                                       return this;
-                               } 
 
-                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
-                               if (expr != null){
-                                       Expr = expr;
-                                       type = expr.Type;
-                                       return this;
-                               }
+                               //
+                               // User conversion
 
-                               expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
-                               if (expr != null){
-                                       Expr = expr;
-                                       type = expr.Type;
+                               type = TypeManager.int32_type;
+                               Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
+                               if (Expr != null)
                                        return this;
-                               }
-                               
+
                                Error23 (expr_type);
                                return null;
                        }
index 8f4cb6e60d3ba67375602ff23ca5dc1265d3f5bf..eb06c1fffa353f7cb86e1f748d210ddb5cbaf807 100644 (file)
@@ -45,12 +45,13 @@ namespace Mono.CSharp {
        }
 
 
-       public abstract class NullConstant : Constant
+       public class NullConstant : Constant
        {
                public NullConstant (Location loc):
                        base (loc)
                {
                        eclass = ExprClass.Value;
+                       type = TypeManager.null_type;
                }
                
                override public string AsString ()
@@ -145,7 +146,7 @@ namespace Mono.CSharp {
                {
                        if (TypeManager.IsGenericParameter (t)) {
                                Report.Error(403, loc,
-                                       "Cannot convert null to the type parameter `{0}' becaues it could be a value " +
+                                       "Cannot convert null to the type parameter `{0}' because it could be a value " +
                                        "type. Consider using `default ({0})' instead", t.Name);
                        } else {
                                Report.Error(37, loc, "Cannot convert null to `{0}' because it is a value type",
index 1695165f02fcdd2d5a841f954c3ec559c31e997c..c159f76e6c51dfb8b2f9b43dea4e4b10817d5d7d 100644 (file)
@@ -10,4 +10,3 @@ test-67.cs IGNORE     # Windows-only test
 test-476.cs
 
 test-xml-027.cs
-