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
CreateConstantReference (Location loc
);
26 public class Const
: FieldBase
, IConstant
{
27 protected Constant
value;
32 public const int AllowedModifiers
=
39 public Const (DeclSpace parent
, Expression constant_type
, string name
,
40 Expression expr
, int mod_flags
, Attributes attrs
, Location loc
)
41 : base (parent
, constant_type
, mod_flags
, AllowedModifiers
,
42 new MemberName (name
, loc
), attrs
)
45 ModFlags
|= Modifiers
.STATIC
;
48 protected override bool CheckBase ()
50 // Constant.Define can be called when the parent type hasn't yet been populated
51 // and it's base types need not have been populated. So, we defer this check
52 // to the second time Define () is called on this member.
53 if (Parent
.PartialContainer
.BaseCache
== null)
55 return base.CheckBase ();
59 /// Defines the constant in the @parent
61 public override bool Define ()
63 // Because constant define can be called from other class
66 return FieldBuilder
!= null;
74 Type ttype
= MemberType
;
75 if (!IsConstantTypeValid (ttype
)) {
76 Error_InvalidConstantType (ttype
, Location
);
80 // If the constant is private then we don't need any field the
81 // value is already inlined and cannot be referenced
82 //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
86 ttype
= TypeManager
.GetElementType (ttype
);
88 FieldAttributes field_attr
= FieldAttributes
.Static
| Modifiers
.FieldAttr (ModFlags
);
89 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
90 if (ttype
== TypeManager
.decimal_type
) {
91 field_attr
|= FieldAttributes
.InitOnly
;
93 field_attr
|= FieldAttributes
.Literal
;
96 FieldBuilder
= Parent
.TypeBuilder
.DefineField (Name
, MemberType
, field_attr
);
97 TypeManager
.RegisterConstant (FieldBuilder
, this);
99 if (ttype
== TypeManager
.decimal_type
)
100 Parent
.PartialContainer
.RegisterFieldForInitialization (this,
101 new FieldInitializer (FieldBuilder
, initializer
, Parent
));
106 public static bool IsConstantTypeValid (Type t
)
108 if (TypeManager
.IsBuiltinOrEnum (t
))
111 if (t
.IsPointer
|| t
.IsValueType
)
114 if (TypeManager
.IsGenericParameter (t
))
121 /// Emits the field value by evaluating the expression
123 public override void Emit ()
125 if (!ResolveValue ())
128 if (FieldBuilder
== null)
131 if (value.Type
== TypeManager
.decimal_type
) {
132 Decimal d
= ((DecimalConstant
)value).Value
;
133 int[] bits
= Decimal
.GetBits (d
);
134 object[] args
= new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] }
;
135 CustomAttributeBuilder cab
= new CustomAttributeBuilder (TypeManager
.decimal_constant_attribute_ctor
, args
);
136 FieldBuilder
.SetCustomAttribute (cab
);
139 FieldBuilder
.SetConstant (value.GetTypedValue ());
145 public static void Error_ExpressionMustBeConstant (Location loc
, string e_name
)
147 Report
.Error (133, loc
, "The expression being assigned to `{0}' must be constant", e_name
);
150 public static void Error_CyclicDeclaration (MemberCore mc
)
152 Report
.Error (110, mc
.Location
, "The evaluation of the constant value for `{0}' involves a circular definition",
153 mc
.GetSignatureForError ());
156 public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc
, string name
)
158 Report
.Error (134, loc
, "`{0}': the constant of reference type other than string can only be initialized with null",
162 public static void Error_InvalidConstantType (Type t
, Location loc
)
164 Report
.Error (283, loc
, "The type `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
167 #region IConstant Members
169 public bool ResolveValue ()
172 return value != null;
176 Error_CyclicDeclaration (this);
177 // Suppress cyclic errors
178 value = New
.Constantify (MemberType
);
184 // TODO: IResolveContext here
185 EmitContext ec
= new EmitContext (
186 this, Parent
, Location
, null, MemberType
, ModFlags
);
187 ec
.InEnumContext
= this is EnumMember
;
188 value = DoResolveValue (ec
);
191 return value != null;
194 protected virtual Constant
DoResolveValue (EmitContext ec
)
196 Constant
value = initializer
.ResolveAsConstant (ec
, this);
200 Constant c
= value.ConvertImplicitly (MemberType
);
202 if (!MemberType
.IsValueType
&& MemberType
!= TypeManager
.string_type
&& !value.IsDefaultValue
)
203 Error_ConstantCanBeInitializedWithNullOnly (Location
, GetSignatureForError ());
205 value.Error_ValueCannotBeConverted (null, Location
, MemberType
, false);
211 public virtual Constant
CreateConstantReference (Location loc
)
216 return Constant
.CreateConstant (value.Type
, value.GetValue(), loc
);
222 public class ExternalConstant
: IConstant
227 public ExternalConstant (FieldInfo fi
)
232 private ExternalConstant (FieldInfo fi
, object value):
239 // Decimal constants cannot be encoded in the constant blob, and thus are marked
240 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
241 // DecimalConstantAttribute metadata.
243 public static IConstant
CreateDecimal (FieldInfo fi
)
245 if (fi
is FieldBuilder
)
248 object[] attrs
= fi
.GetCustomAttributes (TypeManager
.decimal_constant_attribute_type
, false);
249 if (attrs
.Length
!= 1)
252 IConstant ic
= new ExternalConstant (fi
,
253 ((System
.Runtime
.CompilerServices
.DecimalConstantAttribute
) attrs
[0]).Value
);
258 #region IConstant Members
260 public void CheckObsoleteness (Location loc
)
262 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
267 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (fi
), loc
);
270 public bool ResolveValue ()
275 value = fi
.GetValue (fi
);
279 public Constant
CreateConstantReference (Location loc
)
281 return Constant
.CreateConstant (fi
.FieldType
, value, loc
);