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.
13 using System
.Reflection
;
14 using System
.Reflection
.Emit
;
16 namespace Mono
.CSharp
{
18 public class Const
: FieldBase
22 public const Modifiers AllowedModifiers
=
29 public Const (DeclSpace parent
, FullNamedExpression type
, string name
,
30 Expression expr
, Modifiers mod_flags
, Attributes attrs
, Location loc
)
31 : base (parent
, type
, mod_flags
, AllowedModifiers
,
32 new MemberName (name
, loc
), attrs
)
35 initializer
= new ConstInitializer (this, expr
);
37 ModFlags
|= Modifiers
.STATIC
;
40 protected override bool CheckBase ()
42 // Constant.Define can be called when the parent type hasn't yet been populated
43 // and it's base types need not have been populated. So, we defer this check
44 // to the second time Define () is called on this member.
45 if (Parent
.PartialContainer
.BaseCache
== null)
47 return base.CheckBase ();
51 /// Defines the constant in the @parent
53 public override bool Define ()
55 // Because constant define can be called from other class
58 return FieldBuilder
!= null;
66 Type ttype
= MemberType
;
67 if (!IsConstantTypeValid (ttype
)) {
68 Error_InvalidConstantType (ttype
, Location
, Report
);
71 FieldAttributes field_attr
= FieldAttributes
.Static
| ModifiersExtensions
.FieldAttr (ModFlags
);
72 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
73 if (ttype
== TypeManager
.decimal_type
) {
74 field_attr
|= FieldAttributes
.InitOnly
;
76 field_attr
|= FieldAttributes
.Literal
;
79 FieldBuilder
= Parent
.TypeBuilder
.DefineField (Name
, MemberType
, field_attr
);
80 spec
= new ConstSpec (this, FieldBuilder
, ModFlags
, initializer
);
82 TypeManager
.RegisterConstant (FieldBuilder
, (ConstSpec
) spec
);
83 Parent
.MemberCache
.AddMember (FieldBuilder
, spec
);
85 if ((field_attr
& FieldAttributes
.InitOnly
) != 0)
86 Parent
.PartialContainer
.RegisterFieldForInitialization (this,
87 new FieldInitializer (this, initializer
, this));
92 public static bool IsConstantTypeValid (Type t
)
94 if (TypeManager
.IsBuiltinOrEnum (t
))
97 if (TypeManager
.IsGenericParameter (t
) || t
.IsPointer
)
100 return TypeManager
.IsReferenceType (t
);
104 /// Emits the field value by evaluating the expression
106 public override void Emit ()
108 var value = initializer
.Resolve (new ResolveContext (this)) as Constant
;
109 if (value == null || FieldBuilder
== null)
112 if (value.Type
== TypeManager
.decimal_type
) {
113 FieldBuilder
.SetCustomAttribute (CreateDecimalConstantAttribute (value));
115 FieldBuilder
.SetConstant (value.GetTypedValue ());
121 public static CustomAttributeBuilder
CreateDecimalConstantAttribute (Constant c
)
123 PredefinedAttribute pa
= PredefinedAttributes
.Get
.DecimalConstant
;
124 if (pa
.Constructor
== null &&
125 !pa
.ResolveConstructor (c
.Location
, TypeManager
.byte_type
, TypeManager
.byte_type
,
126 TypeManager
.uint32_type
, TypeManager
.uint32_type
, TypeManager
.uint32_type
))
129 Decimal d
= (Decimal
) c
.GetValue ();
130 int [] bits
= Decimal
.GetBits (d
);
131 object [] args
= new object [] {
132 (byte) (bits
[3] >> 16),
133 (byte) (bits
[3] >> 31),
134 (uint) bits
[2], (uint) bits
[1], (uint) bits
[0]
137 return new CustomAttributeBuilder (pa
.Constructor
, args
);
140 public static void Error_InvalidConstantType (Type t
, Location loc
, Report Report
)
142 if (TypeManager
.IsGenericParameter (t
)) {
143 Report
.Error (1959, loc
,
144 "Type parameter `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
146 Report
.Error (283, loc
,
147 "The type `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
152 public class ConstSpec
: FieldSpec
156 public ConstSpec (IMemberDefinition definition
, FieldInfo fi
, Modifiers mod
, Expression
value)
157 : base (definition
, fi
, mod
)
162 public Expression Value
{
172 class ConstInitializer
: ShimExpression
175 protected readonly FieldBase field
;
177 public ConstInitializer (FieldBase field
, Expression
value)
181 this.loc
= value.Location
;
186 protected override Expression
DoResolve (ResolveContext unused
)
191 var opt
= ResolveContext
.Options
.ConstantScope
;
192 if (field
is EnumMember
)
193 opt
|= ResolveContext
.Options
.EnumScope
;
196 // Use a context in which the constant was declared and
197 // not the one in which is referenced
199 var rc
= new ResolveContext (field
, opt
);
200 expr
= DoResolveInitializer (rc
);
206 protected virtual Expression
DoResolveInitializer (ResolveContext rc
)
209 field
.Compiler
.Report
.Error (110, field
.Location
,
210 "The evaluation of the constant value for `{0}' involves a circular definition",
211 field
.GetSignatureForError ());
216 expr
= expr
.Resolve (rc
);
222 Constant c
= expr
as Constant
;
224 c
= field
.ConvertInitializer (rc
, c
);
227 if (TypeManager
.IsReferenceType (field
.MemberType
))
228 Error_ConstantCanBeInitializedWithNullOnly (rc
, field
.MemberType
, loc
, field
.GetSignatureForError ());
229 else if (!(expr
is Constant
))
230 Error_ExpressionMustBeConstant (rc
, field
.Location
, field
.GetSignatureForError ());
232 expr
.Error_ValueCannotBeConverted (rc
, loc
, field
.MemberType
, false);
239 expr
= New
.Constantify (field
.MemberType
);
241 expr
= Constant
.CreateConstantFromValue (field
.MemberType
, null, Location
);
242 expr
= expr
.Resolve (rc
);