public class Const : FieldBase
{
- bool define_called;
-
public const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.INTERNAL |
Modifiers.PRIVATE;
- public Const (DeclSpace parent, FullNamedExpression type, string name,
- Expression expr, Modifiers mod_flags, Attributes attrs, Location loc)
- : base (parent, type, mod_flags, AllowedModifiers,
- new MemberName (name, loc), attrs)
+ public Const (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
+ : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
{
- if (expr != null)
- initializer = new ConstInitializer (this, expr);
-
ModFlags |= Modifiers.STATIC;
}
- protected override bool CheckBase ()
- {
- // Constant.Define can be called when the parent type hasn't yet been populated
- // and it's base types need not have been populated. So, we defer this check
- // to the second time Define () is called on this member.
- if (Parent.PartialContainer.BaseCache == null)
- return true;
- return base.CheckBase ();
- }
-
/// <summary>
/// Defines the constant in the @parent
/// </summary>
public override bool Define ()
{
- // Because constant define can be called from other class
- if (define_called) {
- CheckBase ();
- return FieldBuilder != null;
- }
-
- define_called = true;
-
if (!base.Define ())
return false;
- Type ttype = MemberType;
- if (!IsConstantTypeValid (ttype)) {
- Error_InvalidConstantType (ttype, Location, Report);
+ if (!member_type.IsConstantCompatible) {
+ Error_InvalidConstantType (member_type, Location, Report);
}
FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
// Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
- if (ttype == TypeManager.decimal_type) {
+ if (member_type == TypeManager.decimal_type) {
field_attr |= FieldAttributes.InitOnly;
} else {
field_attr |= FieldAttributes.Literal;
}
- FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
- spec = new ConstSpec (this, FieldBuilder, ModFlags, initializer);
+ FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
+ spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
- TypeManager.RegisterConstant (FieldBuilder, (ConstSpec) spec);
- Parent.MemberCache.AddMember (FieldBuilder, this);
+ Parent.MemberCache.AddMember (spec);
if ((field_attr & FieldAttributes.InitOnly) != 0)
Parent.PartialContainer.RegisterFieldForInitialization (this,
- new FieldInitializer (this, initializer, this));
+ new FieldInitializer (spec, initializer, this));
+
+ if (declarators != null) {
+ var t = new TypeExpression (MemberType, TypeExpression.Location);
+ int index = Parent.PartialContainer.Constants.IndexOf (this);
+ foreach (var d in declarators) {
+ var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
+ c.initializer = d.Initializer;
+ ((ConstInitializer) c.initializer).Name = d.Name.Value;
+ Parent.PartialContainer.Constants.Insert (++index, c);
+ }
+ }
return true;
}
- public static bool IsConstantTypeValid (Type t)
+ public void DefineValue ()
{
- if (TypeManager.IsBuiltinOrEnum (t))
- return true;
-
- if (TypeManager.IsGenericParameter (t) || t.IsPointer)
- return false;
-
- return TypeManager.IsReferenceType (t);
+ var rc = new ResolveContext (this);
+ ((ConstSpec) spec).GetConstant (rc);
}
/// <summary>
/// </summary>
public override void Emit ()
{
- var value = initializer.Resolve (new ResolveContext (this)) as Constant;
- if (value == null || FieldBuilder == null)
- return;
-
- if (value.Type == TypeManager.decimal_type) {
- FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
- } else{
- FieldBuilder.SetConstant (value.GetTypedValue ());
+ var c = ((ConstSpec) spec).Value as Constant;
+ if (c.Type == TypeManager.decimal_type) {
+ FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (c));
+ } else {
+ FieldBuilder.SetConstant (c.GetTypedValue ());
}
base.Emit ();
return new CustomAttributeBuilder (pa.Constructor, args);
}
- public static void Error_InvalidConstantType (Type t, Location loc, Report Report)
+ public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
{
- if (TypeManager.IsGenericParameter (t)) {
+ if (t.IsGenericParameter) {
Report.Error (1959, loc,
"Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
} else {
{
Expression value;
- public ConstSpec (IMemberDefinition definition, FieldInfo fi, Modifiers mod, Expression value)
- : base (definition, fi, mod)
+ public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
+ : base (declaringType, definition, memberType, fi, mod)
{
this.value = value;
}
+ //
+ // This expresion is guarantee to be a constant at emit phase only
+ //
public Expression Value {
get {
return value;
}
- set {
- this.value = value;
- }
+ }
+
+ //
+ // For compiled constants we have to resolve the value as there could be constant dependecies. This
+ // is needed for imported constants too to get the right context type
+ //
+ public Constant GetConstant (ResolveContext rc)
+ {
+ if (value.eclass != ExprClass.Value)
+ value = value.Resolve (rc);
+
+ return (Constant) value;
}
}
- class ConstInitializer : ShimExpression
+ public class ConstInitializer : ShimExpression
{
bool in_transit;
- protected readonly FieldBase field;
+ readonly FieldBase field;
- public ConstInitializer (FieldBase field, Expression value)
+ public ConstInitializer (FieldBase field, Expression value, Location loc)
: base (value)
{
- if (value != null)
- this.loc = value.Location;
-
+ this.loc = loc;
this.field = field;
}
+ public string Name { get; set; }
+
protected override Expression DoResolve (ResolveContext unused)
{
if (type != null)
protected virtual Expression DoResolveInitializer (ResolveContext rc)
{
if (in_transit) {
- field.Compiler.Report.Error (110, field.Location,
+ field.Compiler.Report.Error (110, expr.Location,
"The evaluation of the constant value for `{0}' involves a circular definition",
- field.GetSignatureForError ());
+ GetSignatureForError ());
expr = null;
} else {
if (c == null) {
if (TypeManager.IsReferenceType (field.MemberType))
- Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, loc, field.GetSignatureForError ());
+ Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
else if (!(expr is Constant))
- Error_ExpressionMustBeConstant (rc, field.Location, field.GetSignatureForError ());
+ Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
else
- expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
+ expr.Error_ValueCannotBeConverted (rc, expr.Location, field.MemberType, false);
}
expr = c;
expr = expr.Resolve (rc);
}
-
return expr;
}
+
+ public override string GetSignatureForError ()
+ {
+ if (Name == null)
+ return field.GetSignatureForError ();
+
+ return field.Parent.GetSignatureForError () + "." + Name;
+ }
}
}