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
;
41 /// Defines the constant in the @parent
43 public override bool Define ()
48 TypeSpec ttype
= MemberType
;
49 if (!ttype
.IsConstantCompatible
) {
50 Error_InvalidConstantType (ttype
, Location
, Report
);
53 FieldAttributes field_attr
= FieldAttributes
.Static
| ModifiersExtensions
.FieldAttr (ModFlags
);
54 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
55 if (ttype
== TypeManager
.decimal_type
) {
56 field_attr
|= FieldAttributes
.InitOnly
;
58 field_attr
|= FieldAttributes
.Literal
;
61 FieldBuilder
= Parent
.TypeBuilder
.DefineField (Name
, MemberType
.GetMetaInfo (), field_attr
);
62 spec
= new ConstSpec (Parent
.Definition
, this, MemberType
, FieldBuilder
, ModFlags
, initializer
);
64 Parent
.MemberCache
.AddMember (spec
);
66 if ((field_attr
& FieldAttributes
.InitOnly
) != 0)
67 Parent
.PartialContainer
.RegisterFieldForInitialization (this,
68 new FieldInitializer (this, initializer
, this));
73 public Constant
DefineValue ()
76 value = initializer
.Resolve (new ResolveContext (this)) as Constant
;
82 /// Emits the field value by evaluating the expression
84 public override void Emit ()
86 if (value.Type
== TypeManager
.decimal_type
) {
87 FieldBuilder
.SetCustomAttribute (CreateDecimalConstantAttribute (value));
89 FieldBuilder
.SetConstant (value.GetTypedValue ());
95 public static CustomAttributeBuilder
CreateDecimalConstantAttribute (Constant c
)
97 PredefinedAttribute pa
= PredefinedAttributes
.Get
.DecimalConstant
;
98 if (pa
.Constructor
== null &&
99 !pa
.ResolveConstructor (c
.Location
, TypeManager
.byte_type
, TypeManager
.byte_type
,
100 TypeManager
.uint32_type
, TypeManager
.uint32_type
, TypeManager
.uint32_type
))
103 Decimal d
= (Decimal
) c
.GetValue ();
104 int [] bits
= Decimal
.GetBits (d
);
105 object [] args
= new object [] {
106 (byte) (bits
[3] >> 16),
107 (byte) (bits
[3] >> 31),
108 (uint) bits
[2], (uint) bits
[1], (uint) bits
[0]
111 return new CustomAttributeBuilder (pa
.Constructor
, args
);
114 public static void Error_InvalidConstantType (TypeSpec t
, Location loc
, Report Report
)
116 if (t
.IsGenericParameter
) {
117 Report
.Error (1959, loc
,
118 "Type parameter `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
120 Report
.Error (283, loc
,
121 "The type `{0}' cannot be declared const", TypeManager
.CSharpName (t
));
126 public class ConstSpec
: FieldSpec
130 public ConstSpec (TypeSpec declaringType
, IMemberDefinition definition
, TypeSpec memberType
, FieldInfo fi
, Modifiers mod
, Expression
value)
131 : base (declaringType
, definition
, memberType
, fi
, mod
)
136 public Expression Value
{
146 class ConstInitializer
: ShimExpression
149 protected readonly FieldBase field
;
151 public ConstInitializer (FieldBase field
, Expression
value)
155 this.loc
= value.Location
;
160 protected override Expression
DoResolve (ResolveContext unused
)
165 var opt
= ResolveContext
.Options
.ConstantScope
;
166 if (field
is EnumMember
)
167 opt
|= ResolveContext
.Options
.EnumScope
;
170 // Use a context in which the constant was declared and
171 // not the one in which is referenced
173 var rc
= new ResolveContext (field
, opt
);
174 expr
= DoResolveInitializer (rc
);
180 protected virtual Expression
DoResolveInitializer (ResolveContext rc
)
183 field
.Compiler
.Report
.Error (110, field
.Location
,
184 "The evaluation of the constant value for `{0}' involves a circular definition",
185 field
.GetSignatureForError ());
190 expr
= expr
.Resolve (rc
);
196 Constant c
= expr
as Constant
;
198 c
= field
.ConvertInitializer (rc
, c
);
201 if (TypeManager
.IsReferenceType (field
.MemberType
))
202 Error_ConstantCanBeInitializedWithNullOnly (rc
, field
.MemberType
, loc
, field
.GetSignatureForError ());
203 else if (!(expr
is Constant
))
204 Error_ExpressionMustBeConstant (rc
, field
.Location
, field
.GetSignatureForError ());
206 expr
.Error_ValueCannotBeConverted (rc
, loc
, field
.MemberType
, false);
213 expr
= New
.Constantify (field
.MemberType
);
215 expr
= Constant
.CreateConstantFromValue (field
.MemberType
, null, Location
);
216 expr
= expr
.Resolve (rc
);