X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=b947e4d68f5485ee6552e1e4abb33d32d71d8459;hb=43b6678d45b2cf3705971998e1f04f67ef4d7667;hp=1c15f85ecaa87a95376b2a3753923b132a7a94c5;hpb=812e471a9fa329c17bb3bb52a977c72e6a447366;p=mono.git
diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs
index 1c15f85ecaa..b947e4d68f5 100644
--- a/mcs/mcs/const.cs
+++ b/mcs/mcs/const.cs
@@ -9,15 +9,6 @@
//
//
-//
-// 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;
@@ -25,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 |
@@ -41,54 +35,56 @@ 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;
}
-#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;
- 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)");
+ if (!IsConstantTypeValid (ttype)) {
+ Error_InvalidConstantType (ttype, Location);
return false;
}
+ while (ttype.IsArray)
+ ttype = TypeManager.GetElementType (ttype);
+
FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
- // I don't know why but they emit decimal constant as InitOnly
+ // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
if (ttype == TypeManager.decimal_type) {
field_attr |= FieldAttributes.InitOnly;
- }
- else {
+ Parent.PartialContainer.RegisterFieldForInitialization (this);
+ } else {
field_attr |= FieldAttributes.Literal;
}
@@ -99,207 +95,174 @@ namespace Mono.CSharp {
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.Type == TypeManager.null_type && !type.IsValueType && !TypeManager.IsEnumType (type))
- return NullLiteral.Null;
+ return true;
+ }
- if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, 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;
- // Special-case: The 0 literal can be converted to an enum value,
- // and ImplicitStandardConversionExists will return true in that case.
- if (expr.Type == TypeManager.int32_type && TypeManager.IsEnumType (type)){
- if (expr is IntLiteral && ((IntLiteral) expr).Value == 0)
- return new EnumConstant (expr, type);
+ 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 if (type == TypeManager.decimal_type)
- retval = new DecimalConstant ((decimal) constant_value);
- else
- throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
-
- return retval;
+ base.Emit ();
}
-
- ///
- /// 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_ExpressionMustBeConstant (Location loc, string e_name)
+ {
+ Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
+ }
+
+ public static void Error_CyclicDeclaration (MemberCore mc)
+ {
+ Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
+ mc.GetSignatureForError ());
+ }
+
+ 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;
-
- 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){
- Report.Error (133, Location, "Arrays can not be constant");
- } else {
- if (errors == Report.Errors)
- Report.Error (150, Location, "A constant value is expected");
- value = null;
- return false;
- }
-
- ce = Expr as Constant;
- }
+ return true;
+ }
- 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;
- if (ce is DecimalConstant) {
- Decimal d = ((DecimalConstant)ce).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);
- }
- else{
- 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)
{
- object value;
- LookupConstantValue (out value);
+ this.value = value;
+ }
- if (OptAttributes != null) {
- OptAttributes.Emit (const_ec, this);
+ //
+ // 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)
+ {
+ if (fi is FieldBuilder)
+ return null;
+
+ object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
+ if (attrs.Length != 1)
+ return null;
+
+ 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
+ }
+
+}