// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2001 Ximian, Inc.
-//
+// Copyright 2001-2003 Ximian, Inc.
+// Copyright 2003-2008 Novell, Inc.
//
namespace Mono.CSharp {
{
void CheckObsoleteness (Location loc);
bool ResolveValue ();
- Constant Value { get; }
+ Constant CreateConstantReference (Location loc);
}
- public class Const : FieldMember, IConstant {
- Constant value;
+ public class Const : FieldBase, IConstant {
+ protected Constant value;
bool in_transit;
+ bool resolved;
+ bool define_called;
public const int AllowedModifiers =
Modifiers.NEW |
Modifiers.INTERNAL |
Modifiers.PRIVATE;
- public Const (TypeContainer parent, Expression constant_type, string name,
+ public Const (DeclSpace parent, FullNamedExpression type, string name,
Expression expr, int mod_flags, Attributes attrs, Location loc)
- : base (parent, constant_type, mod_flags, AllowedModifiers,
+ : base (parent, type, mod_flags, AllowedModifiers,
new MemberName (name, loc), attrs)
{
initializer = expr;
// 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.BaseCache == null)
+ if (Parent.PartialContainer.BaseCache == null)
return true;
return base.CheckBase ();
}
/// </summary>
public override bool Define ()
{
- // Make Define () idempotent, but ensure that the error check happens.
- if (FieldBuilder != null)
- return base.CheckBase ();
+ // Because constant define can be called from other class
+ if (define_called) {
+ CheckBase ();
+ return FieldBuilder != null;
+ }
+
+ define_called = true;
if (!base.Define ())
return false;
Type ttype = MemberType;
- while (ttype.IsArray)
- ttype = TypeManager.GetElementType (ttype);
+ if (!IsConstantTypeValid (ttype)) {
+ Error_InvalidConstantType (ttype, Location);
+ }
+
+ // If the constant is private then we don't need any field the
+ // value is already inlined and cannot be referenced
+ //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
+ // return true;
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.RegisterFieldForInitialization (this);
- }
- else {
+ } else {
field_attr |= FieldAttributes.Literal;
}
FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
-
TypeManager.RegisterConstant (FieldBuilder, this);
+ Parent.MemberCache.AddMember (FieldBuilder, this);
+
+ if ((field_attr & FieldAttributes.InitOnly) != 0)
+ Parent.PartialContainer.RegisterFieldForInitialization (this,
+ new FieldInitializer (FieldBuilder, initializer, this));
+
+ return true;
+ }
+
+ public static bool IsConstantTypeValid (Type t)
+ {
+ if (TypeManager.IsBuiltinOrEnum (t))
+ return true;
+
+ if (t.IsPointer || t.IsValueType)
+ return false;
+
+ if (TypeManager.IsGenericParameter (t))
+ return false;
return true;
}
-
+
/// <summary>
/// Emits the field value by evaluating the expression
/// </summary>
if (!ResolveValue ())
return;
+ if (FieldBuilder == null)
+ 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);
- }
- else{
+ EmitDecimalConstant ();
+ } else{
FieldBuilder.SetConstant (value.GetTypedValue ());
}
base.Emit ();
}
+ void EmitDecimalConstant ()
+ {
+ ConstructorInfo ctor = TypeManager.decimal_constant_attribute_ctor;
+ if (ctor == null) {
+ if (TypeManager.decimal_constant_attribute_type == null) {
+ TypeManager.decimal_constant_attribute_type = TypeManager.CoreLookupType (
+ "System.Runtime.CompilerServices", "DecimalConstantAttribute", Kind.Class, true);
+
+ if (TypeManager.decimal_constant_attribute_type == null)
+ return;
+ }
+
+ ctor = TypeManager.GetPredefinedConstructor (TypeManager.decimal_constant_attribute_type, Location,
+ TypeManager.byte_type, TypeManager.byte_type,
+ TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type);
+
+ if (ctor == null)
+ return;
+
+ TypeManager.decimal_constant_attribute_ctor = ctor;
+ }
+
+ 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 (ctor, args);
+ FieldBuilder.SetCustomAttribute (cab);
+ }
+
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);
mc.GetSignatureForError ());
}
+ public static void Error_ConstantCanBeInitializedWithNullOnly (Type type, Location loc, string name)
+ {
+ Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
+ name, TypeManager.CSharpName (type));
+ }
+
+ 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 (value != null)
- return true;
+ if (resolved)
+ return value != null;
SetMemberIsUsed ();
if (in_transit) {
Error_CyclicDeclaration (this);
// Suppress cyclic errors
value = New.Constantify (MemberType);
+ resolved = true;
return false;
}
in_transit = true;
// TODO: IResolveContext here
- EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags);
- value = initializer.ResolveAsConstant (ec, this);
+ EmitContext ec = new EmitContext (
+ this, Parent, Location, null, MemberType, ModFlags);
+ ec.InEnumContext = this is EnumMember;
+ ec.IsAnonymousMethodAllowed = false;
+ value = DoResolveValue (ec);
in_transit = false;
+ resolved = true;
+ return value != null;
+ }
+ protected virtual Constant DoResolveValue (EmitContext ec)
+ {
+ Constant value = initializer.ResolveAsConstant (ec, this);
if (value == null)
- return false;
-
- value = value.ToType (MemberType, Location);
- if (value == null)
- return false;
+ return null;
- if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) {
- Report.Error (134, Location, "`{0}': A const of reference other than string can only be initialized with null",
- GetSignatureForError ());
- return false;
+ Constant c = value.ConvertImplicitly (MemberType);
+ if (c == null) {
+ if (TypeManager.IsReferenceType (MemberType))
+ Error_ConstantCanBeInitializedWithNullOnly (MemberType, Location, GetSignatureForError ());
+ else
+ value.Error_ValueCannotBeConverted (ec, Location, MemberType, false);
}
- return true;
+ return c;
}
- public Constant Value {
- get {
- return value;
- }
+ public virtual Constant CreateConstantReference (Location loc)
+ {
+ if (value == null)
+ return null;
+
+ return Constant.CreateConstant (value.Type, value.GetValue(), loc);
}
#endregion
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;
{
if (fi is FieldBuilder)
return null;
-
+
+ if (TypeManager.decimal_constant_attribute_type == null)
+ return null;
+
object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
if (attrs.Length != 1)
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;
}
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 (TypeManager.TypeToCoreType (fi.FieldType), value, loc);
}
#endregion