1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
|
//
// const.cs: Constant declarations.
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
// Copyright 2001-2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
//
#if STATIC
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace Mono.CSharp {
public class Const : FieldBase
{
const Modifiers AllowedModifiers =
Modifiers.NEW |
Modifiers.PUBLIC |
Modifiers.PROTECTED |
Modifiers.INTERNAL |
Modifiers.PRIVATE;
public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
: base (parent, type, mod_flags, AllowedModifiers, name, attrs)
{
ModFlags |= Modifiers.STATIC;
}
/// <summary>
/// Defines the constant in the @parent
/// </summary>
public override bool Define ()
{
if (!base.Define ())
return false;
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 (member_type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
field_attr |= FieldAttributes.InitOnly;
} else {
field_attr |= FieldAttributes.Literal;
}
FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
Parent.MemberCache.AddMember (spec);
if ((field_attr & FieldAttributes.InitOnly) != 0)
Parent.PartialContainer.RegisterFieldForInitialization (this,
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 void DefineValue ()
{
var rc = new ResolveContext (this);
((ConstSpec) spec).GetConstant (rc);
}
/// <summary>
/// Emits the field value by evaluating the expression
/// </summary>
public override void Emit ()
{
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 ();
}
public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
{
if (t.IsGenericParameter) {
Report.Error (1959, loc,
"Type parameter `{0}' cannot be declared const", t.GetSignatureForError ());
} else {
Report.Error (283, loc,
"The type `{0}' cannot be declared const", t.GetSignatureForError ());
}
}
public override void Accept (StructuralVisitor visitor)
{
visitor.Visit (this);
}
}
public class ConstSpec : FieldSpec
{
Expression value;
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;
}
}
//
// 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;
}
}
public class ConstInitializer : ShimExpression
{
bool in_transit;
readonly FieldBase field;
public ConstInitializer (FieldBase field, Expression value, Location loc)
: base (value)
{
this.loc = loc;
this.field = field;
}
public string Name { get; set; }
protected override Expression DoResolve (ResolveContext unused)
{
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;
}
protected virtual Expression DoResolveInitializer (ResolveContext rc)
{
if (in_transit) {
field.Compiler.Report.Error (110, expr.Location,
"The evaluation of the constant value for `{0}' involves a circular definition",
GetSignatureForError ());
expr = null;
} else {
in_transit = true;
expr = expr.Resolve (rc);
}
in_transit = false;
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);
}
expr = c;
}
if (expr == null) {
expr = New.Constantify (field.MemberType, Location);
if (expr == null)
expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
expr = expr.Resolve (rc);
}
return expr;
}
public override string GetSignatureForError ()
{
if (Name == null)
return field.GetSignatureForError ();
return field.Parent.GetSignatureForError () + "." + Name;
}
public override object Accept (StructuralVisitor visitor)
{
return visitor.Visit (this);
}
}
}
|