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
{