2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001-2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, 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
, FullNamedExpression type
, string name
,
40 Expression expr
, int mod_flags
, Attributes attrs
, Location loc
)
41 : base (parent
, 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
);
79 // If the constant is private then we don't need any field the
80 // value is already inlined and cannot be referenced
81 //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
84 FieldAttributes field_attr
= FieldAttributes
.Static
| Modifiers
.FieldAttr (ModFlags
);
85 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
86 if (ttype
== TypeManager
.decimal_type
) {
87 field_attr
|= FieldAttributes
.InitOnly
;
89 field_attr
|= FieldAttributes
.Literal
;
92 FieldBuilder
= Parent
.TypeBuilder
.DefineField (Name
, MemberType
, field_attr
);
93 TypeManager
.RegisterConstant (FieldBuilder
, this);
94 Parent
.MemberCache
.AddMember (FieldBuilder
, this);
96 if ((field_attr
& FieldAttributes
.InitOnly
) != 0)
97 Parent
.PartialContainer
.RegisterFieldForInitialization (this,
98 new FieldInitializer (FieldBuilder
, initializer
, this));
103 public static bool IsConstantTypeValid (Type t
)
105 if (TypeManager
.IsBuiltinOrEnum (t
))
108 if (TypeManager
.IsGenericParameter (t
) || t
.IsPointer
)
111 return TypeManager
.IsReferenceType (t
);
115 /// Emits the field value by evaluating the expression
117 public override void Emit ()
119 if (!ResolveValue ())
122 if (FieldBuilder
== null)
125 if (value.Type
== TypeManager
.decimal_type
) {
126 FieldBuilder
.SetCustomAttribute (CreateDecimalConstantAttribute (value));
128 FieldBuilder
.SetConstant (value.GetTypedValue ());
134 public static CustomAttributeBuilder
CreateDecimalConstantAttribute (Constant c
)
136 PredefinedAttribute pa
= PredefinedAttributes
.Get
.DecimalConstant
;
137 if (pa
.Constructor
== null &&
138 !pa
.ResolveConstructor (c
.Location
, TypeManager
.byte_type
, TypeManager
.byte_type
,
139 TypeManager
.uint32_type
, TypeManager
.uint32_type
, TypeManager
.uint32_type
))
142 Decimal d
= (Decimal
) c
.GetValue ();
143 int [] bits
= Decimal
.GetBits (d
);
144 object [] args
= new object [] {
145 (byte) (bits
[3] >> 16),
146 (byte) (bits
[3] >> 31),
147 (uint) bits
[2], (uint) bits
[1], (uint) bits
[0]
150 return new CustomAttributeBuilder (pa
.Constructor
, args
);
153 public static void Error_ExpressionMustBeConstant (Location loc
, string e_name
)
155 Report
.Error (133, loc
, "The expression being assigned to `{0}' must be constant", e_name
);
158 public static void Error_CyclicDeclaration (MemberCore mc
)
160 Report
.Error (110, mc
.Location
, "The evaluation of the constant value for `{0}' involves a circular definition",
161 mc
.GetSignatureForError ());
164 public static void Error_ConstantCanBeInitializedWithNullOnly (Type type
, Location loc
, string name
)
166 Report
.Error (134, loc
, "A constant `{0}' of reference type `{1}' can only be initialized with null",
167 name
, TypeManager
.CSharpName (type
));
170 public static void Error_InvalidConstantType (Type t
, Location loc
)
172 if (TypeManager
.IsGenericParameter (t
)) {
173 Report
.Error (1959, loc
,
174 "Type parameter `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
176 Report
.Error (283, loc
,
177 "The type `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
181 #region IConstant Members
183 public bool ResolveValue ()
186 return value != null;
190 Error_CyclicDeclaration (this);
191 // Suppress cyclic errors
192 value = New
.Constantify (MemberType
);
198 // TODO: IResolveContext here
199 EmitContext ec
= new EmitContext (
200 this, Parent
, Location
, null, MemberType
, ModFlags
);
201 ec
.InEnumContext
= this is EnumMember
;
202 ec
.IsAnonymousMethodAllowed
= false;
203 value = DoResolveValue (ec
);
206 return value != null;
209 protected virtual Constant
DoResolveValue (EmitContext ec
)
211 Constant
value = initializer
.ResolveAsConstant (ec
, this);
215 Constant c
= value.ConvertImplicitly (MemberType
);
217 if (TypeManager
.IsReferenceType (MemberType
))
218 Error_ConstantCanBeInitializedWithNullOnly (MemberType
, Location
, GetSignatureForError ());
220 value.Error_ValueCannotBeConverted (ec
, Location
, MemberType
, false);
226 public virtual Constant
CreateConstantReference (Location loc
)
231 return Constant
.CreateConstant (value.Type
, value.GetValue(), loc
);
237 public class ExternalConstant
: IConstant
242 public ExternalConstant (FieldInfo fi
)
247 private ExternalConstant (FieldInfo fi
, object value):
254 // Decimal constants cannot be encoded in the constant blob, and thus are marked
255 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
256 // DecimalConstantAttribute metadata.
258 public static IConstant
CreateDecimal (FieldInfo fi
)
260 if (fi
is FieldBuilder
)
263 PredefinedAttribute pa
= PredefinedAttributes
.Get
.DecimalConstant
;
267 object[] attrs
= fi
.GetCustomAttributes (pa
.Type
, false);
268 if (attrs
.Length
!= 1)
271 IConstant ic
= new ExternalConstant (fi
,
272 ((System
.Runtime
.CompilerServices
.DecimalConstantAttribute
) attrs
[0]).Value
);
277 #region IConstant Members
279 public void CheckObsoleteness (Location loc
)
281 ObsoleteAttribute oa
= AttributeTester
.GetMemberObsoleteAttribute (fi
);
286 AttributeTester
.Report_ObsoleteMessage (oa
, TypeManager
.GetFullNameSignature (fi
), loc
);
289 public bool ResolveValue ()
294 value = fi
.GetValue (fi
);
298 public Constant
CreateConstantReference (Location loc
)
300 return Constant
.CreateConstant (TypeManager
.TypeToCoreType (fi
.FieldType
), value, loc
);