X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=b947e4d68f5485ee6552e1e4abb33d32d71d8459;hb=43b6678d45b2cf3705971998e1f04f67ef4d7667;hp=4a6851a88465ccf4b0243e08e5bc947da3e8d365;hpb=eb5ed7e613c07333e7ed381609268f311b428a0e;p=mono.git
diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs
old mode 100755
new mode 100644
index 4a6851a8846..b947e4d68f5
--- a/mcs/mcs/const.cs
+++ b/mcs/mcs/const.cs
@@ -3,20 +3,12 @@
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
+// Marek Safar (marek.safar@seznam.cz)
//
// (C) 2001 Ximian, Inc.
//
//
-//
-// This is needed because the following situation arises:
-//
-// The FieldBuilder is declared with the real type for an enumeration
-//
-// When we attempt to set the value for the constant, the FieldBuilder.SetConstant
-// function aborts because it requires its argument to be of the same type
-//
-
namespace Mono.CSharp {
using System;
@@ -24,14 +16,17 @@ namespace Mono.CSharp {
using System.Reflection.Emit;
using System.Collections;
- public class Const : FieldMember {
- public Expression Expr;
- EmitContext const_ec;
-
- bool resolved = false;
- object ConstantValue = null;
+ public interface IConstant
+ {
+ void CheckObsoleteness (Location loc);
+ bool ResolveValue ();
+ Constant CreateConstantReference (Location loc);
+ }
- bool in_transit = false;
+ public class Const : FieldMember, IConstant {
+ Constant value;
+ bool in_transit;
+ bool define_called;
public const int AllowedModifiers =
Modifiers.NEW |
@@ -40,267 +35,234 @@ namespace Mono.CSharp {
Modifiers.INTERNAL |
Modifiers.PRIVATE;
- public Const (TypeContainer parent, Expression constant_type, string name,
+ public Const (DeclSpace parent, Expression constant_type, string name,
Expression expr, int mod_flags, Attributes attrs, Location loc)
: base (parent, constant_type, mod_flags, AllowedModifiers,
- new MemberName (name), null, attrs, loc)
+ new MemberName (name, loc), attrs)
{
- Expr = expr;
+ initializer = expr;
ModFlags |= Modifiers.STATIC;
}
- public FieldAttributes FieldAttr {
- get {
- return FieldAttributes.Literal | FieldAttributes.Static |
- Modifiers.FieldAttr (ModFlags) ;
- }
- }
-
-#if DEBUG
- void dump_tree (Type t)
+ protected override bool CheckBase ()
{
- Console.WriteLine ("Dumping hierarchy");
- while (t != null){
- Console.WriteLine (" " + t.FullName + " " +
- (t.GetType ().IsEnum ? "yes" : "no"));
- t = t.BaseType;
- }
+ // Constant.Define can be called when the parent type hasn't yet been populated
+ // and it's base types need not have been populated. So, we defer this check
+ // to the second time Define () is called on this member.
+ if (Parent.PartialContainer.BaseCache == null)
+ return true;
+ return base.CheckBase ();
}
-#endif
///
/// Defines the constant in the @parent
///
public override bool Define ()
{
+ // Because constant define can be called from other class
+ if (define_called) {
+ CheckBase ();
+ return FieldBuilder != null;
+ }
+
+ define_called = true;
+
if (!base.Define ())
return false;
- const_ec = new EmitContext (Parent, Location, null, MemberType, ModFlags);
-
Type ttype = MemberType;
+ if (!IsConstantTypeValid (ttype)) {
+ Error_InvalidConstantType (ttype, Location);
+ return false;
+ }
+
while (ttype.IsArray)
ttype = TypeManager.GetElementType (ttype);
-
- if (!TypeManager.IsBuiltinType (ttype) && (!ttype.IsSubclassOf (TypeManager.enum_type)) && !(Expr is NullLiteral)) {
- Report.Error (
- -3, Location,
- "Constant type is not valid (only system types are allowed)");
- return false;
+
+ FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
+ // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
+ if (ttype == TypeManager.decimal_type) {
+ field_attr |= FieldAttributes.InitOnly;
+ Parent.PartialContainer.RegisterFieldForInitialization (this);
+ } else {
+ field_attr |= FieldAttributes.Literal;
}
- FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, FieldAttr);
+ FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
TypeManager.RegisterConstant (FieldBuilder, this);
return true;
}
- //
- // Changes the type of the constant expression `expr' to the Type `type'
- // Returns null on failure.
- //
- public static Constant ChangeType (Location loc, Constant expr, Type type)
+ public static bool IsConstantTypeValid (Type t)
{
- if (type == TypeManager.object_type)
- return expr;
+ if (TypeManager.IsBuiltinOrEnum (t))
+ return true;
- bool fail;
+ if (t.IsPointer || t.IsValueType)
+ return false;
+
+ if (TypeManager.IsGenericParameter (t))
+ return false;
- // from the null type to any reference-type.
- if (expr is NullLiteral && !type.IsValueType && !TypeManager.IsEnumType (type))
- return NullLiteral.Null;
+ return true;
+ }
- if (!Convert.ImplicitStandardConversionExists (expr, type)){
- Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
- return null;
+ ///
+ /// Emits the field value by evaluating the expression
+ ///
+ public override void Emit ()
+ {
+ if (!ResolveValue ())
+ return;
+
+ if (value.Type == TypeManager.decimal_type) {
+ Decimal d = ((DecimalConstant)value).Value;
+ int[] bits = Decimal.GetBits (d);
+ object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
+ CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
+ FieldBuilder.SetCustomAttribute (cab);
}
-
- object constant_value = TypeManager.ChangeType (expr.GetValue (), type, out fail);
- if (fail){
- Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
-
- //
- // We should always catch the error before this is ever
- // reached, by calling Convert.ImplicitStandardConversionExists
- //
- throw new Exception (
- String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type));
+ else{
+ FieldBuilder.SetConstant (value.GetTypedValue ());
}
- Constant retval;
- if (type == TypeManager.int32_type)
- retval = new IntConstant ((int) constant_value);
- else if (type == TypeManager.uint32_type)
- retval = new UIntConstant ((uint) constant_value);
- else if (type == TypeManager.int64_type)
- retval = new LongConstant ((long) constant_value);
- else if (type == TypeManager.uint64_type)
- retval = new ULongConstant ((ulong) constant_value);
- else if (type == TypeManager.float_type)
- retval = new FloatConstant ((float) constant_value);
- else if (type == TypeManager.double_type)
- retval = new DoubleConstant ((double) constant_value);
- else if (type == TypeManager.string_type)
- retval = new StringConstant ((string) constant_value);
- else if (type == TypeManager.short_type)
- retval = new ShortConstant ((short) constant_value);
- else if (type == TypeManager.ushort_type)
- retval = new UShortConstant ((ushort) constant_value);
- else if (type == TypeManager.sbyte_type)
- retval = new SByteConstant ((sbyte) constant_value);
- else if (type == TypeManager.byte_type)
- retval = new ByteConstant ((byte) constant_value);
- else if (type == TypeManager.char_type)
- retval = new CharConstant ((char) constant_value);
- else if (type == TypeManager.bool_type)
- retval = new BoolConstant ((bool) constant_value);
- else
- throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
-
- return retval;
+ base.Emit ();
}
- static void ReportConstantError (Location loc, string opt_name)
+ public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
{
- if (opt_name != null)
- Report.Error (133, loc, String.Format ("The expression being assigned to `{0}' must be constant"));
- else
- Report.Error (150, loc, "A constant value is expected");
+ Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
}
-
- public static Constant ConvertExpressionToConstant (Expression expr, Location loc, bool show_errors, string opt_name)
+
+ public static void Error_CyclicDeclaration (MemberCore mc)
{
- Constant ce = expr as Constant;
- if (ce == null){
- UnCheckedExpr un_expr = expr as UnCheckedExpr;
- CheckedExpr ch_expr = expr as CheckedExpr;
- EmptyCast ec_expr = expr as EmptyCast;
-
- if ((un_expr != null) && (un_expr.Expr is Constant))
- expr = un_expr.Expr;
- else if ((ch_expr != null) && (ch_expr.Expr is Constant))
- expr = ch_expr.Expr;
- else if ((ec_expr != null) && (ec_expr.Child is Constant))
- expr = ec_expr.Child;
- else if (expr is ArrayCreation){
- if (show_errors)
- Report.Error (133, loc, "Arrays can not be constant");
- } else {
- if (show_errors)
- ReportConstantError (loc, opt_name);
- return null;
- }
-
- ce = expr as Constant;
- if (ce == null){
- if (show_errors)
- ReportConstantError (loc, opt_name);
- }
- }
- return ce;
+ Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
+ mc.GetSignatureForError ());
}
-
- ///
- /// Looks up the value of a constant field. Defines it if it hasn't
- /// already been. Similar to LookupEnumValue in spirit.
- ///
- public bool LookupConstantValue (out object value)
+
+ public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
+ {
+ Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
+ name);
+ }
+
+ public static void Error_InvalidConstantType (Type t, Location loc)
+ {
+ Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
+ }
+
+ #region IConstant Members
+
+ public bool ResolveValue ()
{
- if (resolved) {
- value = ConstantValue;
+ if (value != null)
return true;
- }
+ SetMemberIsUsed ();
if (in_transit) {
- Report.Error (110, Location,
- "The evaluation of the constant value for `" +
- Name + "' involves a circular definition.");
- value = null;
+ Error_CyclicDeclaration (this);
+ // Suppress cyclic errors
+ value = New.Constantify (MemberType);
return false;
}
in_transit = true;
- int errors = Report.Errors;
+ // TODO: IResolveContext here
+ EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags);
+ value = initializer.ResolveAsConstant (ec, this);
+ in_transit = false;
- //
- // We might have cleared Expr ourselves in a recursive definition
- //
- if (Expr == null){
- value = null;
+ if (value == null)
return false;
- }
-
- Expr = Expr.Resolve (const_ec);
- in_transit = false;
+ value = value.ImplicitConversionRequired (MemberType, Location);
+ if (value == null)
+ return false;
- if (Expr == null) {
- if (errors == Report.Errors)
- Report.Error (150, Location, "A constant value is expected");
- value = null;
+ if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) {
+ Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
return false;
}
- Expression real_expr = Expr;
+ return true;
+ }
- Constant ce = ConvertExpressionToConstant (Expr, Location, errors == Report.Errors, null);
- if (ce == null){
- value = null;
- return false;
- }
-
- if (MemberType != real_expr.Type) {
- ce = ChangeType (Location, ce, MemberType);
- if (ce == null){
- value = null;
- return false;
- }
- Expr = ce;
- }
- ConstantValue = ce.GetValue ();
-
- if (MemberType.IsEnum){
- //
- // This sadly does not work for our user-defined enumerations types ;-(
- //
- try {
- ConstantValue = System.Enum.ToObject (
- MemberType, ConstantValue);
- } catch (ArgumentException){
- Report.Error (
- -16, Location,
- ".NET SDK 1.0 does not permit to create the constant "+
- " field from a user-defined enumeration");
- }
- }
+ public Constant CreateConstantReference (Location loc)
+ {
+ if (value == null)
+ return null;
- FieldBuilder.SetConstant (ConstantValue);
+ return Constant.CreateConstant (value.Type, value.GetValue(), loc);
+ }
- if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
- throw new Exception ("Cannot register const value");
+ #endregion
+ }
- value = ConstantValue;
- resolved = true;
- return true;
+ public class ExternalConstant : IConstant
+ {
+ FieldInfo fi;
+ object value;
+
+ public ExternalConstant (FieldInfo fi)
+ {
+ this.fi = fi;
}
-
-
- ///
- /// Emits the field value by evaluating the expression
- ///
- public override void Emit ()
+
+ private ExternalConstant (FieldInfo fi, object value):
+ this (fi)
+ {
+ this.value = value;
+ }
+
+ //
+ // Decimal constants cannot be encoded in the constant blob, and thus are marked
+ // as IsInitOnly ('readonly' in C# parlance). We get its value from the
+ // DecimalConstantAttribute metadata.
+ //
+ public static IConstant CreateDecimal (FieldInfo fi)
{
- object value;
- LookupConstantValue (out value);
+ if (fi is FieldBuilder)
+ return null;
+
+ object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
+ if (attrs.Length != 1)
+ return null;
- if (OptAttributes != null) {
- OptAttributes.Emit (const_ec, this);
+ IConstant ic = new ExternalConstant (fi,
+ ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
+
+ return ic;
+ }
+
+ #region IConstant Members
+
+ public void CheckObsoleteness (Location loc)
+ {
+ ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
+ if (oa == null) {
+ return;
}
- base.Emit ();
+ AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
}
- }
-}
+ public bool ResolveValue ()
+ {
+ if (value != null)
+ return true;
+
+ value = fi.GetValue (fi);
+ return true;
+ }
+ public Constant CreateConstantReference (Location loc)
+ {
+ return Constant.CreateConstant (fi.FieldType, value, loc);
+ }
+
+ #endregion
+ }
+
+}