// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2001 Ximian, Inc.
-//
+// Copyright 2001-2003 Ximian, Inc.
+// Copyright 2003-2008 Novell, Inc.
//
-namespace Mono.CSharp {
+#if STATIC
+using IKVM.Reflection;
+#else
+using System.Reflection;
+#endif
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Collections;
+namespace Mono.CSharp {
- public interface IConstant
+ public class Const : FieldBase
{
- void CheckObsoleteness (Location loc);
- bool ResolveValue ();
- Constant CreateConstantReference (Location loc);
- }
-
- public class Const : FieldBase, IConstant {
- protected Constant value;
- bool in_transit;
- bool resolved;
- bool define_called;
-
- public const int AllowedModifiers =
+ const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE;
- public Const (DeclSpace parent, Expression constant_type, string name,
- Expression expr, int mod_flags, Attributes attrs, Location loc)
- : base (parent, constant_type, mod_flags, AllowedModifiers,
- new MemberName (name, loc), attrs)
+ public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
+ : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
{
- initializer = 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);
- return false;
+ if (!member_type.IsConstantCompatible) {
+ Error_InvalidConstantType (member_type, Location, Report);
}
- // If the constant is private then we don't need any field the
- // value is already inlined and cannot be referenced
- //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
- // return true;
-
- while (ttype.IsArray)
- ttype = TypeManager.GetElementType (ttype);
-
- FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
+ 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.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
field_attr |= FieldAttributes.InitOnly;
} else {
field_attr |= FieldAttributes.Literal;
}
- FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
- TypeManager.RegisterConstant (FieldBuilder, this);
- Parent.MemberCache.AddMember (FieldBuilder, this);
+ FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
+ spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
- if (ttype == TypeManager.decimal_type)
+ Parent.MemberCache.AddMember (spec);
+
+ if ((field_attr & FieldAttributes.InitOnly) != 0)
Parent.PartialContainer.RegisterFieldForInitialization (this,
- new FieldInitializer (FieldBuilder, initializer));
+ new FieldInitializer (this, initializer, Location));
+
+ if (declarators != null) {
+ var t = new TypeExpression (MemberType, TypeExpression.Location);
+ 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;
+ c.Define ();
+ Parent.PartialContainer.Members.Add (c);
+ }
+ }
return true;
}
- public static bool IsConstantTypeValid (Type t)
+ public void DefineValue ()
{
- if (TypeManager.IsBuiltinOrEnum (t))
- return true;
-
- if (t.IsPointer || t.IsValueType)
- return false;
-
- if (TypeManager.IsGenericParameter (t))
- return false;
-
- return true;
+ var rc = new ResolveContext (this);
+ ((ConstSpec) spec).GetConstant (rc);
}
/// <summary>
/// </summary>
public override void Emit ()
{
- if (!ResolveValue ())
- return;
-
- if (FieldBuilder == null)
- return;
-
- if (value.Type == TypeManager.decimal_type) {
- EmitDecimalConstant ();
- } else{
- FieldBuilder.SetConstant (value.GetTypedValue ());
+ var c = ((ConstSpec) spec).Value as Constant;
+ if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
+ Module.PredefinedAttributes.DecimalConstant.EmitAttribute (FieldBuilder, (decimal) c.GetValue (), c.Location);
+ } else {
+ FieldBuilder.SetConstant (c.GetValue ());
}
base.Emit ();
}
- void EmitDecimalConstant ()
+ public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
{
- ConstructorInfo ctor = TypeManager.decimal_constant_attribute_ctor;
- if (ctor == null) {
- if (TypeManager.decimal_constant_attribute_type == null) {
- TypeManager.decimal_constant_attribute_type = TypeManager.CoreLookupType (
- "System.Runtime.CompilerServices", "DecimalConstantAttribute", Kind.Class, true);
-
- if (TypeManager.decimal_constant_attribute_type == null)
- return;
- }
-
- ctor = TypeManager.GetPredefinedConstructor (TypeManager.decimal_constant_attribute_type, Location,
- TypeManager.byte_type, TypeManager.byte_type,
- TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type);
-
- if (ctor == null)
- return;
-
- TypeManager.decimal_constant_attribute_ctor = ctor;
+ if (t.IsGenericParameter) {
+ Report.Error (1959, loc,
+ "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
+ } else {
+ Report.Error (283, loc,
+ "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
}
-
- Decimal d = ((DecimalConstant) value).Value;
- int [] bits = Decimal.GetBits (d);
- object [] args = new object [] {
- (byte) (bits [3] >> 16),
- (byte) (bits [3] >> 31),
- (uint) bits [2], (uint) bits [1], (uint) bits [0]
- };
-
- CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, args);
- FieldBuilder.SetCustomAttribute (cab);
- }
-
- public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
- {
- Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
- }
-
- public static void Error_CyclicDeclaration (MemberCore mc)
- {
- Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
- mc.GetSignatureForError ());
- }
-
- public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
- {
- Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
- name);
- }
-
- public static void Error_InvalidConstantType (Type t, Location loc)
- {
- Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
}
+ }
- #region IConstant Members
+ public class ConstSpec : FieldSpec
+ {
+ Expression value;
- public bool ResolveValue ()
+ public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
+ : base (declaringType, definition, memberType, fi, mod)
{
- if (resolved)
- return value != null;
-
- SetMemberIsUsed ();
- if (in_transit) {
- Error_CyclicDeclaration (this);
- // Suppress cyclic errors
- value = New.Constantify (MemberType);
- resolved = true;
- return false;
- }
-
- in_transit = true;
- // TODO: IResolveContext here
- EmitContext ec = new EmitContext (
- this, Parent, Location, null, MemberType, ModFlags);
- ec.InEnumContext = this is EnumMember;
- ec.IsAnonymousMethodAllowed = false;
- value = DoResolveValue (ec);
- in_transit = false;
- resolved = true;
- return value != null;
+ this.value = value;
}
- protected virtual Constant DoResolveValue (EmitContext ec)
- {
- Constant value = initializer.ResolveAsConstant (ec, this);
- if (value == null)
- return null;
-
- Constant c = value.ConvertImplicitly (MemberType);
- if (c == null) {
- if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue)
- Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
- else
- value.Error_ValueCannotBeConverted (null, Location, MemberType, false);
+ //
+ // This expresion is guarantee to be a constant at emit phase only
+ //
+ public Expression Value {
+ get {
+ return value;
}
-
- return c;
}
- public virtual Constant CreateConstantReference (Location loc)
+ //
+ // 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 == null)
- return null;
+ if (value.eclass != ExprClass.Value)
+ value = value.Resolve (rc);
- return Constant.CreateConstant (value.Type, value.GetValue(), loc);
+ return (Constant) value;
}
-
- #endregion
}
- public class ExternalConstant : IConstant
+ public class ConstInitializer : ShimExpression
{
- FieldInfo fi;
- object value;
+ bool in_transit;
+ readonly FieldBase field;
- public ExternalConstant (FieldInfo fi)
+ public ConstInitializer (FieldBase field, Expression value, Location loc)
+ : base (value)
{
- this.fi = fi;
+ this.loc = loc;
+ this.field = field;
}
- private ExternalConstant (FieldInfo fi, object value):
- this (fi)
+ public string Name { get; set; }
+
+ protected override Expression DoResolve (ResolveContext unused)
{
- this.value = value;
+ if (type != null)
+ return expr;
+
+ var opt = ResolveContext.Options.ConstantScope;
+ if (field is EnumMember)
+ opt |= ResolveContext.Options.EnumScope;
+
+ //
+ // Use a context in which the constant was declared and
+ // not the one in which is referenced
+ //
+ var rc = new ResolveContext (field, opt);
+ expr = DoResolveInitializer (rc);
+ type = expr.Type;
+
+ return expr;
}
- //
- // Decimal constants cannot be encoded in the constant blob, and thus are marked
- // as IsInitOnly ('readonly' in C# parlance). We get its value from the
- // DecimalConstantAttribute metadata.
- //
- public static IConstant CreateDecimal (FieldInfo fi)
+ protected virtual Expression DoResolveInitializer (ResolveContext rc)
{
- if (fi is FieldBuilder)
- return null;
-
- if (TypeManager.decimal_constant_attribute_type == null)
- return null;
+ if (in_transit) {
+ field.Compiler.Report.Error (110, expr.Location,
+ "The evaluation of the constant value for `{0}' involves a circular definition",
+ GetSignatureForError ());
- object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
- if (attrs.Length != 1)
- return null;
+ expr = null;
+ } else {
+ in_transit = true;
+ expr = expr.Resolve (rc);
+ }
- IConstant ic = new ExternalConstant (fi,
- ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
+ in_transit = false;
- return ic;
- }
+ if (expr != null) {
+ Constant c = expr as Constant;
+ if (c != null)
+ c = field.ConvertInitializer (rc, c);
+
+ if (c == null) {
+ if (TypeSpec.IsReferenceType (field.MemberType))
+ Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
+ else if (!(expr is Constant))
+ Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
+ else
+ expr.Error_ValueCannotBeConverted (rc, field.MemberType, false);
+ }
- #region IConstant Members
+ expr = c;
+ }
- public void CheckObsoleteness (Location loc)
- {
- ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
- if (oa == null) {
- return;
+ if (expr == null) {
+ expr = New.Constantify (field.MemberType, Location);
+ if (expr == null)
+ expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
+ expr = expr.Resolve (rc);
}
- AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
+ return expr;
}
- public bool ResolveValue ()
+ public override string GetSignatureForError ()
{
- if (value != null)
- return true;
+ if (Name == null)
+ return field.GetSignatureForError ();
- value = fi.GetValue (fi);
- return true;
+ return field.Parent.GetSignatureForError () + "." + Name;
}
- public Constant CreateConstantReference (Location loc)
+ public override object Accept (StructuralVisitor visitor)
{
- return Constant.CreateConstant (TypeManager.TypeToCoreType (fi.FieldType), value, loc);
+ return visitor.Visit (this);
}
-
- #endregion
}
-
}