2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001 Ximian, Inc.
12 namespace Mono
.CSharp
{
15 using System
.Reflection
;
16 using System
.Reflection
.Emit
;
17 using System
.Collections
;
19 public interface IConstant
21 void CheckObsoleteness (Location loc
);
23 Constant Value { get; }
26 public class Const
: FieldMember
, IConstant
{
30 public const int AllowedModifiers
=
37 public Const (DeclSpace parent
, Expression constant_type
, string name
,
38 Expression expr
, int mod_flags
, Attributes attrs
, Location loc
)
39 : base (parent
, constant_type
, mod_flags
, AllowedModifiers
,
40 new MemberName (name
, loc
), attrs
)
43 ModFlags
|= Modifiers
.STATIC
;
46 protected override bool CheckBase ()
48 // Constant.Define can be called when the parent type hasn't yet been populated
49 // and it's base types need not have been populated. So, we defer this check
50 // to the second time Define () is called on this member.
51 if (ParentContainer
.BaseCache
== null)
53 return base.CheckBase ();
57 /// Defines the constant in the @parent
59 public override bool Define ()
61 // Make Define () idempotent, but ensure that the error check happens.
62 if (FieldBuilder
!= null)
63 return base.CheckBase ();
68 Type ttype
= MemberType
;
70 ttype
= TypeManager
.GetElementType (ttype
);
72 FieldAttributes field_attr
= FieldAttributes
.Static
| Modifiers
.FieldAttr (ModFlags
);
73 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
74 if (ttype
== TypeManager
.decimal_type
) {
75 field_attr
|= FieldAttributes
.InitOnly
;
76 ParentContainer
.RegisterFieldForInitialization (this);
79 field_attr
|= FieldAttributes
.Literal
;
82 FieldBuilder
= Parent
.TypeBuilder
.DefineField (Name
, MemberType
, field_attr
);
84 TypeManager
.RegisterConstant (FieldBuilder
, this);
90 /// Emits the field value by evaluating the expression
92 public override void Emit ()
97 if (value.Type
== TypeManager
.decimal_type
) {
98 Decimal d
= ((DecimalConstant
)value).Value
;
99 int[] bits
= Decimal
.GetBits (d
);
100 object[] args
= new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] }
;
101 CustomAttributeBuilder cab
= new CustomAttributeBuilder (TypeManager
.decimal_constant_attribute_ctor
, args
);
102 FieldBuilder
.SetCustomAttribute (cab
);
105 FieldBuilder
.SetConstant (value.GetTypedValue ());
111 public static void Error_ExpressionMustBeConstant (Type constantType
, Location loc
, string e_name
)
113 if (constantType
!= null && TypeManager
.IsValueType (constantType
) &&
114 !TypeManager
.IsBuiltinOrEnum (constantType
)) {
115 Report
.Error (283, loc
, "The type `{0}' cannot be declared const", TypeManager
.CSharpName (constantType
));
118 Report
.Error (133, loc
, "The expression being assigned to `{0}' must be constant", e_name
);
121 public static void Error_CyclicDeclaration (MemberCore mc
)
123 Report
.Error (110, mc
.Location
, "The evaluation of the constant value for `{0}' involves a circular definition",
124 mc
.GetSignatureForError ());
127 public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc
, string name
)
129 Report
.Error (134, loc
, "`{0}': the constant of reference type other than string can only be initialized with null",
133 #region IConstant Members
135 public bool ResolveValue ()
142 Error_CyclicDeclaration (this);
143 // Suppress cyclic errors
144 value = New
.Constantify (MemberType
);
149 // TODO: IResolveContext here
150 EmitContext ec
= new EmitContext (this, Parent
, Location
, null, MemberType
, ModFlags
);
151 value = initializer
.ResolveAsConstant (ec
, this);
157 value = value.ToType (MemberType
, Location
);
161 if (!MemberType
.IsValueType
&& MemberType
!= TypeManager
.string_type
&& !value.IsDefaultValue
) {
162 Error_ConstantCanBeInitializedWithNullOnly (Location
, GetSignatureForError ());
169 public Constant Value
{
178 public class ExternalConstant
: IConstant
183 public ExternalConstant (FieldInfo fi
)
188 private ExternalConstant (FieldInfo fi
, Constant
value):
195 // Decimal constants cannot be encoded in the constant blob, and thus are marked
196 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
197 // DecimalConstantAttribute metadata.
199 public static IConstant
CreateDecimal (FieldInfo fi
)
201 if (fi
is FieldBuilder
)
204 object[] attrs
= fi
.GetCustomAttributes (TypeManager
.decimal_constant_attribute_type
, false);
205 if (attrs
.Length
!= 1)
208 IConstant ic
= new ExternalConstant (fi
,
209 new DecimalConstant (((System
.Runtime
.CompilerServices
.DecimalConstantAttribute
) attrs
[0]).Value
, Location
.Null
));
214 #region IConstant Members
216 public void CheckObsoleteness (Location loc
)
218 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
223 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (fi
), loc
);
226 public bool ResolveValue ()
231 if (fi
.DeclaringType
.IsEnum
) {
232 value = Expression
.Constantify (fi
.GetValue (fi
), TypeManager
.EnumToUnderlying (fi
.FieldType
));
233 value = new EnumConstant (value, fi
.DeclaringType
);
237 value = Expression
.Constantify (fi
.GetValue (fi
), fi
.FieldType
);
241 public Constant Value
{