In corlib/System.Runtime.InteropServices:
[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 // (C) 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 //
27 // I put System.Null just so we do not have to special case it on 
28 // TypeManager.CSharpName
29 //
30 namespace System {
31         //
32         // Represents the Null Type, just used as a placeholder for the type in NullLiteral
33         //
34         public class Null {
35         }
36 }
37         
38 namespace Mono.CSharp {
39
40         //
41         // The NullType just exists to compare type equality, and for
42         // expressions that might have the `null type'
43         //
44         public class NullType {
45         }
46
47
48         public class NullConstant : Constant
49         {
50                 public NullConstant (Location loc):
51                         base (loc)
52                 {
53                         eclass = ExprClass.Value;
54                         type = TypeManager.null_type;
55                 }
56                 
57                 override public string AsString ()
58                 {
59                         return "null";
60                 }
61
62                 public override object GetValue ()
63                 {
64                         return null;
65                 }
66
67                 public override void Emit (EmitContext ec)
68                 {
69                         ec.ig.Emit(OpCodes.Ldnull);
70                 }
71
72                 public override string GetSignatureForError ()
73                 {
74                         return "null";
75                 }
76
77                 public override Constant Increment ()
78                 {
79                         throw new NotSupportedException ();
80                 }
81
82                 public override bool IsDefaultValue 
83                 {
84                         get { return true; }
85                 }
86
87                 public override bool IsNegative 
88                 {
89                         get { return false; }
90                 }
91
92                 public override bool IsZeroInteger 
93                 {
94                         get { return true; }
95                 }
96
97                 public override Constant ConvertExplicitly(bool inCheckedContext, Type target_type)
98                 {
99                         if (!TypeManager.IsValueType (target_type))
100                                 return new EmptyConstantCast (this, target_type);
101
102                         return null;
103                 }
104
105                 public override Constant ConvertImplicitly (Type targetType)
106                 {
107                         if (!TypeManager.IsValueType (targetType))
108                                 return new EmptyConstantCast (this, targetType);
109
110                         return null;
111                 }
112         }
113
114         //
115         // Represents default(X) when result can be reduced to null
116         //
117         public class NullDefault : EmptyConstantCast
118         {
119                 public NullDefault(Constant value, Type type)
120                         : base (value, type)
121                 {
122                 }
123
124                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
125                 {
126                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
127                 }
128         }
129
130         //
131         // The null Literal constant
132         //
133         public class NullLiteral : NullConstant {
134                 public NullLiteral (Location loc):
135                         base (loc)
136                 {
137                 }
138
139                 public override Expression DoResolve (EmitContext ec)
140                 {
141                         type = TypeManager.null_type;
142                         return this;
143                 }
144
145                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
146                 {
147                         if (TypeManager.IsGenericParameter (t)) {
148                                 Report.Error(403, loc,
149                                         "Cannot convert null to the type parameter `{0}' because it could be a value " +
150                                         "type. Consider using `default ({0})' instead", t.Name);
151                         } else {
152                                 Report.Error(37, loc, "Cannot convert null to `{0}' because it is a value type",
153                                         TypeManager.CSharpName(t));
154                         }
155                 }
156
157                 public override Constant ConvertImplicitly (Type targetType)
158                 {
159                         if (targetType.IsPointer)
160                                 return new EmptyConstantCast (NullPointer.Null, targetType);
161
162                         if (TypeManager.IsGenericParameter(targetType)) {
163                                 GenericConstraints gc = null;
164
165 #if GMCS_SOURCE
166                                 gc = TypeManager.GetTypeParameterConstraints(targetType);
167 #endif
168                                 if (gc != null && gc.IsReferenceType)
169                                         return new EmptyConstantCast (this, targetType);
170
171                                 return null;
172                         }
173
174                         return base.ConvertImplicitly(targetType);
175                 }
176
177         }
178
179         //
180         // A null literal in a pointer context
181         //
182         public class NullPointer : NullLiteral {
183                 public static readonly NullLiteral Null;
184
185                 static NullPointer ()
186                 {
187                         Null = new NullPointer ();
188                 }
189
190                 private NullPointer ():
191                         base (Location.Null)
192                 {
193                         type = TypeManager.object_type;
194                 }
195
196                 public override void Emit (EmitContext ec)
197                 {
198                         ILGenerator ig = ec.ig;
199                                 
200                         // TODO: why not use Ldnull instead ?
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
218         public class CharLiteral : CharConstant {
219                 public CharLiteral (char c, Location loc) : base (c, loc)
220                 {
221                 }
222
223                 public override Expression DoResolve (EmitContext ec)
224                 {
225                         type = TypeManager.char_type;
226                         return this;
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.EnumToUnderlying (type));
248                                 if (c == null)
249                                         return null;
250
251                                 return new EnumConstant (c, type);
252                         }
253                         return base.ConvertImplicitly (type);
254                 }
255
256         }
257
258         public class UIntLiteral : UIntConstant {
259                 public UIntLiteral (uint l, Location loc) : base (l, loc)
260                 {
261                 }
262
263                 public override Expression DoResolve (EmitContext ec)
264                 {
265                         type = TypeManager.uint32_type;
266                         return this;
267                 }
268         }
269         
270         public class LongLiteral : LongConstant {
271                 public LongLiteral (long l, Location loc) : base (l, loc)
272                 {
273                 }
274
275                 public override Expression DoResolve (EmitContext ec)
276                 {
277                         type = TypeManager.int64_type;
278
279                         return this;
280                 }
281         }
282
283         public class ULongLiteral : ULongConstant {
284                 public ULongLiteral (ulong l, Location loc) : base (l, loc)
285                 {
286                 }
287
288                 public override Expression DoResolve (EmitContext ec)
289                 {
290                         type = TypeManager.uint64_type;
291                         return this;
292                 }
293         }
294         
295         public class FloatLiteral : FloatConstant {
296                 
297                 public FloatLiteral (float f, Location loc) : base (f, loc)
298                 {
299                 }
300
301                 public override Expression DoResolve (EmitContext ec)
302                 {
303                         type = TypeManager.float_type;
304                         return this;
305                 }
306         }
307
308         public class DoubleLiteral : DoubleConstant {
309                 public DoubleLiteral (double d, Location loc) : base (d, loc)
310                 {
311                 }
312
313                 public override Expression DoResolve (EmitContext ec)
314                 {
315                         type = TypeManager.double_type;
316
317                         return this;
318                 }
319
320                 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
321                 {
322                         if (target == TypeManager.float_type) {
323                                 Error_664 (loc, "float", "f");
324                                 return;
325                         }
326
327                         if (target == TypeManager.decimal_type) {
328                                 Error_664 (loc, "decimal", "m");
329                                 return;
330                         }
331
332                         base.Error_ValueCannotBeConverted (ec, loc, target, expl);
333                 }
334
335                 static void Error_664 (Location loc, string type, string suffix)
336                 {
337                         Report.Error (664, loc,
338                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
339                                 type, suffix);
340                 }
341         }
342
343         public class DecimalLiteral : DecimalConstant {
344                 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
345                 {
346                 }
347
348                 public override Expression DoResolve (EmitContext ec)
349                 {
350                         type = TypeManager.decimal_type;
351                         return this;
352                 }
353         }
354
355         public class StringLiteral : StringConstant {
356                 public StringLiteral (string s, Location loc) : base (s, loc)
357                 {
358                 }
359
360                 public override Expression DoResolve (EmitContext ec)
361                 {
362                         type = TypeManager.string_type;
363
364                         return this;
365                 }
366         }
367 }