2 // literal.cs: Literal representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001 Ximian, Inc.
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).
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.
23 using System.Reflection;
24 using System.Reflection.Emit;
26 namespace Mono.CSharp {
31 // Note: C# specification null-literal is NullLiteral of NullType type
33 class NullLiteral : Constant
36 // Default type of null is an object
38 public NullLiteral (Location loc):
39 this (typeof (NullLiteral), loc)
44 // Null can have its own type, think of default (Foo)
46 public NullLiteral (Type type, Location loc)
49 eclass = ExprClass.Value;
53 override public string AsString ()
55 return GetSignatureForError ();
58 public override Expression CreateExpressionTree (EmitContext ec)
60 // HACK: avoid referencing mcs internal type
61 if (type == typeof (NullLiteral))
62 type = TypeManager.object_type;
64 return base.CreateExpressionTree (ec);
67 public override Expression DoResolve (EmitContext ec)
72 public override void Emit (EmitContext ec)
74 ec.ig.Emit (OpCodes.Ldnull);
77 // Only to make verifier happy
78 if (TypeManager.IsGenericParameter (type))
79 ec.ig.Emit (OpCodes.Unbox_Any, type);
83 public override string ExprClassName {
85 return GetSignatureForError ();
89 public override string GetSignatureForError ()
94 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
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);
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));
109 base.Error_ValueCannotBeConverted (ec, loc, t, expl);
112 public override Constant ConvertExplicitly (bool inCheckedContext, Type targetType)
114 if (targetType.IsPointer) {
115 if (type == TypeManager.null_type || this is NullPointer)
116 return new EmptyConstantCast (new NullPointer (loc), targetType);
121 // Exlude internal compiler types
122 if (targetType == InternalType.AnonymousMethod)
125 if (type != TypeManager.null_type && !Convert.ImplicitStandardConversionExists (this, targetType))
128 if (TypeManager.IsReferenceType (targetType))
129 return new NullLiteral (targetType, loc);
131 if (TypeManager.IsNullableType (targetType))
132 return Nullable.LiftedNull.Create (targetType, loc);
137 public override Constant ConvertImplicitly (Type targetType)
140 // Null literal is of object type
142 if (targetType == TypeManager.object_type)
145 return ConvertExplicitly (false, targetType);
148 public override object GetValue ()
153 public override Constant Increment ()
155 throw new NotSupportedException ();
158 public override bool IsDefaultValue {
162 public override bool IsLiteral {
166 public override bool IsNegative {
167 get { return false; }
170 public override bool IsNull {
174 public override bool IsZeroInteger {
178 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
180 type = storey.MutateType (type);
185 // A null literal in a pointer context
187 class NullPointer : NullLiteral {
188 public NullPointer (Location loc):
191 type = TypeManager.object_type;
194 public override void Emit (EmitContext ec)
196 ILGenerator ig = ec.ig;
199 // Emits null pointer
201 ig.Emit (OpCodes.Ldc_I4_0);
202 ig.Emit (OpCodes.Conv_U);
206 public class BoolLiteral : BoolConstant {
207 public BoolLiteral (bool val, Location loc) : base (val, loc)
211 public override Expression DoResolve (EmitContext ec)
213 type = TypeManager.bool_type;
217 public override bool IsLiteral {
222 public class CharLiteral : CharConstant {
223 public CharLiteral (char c, Location loc) : base (c, loc)
227 public override Expression DoResolve (EmitContext ec)
229 type = TypeManager.char_type;
233 public override bool IsLiteral {
238 public class IntLiteral : IntConstant {
239 public IntLiteral (int l, Location loc) : base (l, loc)
243 public override Expression DoResolve (EmitContext ec)
245 type = TypeManager.int32_type;
249 public override Constant ConvertImplicitly (Type type)
252 /// The 0 literal can be converted to an enum value,
254 if (Value == 0 && TypeManager.IsEnumType (type)) {
255 Constant c = ConvertImplicitly (TypeManager.GetEnumUnderlyingType (type));
259 return new EnumConstant (c, type);
261 return base.ConvertImplicitly (type);
264 public override bool IsLiteral {
269 public class UIntLiteral : UIntConstant {
270 public UIntLiteral (uint l, Location loc) : base (l, loc)
274 public override Expression DoResolve (EmitContext ec)
276 type = TypeManager.uint32_type;
280 public override bool IsLiteral {
285 public class LongLiteral : LongConstant {
286 public LongLiteral (long l, Location loc) : base (l, loc)
290 public override Expression DoResolve (EmitContext ec)
292 type = TypeManager.int64_type;
296 public override bool IsLiteral {
301 public class ULongLiteral : ULongConstant {
302 public ULongLiteral (ulong l, Location loc) : base (l, loc)
306 public override Expression DoResolve (EmitContext ec)
308 type = TypeManager.uint64_type;
312 public override bool IsLiteral {
317 public class FloatLiteral : FloatConstant {
319 public FloatLiteral (float f, Location loc) : base (f, loc)
323 public override Expression DoResolve (EmitContext ec)
325 type = TypeManager.float_type;
329 public override bool IsLiteral {
335 public class DoubleLiteral : DoubleConstant {
336 public DoubleLiteral (double d, Location loc) : base (d, loc)
340 public override Expression DoResolve (EmitContext ec)
342 type = TypeManager.double_type;
347 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
349 if (target == TypeManager.float_type) {
350 Error_664 (loc, "float", "f");
354 if (target == TypeManager.decimal_type) {
355 Error_664 (loc, "decimal", "m");
359 base.Error_ValueCannotBeConverted (ec, loc, target, expl);
362 static void Error_664 (Location loc, string type, string suffix)
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",
369 public override bool IsLiteral {
375 public class DecimalLiteral : DecimalConstant {
376 public DecimalLiteral (decimal d, Location loc) : base (d, loc)
380 public override Expression DoResolve (EmitContext ec)
382 type = TypeManager.decimal_type;
386 public override bool IsLiteral {
391 public class StringLiteral : StringConstant {
392 public StringLiteral (string s, Location loc) : base (s, loc)
396 public override Expression DoResolve (EmitContext ec)
398 type = TypeManager.string_type;
403 public override bool IsLiteral {