2009-07-10 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / literal.cs
1 //
2 // literal.cs: Literal representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // Copyright 2001 Ximian, Inc.
9 //
10 //
11 // Notice that during parsing we create objects of type Literal, but the
12 // types are not loaded (thats why the Resolve method has to assign the
13 // type at that point).
14 //
15 // Literals differ from the constants in that we know we encountered them
16 // as a literal in the source code (and some extra rules apply there) and
17 // they have to be resolved (since during parsing we have not loaded the
18 // types yet) while constants are created only after types have been loaded
19 // and are fully resolved when born.
20 //
21
22 using System;
23 using System.Reflection;
24 using System.Reflection.Emit;
25
26 namespace Mono.CSharp {
27
28         //
29         // The null literal
30         //
31         // Note: C# specification null-literal is NullLiteral of NullType type
32         //
33         class NullLiteral : Constant
34         {
35                 //
36                 // Default type of null is an object
37                 //
38                 public NullLiteral (Location loc):
39                         this (typeof (NullLiteral), loc)
40                 {
41                 }
42
43                 //
44                 // Null can have its own type, think of default (Foo)
45                 //
46                 public NullLiteral (Type type, Location loc)
47                         : base (loc)
48                 {
49                         eclass = ExprClass.Value;
50                         this.type = type;
51                 }
52
53                 override public string AsString ()
54                 {
55                         return GetSignatureForError ();
56                 }
57                 
58                 public override Expression CreateExpressionTree (EmitContext ec)
59                 {
60                         // HACK: avoid referencing mcs internal type
61                         if (type == typeof (NullLiteral))
62                                 type = TypeManager.object_type;
63
64                         return base.CreateExpressionTree (ec);
65                 }               
66
67                 public override Expression DoResolve (EmitContext ec)
68                 {
69                         return this;
70                 }
71
72                 public override void Emit (EmitContext ec)
73                 {
74                         ec.ig.Emit (OpCodes.Ldnull);
75
76 #if GMCS_SOURCE
77                         // Only to make verifier happy
78                         if (TypeManager.IsGenericParameter (type))
79                                 ec.ig.Emit (OpCodes.Unbox_Any, type);
80 #endif
81                 }
82
83                 public override string ExprClassName {
84                         get {
85                                 return GetSignatureForError ();
86                         }
87                 }
88
89                 public override string GetSignatureForError ()
90                 {
91                         return "null";
92                 }
93
94                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
95                 {
96                         if (TypeManager.IsGenericParameter (t)) {
97                                 Report.Error(403, loc,
98                                         "Cannot convert null to the type parameter `{0}' because it could be a value " +
99                                         "type. Consider using `default ({0})' instead", t.Name);
100                                 return;
101                         }
102
103                         if (TypeManager.IsValueType (t)) {
104                                 Report.Error(37, loc, "Cannot convert null to `{0}' because it is a value type",
105                                         TypeManager.CSharpName(t));
106                                 return;
107                         }
108
109                         base.Error_ValueCannotBeConverted (ec, loc, t, expl);
110                 }
111
112                 public override Constant ConvertExplicitly (bool inCheckedContext, Type targetType)
113                 {
114                         if (targetType.IsPointer) {
115                                 if (type == TypeManager.null_type || this is NullPointer)
116                                         return new EmptyConstantCast (new NullPointer (loc), targetType);
117
118                                 return null;
119                         }
120
121                         // Exlude internal compiler types
122                         if (targetType == InternalType.AnonymousMethod)
123                                 return null;
124
125                         if (type != TypeManager.null_type && !Convert.ImplicitStandardConversionExists (this, targetType))
126                                 return null;
127
128                         if (TypeManager.IsReferenceType (targetType))
129                                 return new NullLiteral (targetType, loc);
130
131                         if (TypeManager.IsNullableType (targetType))
132                                 return Nullable.LiftedNull.Create (targetType, loc);
133
134                         return null;
135                 }
136
137                 public override Constant ConvertImplicitly (Type targetType)
138                 {
139                         //
140                         // Null literal is of object type
141                         //
142                         if (targetType == TypeManager.object_type)
143                                 return this;
144
145                         return ConvertExplicitly (false, targetType);
146                 }
147
148                 public override object GetValue ()
149                 {
150                         return null;
151                 }
152
153                 public override Constant Increment ()
154                 {
155                         throw new NotSupportedException ();
156                 }
157
158                 public override bool IsDefaultValue {
159                         get { return true; }
160                 }
161
162                 public override bool IsLiteral {
163                         get { return true; }
164                 }
165
166                 public override bool IsNegative {
167                         get { return false; }
168                 }
169
170                 public override bool IsNull {
171                         get { return true; }
172                 }
173
174                 public override bool IsZeroInteger {
175                         get { return true; }
176                 }
177                 
178                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
179                 {
180                         type = storey.MutateType (type);
181                 }
182         }
183
184         //
185         // A null literal in a pointer context
186         //
187         class NullPointer : NullLiteral {
188                 public NullPointer (Location loc):
189                         base (loc)
190                 {
191                         type = TypeManager.object_type;
192                 }
193
194                 public override void Emit (EmitContext ec)
195                 {
196                         ILGenerator ig = ec.ig;
197                                 
198                         //
199                         // Emits null pointer
200                         //
201                         ig.Emit (OpCodes.Ldc_I4_0);
202                         ig.Emit (OpCodes.Conv_U);
203                 }
204         }
205
206         public class BoolLiteral : BoolConstant {
207                 public BoolLiteral (bool val, Location loc) : base (val, loc)
208                 {
209                 }
210
211                 public override Expression DoResolve (EmitContext ec)
212                 {
213                         type = TypeManager.bool_type;
214                         return this;
215                 }
216
217                 public override bool IsLiteral {
218                         get { return true; }
219                 }
220         }
221
222         public class CharLiteral : CharConstant {
223                 public CharLiteral (char c, Location loc) : base (c, loc)
224                 {
225                 }
226
227                 public override Expression DoResolve (EmitContext ec)
228                 {
229                         type = TypeManager.char_type;
230                         return this;
231                 }
232
233                 public override bool IsLiteral {
234                         get { return true; }
235                 }
236         }
237
238         public class IntLiteral : IntConstant {
239                 public IntLiteral (int l, Location loc) : base (l, loc)
240                 {
241                 }
242
243                 public override Expression DoResolve (EmitContext ec)
244                 {
245                         type = TypeManager.int32_type;
246                         return this;
247                 }
248
249                 public override Constant ConvertImplicitly (Type type)
250                 {
251                         ///
252                         /// The 0 literal can be converted to an enum value,
253                         ///
254                         if (Value == 0 && TypeManager.IsEnumType (type)) {
255                                 Constant c = ConvertImplicitly (TypeManager.GetEnumUnderlyingType (type));
256                                 if (c == null)
257                                         return null;
258
259                                 return new EnumConstant (c, type);
260                         }
261                         return base.ConvertImplicitly (type);
262                 }
263
264                 public override bool IsLiteral {
265                         get { return true; }
266                 }
267         }
268
269         public class UIntLiteral : UIntConstant {
270                 public UIntLiteral (uint l, Location loc) : base (l, loc)
271                 {
272                 }
273
274                 public override Expression DoResolve (EmitContext ec)
275                 {
276                         type = TypeManager.uint32_type;
277                         return this;
278                 }
279
280                 public override bool IsLiteral {
281                         get { return true; }
282                 }
283         }
284         
285         public class LongLiteral : LongConstant {
286                 public LongLiteral (long l, Location loc) : base (l, loc)
287                 {
288                 }
289
290                 public override Expression DoResolve (EmitContext ec)
291                 {
292                         type = TypeManager.int64_type;
293                         return this;
294                 }
295
296                 public override bool IsLiteral {
297                         get { return true; }
298                 }
299         }
300
301         public class ULongLiteral : ULongConstant {
302                 public ULongLiteral (ulong l, Location loc) : base (l, loc)
303                 {
304                 }
305
306                 public override Expression DoResolve (EmitContext ec)
307                 {
308                         type = TypeManager.uint64_type;
309                         return this;
310                 }
311
312                 public override bool IsLiteral {
313                         get { return true; }
314                 }
315         }
316         
317         public class FloatLiteral : FloatConstant {
318                 
319                 public FloatLiteral (float f, Location loc) : base (f, loc)
320                 {
321                 }
322
323                 public override Expression DoResolve (EmitContext ec)
324                 {
325                         type = TypeManager.float_type;
326                         return this;
327                 }
328
329                 public override bool IsLiteral {
330                         get { return true; }
331                 }
332
333         }
334
335         public class DoubleLiteral : DoubleConstant {
336                 public DoubleLiteral (double d, Location loc) : base (d, loc)
337                 {
338                 }
339
340                 public override Expression DoResolve (EmitContext ec)
341                 {
342                         type = TypeManager.double_type;
343
344                         return this;
345                 }
346
347                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
348                 {
349                         if (target == TypeManager.float_type) {
350                                 Error_664 (loc, "float", "f");
351                                 return;
352                         }
353
354                         if (target == TypeManager.decimal_type) {
355                                 Error_664 (loc, "decimal", "m");
356                                 return;
357                         }
358
359                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
360                 }
361
362                 static void Error_664 (Location loc, string type, string suffix)
363                 {
364                         Report.Error (664, loc,
365                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
366                                 type, suffix);
367                 }
368
369                 public override bool IsLiteral {
370                         get { return true; }
371                 }
372
373         }
374
375         public class DecimalLiteral : DecimalConstant {
376                 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
377                 {
378                 }
379
380                 public override Expression DoResolve (EmitContext ec)
381                 {
382                         type = TypeManager.decimal_type;
383                         return this;
384                 }
385
386                 public override bool IsLiteral {
387                         get { return true; }
388                 }
389         }
390
391         public class StringLiteral : StringConstant {
392                 public StringLiteral (string s, Location loc) : base (s, loc)
393                 {
394                 }
395
396                 public override Expression DoResolve (EmitContext ec)
397                 {
398                         type = TypeManager.string_type;
399
400                         return this;
401                 }
402
403                 public override bool IsLiteral {
404                         get { return true; }
405                 }
406
407         }
408 }