New test.
[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 == TypeManager.anonymous_method_type)
123                                 return null;
124
125                         if (TypeManager.IsReferenceType (targetType))
126                                 return new NullLiteral (targetType, loc);
127
128                         if (TypeManager.IsNullableType (targetType))
129                                 return Nullable.LiftedNull.Create (targetType, loc);
130
131                         return null;
132                 }
133
134                 public override Constant ConvertImplicitly (Type targetType)
135                 {
136                         //
137                         // Null literal is of object type
138                         //
139                         if (targetType == TypeManager.object_type)
140                                 return this;
141
142                         return ConvertExplicitly (false, targetType);
143                 }
144
145                 public override object GetValue ()
146                 {
147                         return null;
148                 }
149
150                 public override Constant Increment ()
151                 {
152                         throw new NotSupportedException ();
153                 }
154
155                 public override bool IsDefaultValue {
156                         get { return true; }
157                 }
158
159                 public override bool IsLiteral {
160                         get { return true; }
161                 }
162
163                 public override bool IsNegative {
164                         get { return false; }
165                 }
166
167                 public override bool IsNull {
168                         get { return true; }
169                 }
170
171                 public override bool IsZeroInteger {
172                         get { return true; }
173                 }
174         }
175
176         //
177         // A null literal in a pointer context
178         //
179         class NullPointer : NullLiteral {
180                 public NullPointer (Location loc):
181                         base (loc)
182                 {
183                         type = TypeManager.object_type;
184                 }
185
186                 public override void Emit (EmitContext ec)
187                 {
188                         ILGenerator ig = ec.ig;
189                                 
190                         //
191                         // Emits null pointer
192                         //
193                         ig.Emit (OpCodes.Ldc_I4_0);
194                         ig.Emit (OpCodes.Conv_U);
195                 }
196         }
197
198         public class BoolLiteral : BoolConstant {
199                 public BoolLiteral (bool val, Location loc) : base (val, loc)
200                 {
201                 }
202
203                 public override Expression DoResolve (EmitContext ec)
204                 {
205                         type = TypeManager.bool_type;
206                         return this;
207                 }
208
209                 public override bool IsLiteral {
210                         get { return true; }
211                 }
212         }
213
214         public class CharLiteral : CharConstant {
215                 public CharLiteral (char c, Location loc) : base (c, loc)
216                 {
217                 }
218
219                 public override Expression DoResolve (EmitContext ec)
220                 {
221                         type = TypeManager.char_type;
222                         return this;
223                 }
224
225                 public override bool IsLiteral {
226                         get { return true; }
227                 }
228         }
229
230         public class IntLiteral : IntConstant {
231                 public IntLiteral (int l, Location loc) : base (l, loc)
232                 {
233                 }
234
235                 public override Expression DoResolve (EmitContext ec)
236                 {
237                         type = TypeManager.int32_type;
238                         return this;
239                 }
240
241                 public override Constant ConvertImplicitly (Type type)
242                 {
243                         ///
244                         /// The 0 literal can be converted to an enum value,
245                         ///
246                         if (Value == 0 && TypeManager.IsEnumType (type)) {
247                                 Constant c = ConvertImplicitly (TypeManager.GetEnumUnderlyingType (type));
248                                 if (c == null)
249                                         return null;
250
251                                 return new EnumConstant (c, type);
252                         }
253                         return base.ConvertImplicitly (type);
254                 }
255
256                 public override bool IsLiteral {
257                         get { return true; }
258                 }
259         }
260
261         public class UIntLiteral : UIntConstant {
262                 public UIntLiteral (uint l, Location loc) : base (l, loc)
263                 {
264                 }
265
266                 public override Expression DoResolve (EmitContext ec)
267                 {
268                         type = TypeManager.uint32_type;
269                         return this;
270                 }
271
272                 public override bool IsLiteral {
273                         get { return true; }
274                 }
275         }
276         
277         public class LongLiteral : LongConstant {
278                 public LongLiteral (long l, Location loc) : base (l, loc)
279                 {
280                 }
281
282                 public override Expression DoResolve (EmitContext ec)
283                 {
284                         type = TypeManager.int64_type;
285                         return this;
286                 }
287
288                 public override bool IsLiteral {
289                         get { return true; }
290                 }
291         }
292
293         public class ULongLiteral : ULongConstant {
294                 public ULongLiteral (ulong l, Location loc) : base (l, loc)
295                 {
296                 }
297
298                 public override Expression DoResolve (EmitContext ec)
299                 {
300                         type = TypeManager.uint64_type;
301                         return this;
302                 }
303
304                 public override bool IsLiteral {
305                         get { return true; }
306                 }
307         }
308         
309         public class FloatLiteral : FloatConstant {
310                 
311                 public FloatLiteral (float f, Location loc) : base (f, loc)
312                 {
313                 }
314
315                 public override Expression DoResolve (EmitContext ec)
316                 {
317                         type = TypeManager.float_type;
318                         return this;
319                 }
320
321                 public override bool IsLiteral {
322                         get { return true; }
323                 }
324
325         }
326
327         public class DoubleLiteral : DoubleConstant {
328                 public DoubleLiteral (double d, Location loc) : base (d, loc)
329                 {
330                 }
331
332                 public override Expression DoResolve (EmitContext ec)
333                 {
334                         type = TypeManager.double_type;
335
336                         return this;
337                 }
338
339                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
340                 {
341                         if (target == TypeManager.float_type) {
342                                 Error_664 (loc, "float", "f");
343                                 return;
344                         }
345
346                         if (target == TypeManager.decimal_type) {
347                                 Error_664 (loc, "decimal", "m");
348                                 return;
349                         }
350
351                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
352                 }
353
354                 static void Error_664 (Location loc, string type, string suffix)
355                 {
356                         Report.Error (664, loc,
357                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
358                                 type, suffix);
359                 }
360
361                 public override bool IsLiteral {
362                         get { return true; }
363                 }
364
365         }
366
367         public class DecimalLiteral : DecimalConstant {
368                 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
369                 {
370                 }
371
372                 public override Expression DoResolve (EmitContext ec)
373                 {
374                         type = TypeManager.decimal_type;
375                         return this;
376                 }
377
378                 public override bool IsLiteral {
379                         get { return true; }
380                 }
381         }
382
383         public class StringLiteral : StringConstant {
384                 public StringLiteral (string s, Location loc) : base (s, loc)
385                 {
386                 }
387
388                 public override Expression DoResolve (EmitContext ec)
389                 {
390                         type = TypeManager.string_type;
391
392                         return this;
393                 }
394
395                 public override bool IsLiteral {
396                         get { return true; }
397                 }
398
399         }
400 }