2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001 Ximian, Inc.
13 // This is needed because the following situation arises:
15 // The FieldBuilder is declared with the real type for an enumeration
17 // When we attempt to set the value for the constant, the FieldBuilder.SetConstant
18 // function aborts because it requires its argument to be of the same type
21 namespace Mono.CSharp {
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Collections;
28 public class Const : FieldMember {
29 public Expression Expr;
32 bool resolved = false;
33 object ConstantValue = null;
35 bool in_transit = false;
37 public const int AllowedModifiers =
44 public Const (TypeContainer parent, Expression constant_type, string name,
45 Expression expr, int mod_flags, Attributes attrs, Location loc)
46 : base (parent, constant_type, mod_flags, AllowedModifiers,
47 new MemberName (name), expr, attrs, loc)
50 ModFlags |= Modifiers.STATIC;
54 void dump_tree (Type t)
56 Console.WriteLine ("Dumping hierarchy");
58 Console.WriteLine (" " + t.FullName + " " +
59 (t.GetType ().IsEnum ? "yes" : "no"));
65 protected override bool CheckBase ()
67 // Constant.Define can be called when the parent type hasn't yet been populated
68 // and it's base types need not have been populated. So, we defer this check
69 // to the second time Define () is called on this member.
70 if (Parent.BaseCache == null)
72 return base.CheckBase ();
76 /// Defines the constant in the @parent
78 public override bool Define ()
80 // Make Define () idempotent, but ensure that the error check happens.
81 if (FieldBuilder != null)
82 return base.CheckBase ();
87 const_ec = new EmitContext (Parent, Location, null, MemberType, ModFlags);
89 Type ttype = MemberType;
91 ttype = TypeManager.GetElementType (ttype);
93 if (!TypeManager.IsBuiltinType(ttype) && (!ttype.IsSubclassOf(TypeManager.enum_type)) && !(Expr is NullLiteral)){
96 "Constant type is not valid (only system types are allowed)");
100 FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
101 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
102 if (ttype == TypeManager.decimal_type) {
103 field_attr |= FieldAttributes.InitOnly;
104 Parent.RegisterFieldForInitialization (this);
107 field_attr |= FieldAttributes.Literal;
110 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
112 TypeManager.RegisterConstant (FieldBuilder, this);
118 // Changes the type of the constant expression `expr' to the Type `type'
119 // Returns null on failure.
121 public static Constant ChangeType (Location loc, Constant expr, Type type)
123 if (type == TypeManager.object_type)
128 // from the null type to any reference-type.
129 if (expr.Type == TypeManager.null_type && !type.IsValueType && !TypeManager.IsEnumType (type))
130 return NullLiteral.Null;
132 if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, expr, type)){
133 Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
137 // Special-case: The 0 literal can be converted to an enum value,
138 // and ImplicitStandardConversionExists will return true in that case.
139 if (expr.Type == TypeManager.int32_type && TypeManager.IsEnumType (type)){
140 if (expr is IntLiteral && ((IntLiteral) expr).Value == 0)
141 return new EnumConstant (expr, type);
144 object constant_value = TypeManager.ChangeType (expr.GetValue (), type, out fail);
146 Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
149 // We should always catch the error before this is ever
150 // reached, by calling Convert.ImplicitStandardConversionExists
152 throw new Exception (
153 String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type));
157 if (type == TypeManager.int32_type)
158 retval = new IntConstant ((int) constant_value);
159 else if (type == TypeManager.uint32_type)
160 retval = new UIntConstant ((uint) constant_value);
161 else if (type == TypeManager.int64_type)
162 retval = new LongConstant ((long) constant_value);
163 else if (type == TypeManager.uint64_type)
164 retval = new ULongConstant ((ulong) constant_value);
165 else if (type == TypeManager.float_type)
166 retval = new FloatConstant ((float) constant_value);
167 else if (type == TypeManager.double_type)
168 retval = new DoubleConstant ((double) constant_value);
169 else if (type == TypeManager.string_type)
170 retval = new StringConstant ((string) constant_value);
171 else if (type == TypeManager.short_type)
172 retval = new ShortConstant ((short) constant_value);
173 else if (type == TypeManager.ushort_type)
174 retval = new UShortConstant ((ushort) constant_value);
175 else if (type == TypeManager.sbyte_type)
176 retval = new SByteConstant ((sbyte) constant_value);
177 else if (type == TypeManager.byte_type)
178 retval = new ByteConstant ((byte) constant_value);
179 else if (type == TypeManager.char_type)
180 retval = new CharConstant ((char) constant_value);
181 else if (type == TypeManager.bool_type)
182 retval = new BoolConstant ((bool) constant_value);
183 else if (type == TypeManager.decimal_type)
184 retval = new DecimalConstant ((decimal) constant_value);
186 throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
192 /// Looks up the value of a constant field. Defines it if it hasn't
193 /// already been. Similar to LookupEnumValue in spirit.
195 public bool LookupConstantValue (out object value)
198 value = ConstantValue;
203 Report.Error (110, Location,
204 "The evaluation of the constant value for `" +
205 Name + "' involves a circular definition.");
211 int errors = Report.Errors;
214 // We might have cleared Expr ourselves in a recursive definition
221 Expr = Expr.Resolve (const_ec);
226 if (errors == Report.Errors)
227 Report.Error (150, Location, "A constant value is expected");
232 Expression real_expr = Expr;
234 Constant ce = Expr as Constant;
236 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
237 CheckedExpr ch_expr = Expr as CheckedExpr;
238 EmptyCast ec_expr = Expr as EmptyCast;
240 if ((un_expr != null) && (un_expr.Expr is Constant))
242 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
244 else if ((ec_expr != null) && (ec_expr.Child is Constant))
245 Expr = ec_expr.Child;
246 else if (Expr is ArrayCreation){
247 Report.Error (133, Location, "Arrays can not be constant");
249 if (errors == Report.Errors)
250 Report.Error (150, Location, "A constant value is expected");
255 ce = Expr as Constant;
258 if (MemberType != real_expr.Type) {
259 ce = ChangeType (Location, ce, MemberType);
268 ConstantValue = ce.GetValue ();
270 if (MemberType.IsEnum){
272 // This sadly does not work for our user-defined enumerations types ;-(
275 ConstantValue = System.Enum.ToObject (
276 MemberType, ConstantValue);
277 } catch (ArgumentException){
280 ".NET SDK 1.0 does not permit to create the constant "+
281 " field from a user-defined enumeration");
285 if (ce is DecimalConstant) {
286 Decimal d = ((DecimalConstant)ce).Value;
287 int[] bits = Decimal.GetBits (d);
288 object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
289 CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
290 FieldBuilder.SetCustomAttribute (cab);
293 FieldBuilder.SetConstant (ConstantValue);
296 if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
297 throw new Exception ("Cannot register const value");
299 value = ConstantValue;
306 /// Emits the field value by evaluating the expression
308 public override void Emit ()
311 LookupConstantValue (out value);