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