2 // conversion.cs: various routines for implementing conversions.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Ravi Pratap (ravi@ximian.com)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
11 namespace Mono
.CSharp
{
13 using System
.Collections
;
14 using System
.Diagnostics
;
15 using System
.Reflection
;
16 using System
.Reflection
.Emit
;
19 // A container class for all the conversion operations
21 public class Convert
{
23 static EmptyExpression MyEmptyExpr
;
24 static public Expression
ImplicitReferenceConversion (Expression expr
, Type target_type
)
26 Type expr_type
= expr
.Type
;
28 if (expr_type
== null && expr
.eclass
== ExprClass
.MethodGroup
){
29 // if we are a method group, emit a warning
34 if (expr_type
== TypeManager
.void_type
)
38 // notice that it is possible to write "ValueType v = 1", the ValueType here
39 // is an abstract class, and not really a value type, so we apply the same rules.
41 if (target_type
== TypeManager
.object_type
) {
43 // A pointer type cannot be converted to object
45 if (expr_type
.IsPointer
)
48 if (expr_type
.IsValueType
)
49 return new BoxedCast (expr
, target_type
);
50 if (expr_type
.IsClass
|| expr_type
.IsInterface
|| expr_type
== TypeManager
.enum_type
){
51 if (expr_type
== TypeManager
.anonymous_method_type
)
53 return new EmptyCast (expr
, target_type
);
57 } else if (target_type
== TypeManager
.value_type
) {
58 if (expr_type
.IsValueType
)
59 return new BoxedCast (expr
, target_type
);
60 if (expr_type
== TypeManager
.null_type
)
61 return new NullCast ((Constant
)expr
, target_type
);
64 } else if (expr_type
.IsSubclassOf (target_type
)) {
66 // Special case: enumeration to System.Enum.
67 // System.Enum is not a value type, it is a class, so we need
68 // a boxing conversion
71 return new BoxedCast (expr
, target_type
);
73 return new EmptyCast (expr
, target_type
);
76 // This code is kind of mirrored inside ImplicitStandardConversionExists
77 // with the small distinction that we only probe there
79 // Always ensure that the code here and there is in sync
81 // from the null type to any reference-type.
82 if (expr_type
== TypeManager
.null_type
){
83 if (target_type
.IsPointer
)
84 return new EmptyCast (NullPointer
.Null
, target_type
);
86 if (!target_type
.IsValueType
) {
88 return new NullCast ((Constant
)expr
, target_type
);
90 // I found only one case when it happens -- Foo () ? null : null;
91 Report
.Warning (-100, 1, expr
.Location
, "The result of the expression is always `null'");
92 return new NullCast (new NullLiteral (expr
.Location
), target_type
);
96 // from any class-type S to any interface-type T.
97 if (target_type
.IsInterface
) {
98 if (target_type
!= TypeManager
.iconvertible_type
&&
99 expr_type
.IsValueType
&& (expr
is Constant
) &&
100 !(expr
is IntLiteral
|| expr
is BoolLiteral
||
101 expr
is FloatLiteral
|| expr
is DoubleLiteral
||
102 expr
is LongLiteral
|| expr
is CharLiteral
||
103 expr
is StringLiteral
|| expr
is DecimalLiteral
||
104 expr
is UIntLiteral
|| expr
is ULongLiteral
)) {
108 if (TypeManager
.ImplementsInterface (expr_type
, target_type
)){
109 if (expr_type
.IsClass
)
110 return new EmptyCast (expr
, target_type
);
111 else if (expr_type
.IsValueType
)
112 return new BoxedCast (expr
, target_type
);
114 return new EmptyCast (expr
, target_type
);
118 // from any interface type S to interface-type T.
119 if (expr_type
.IsInterface
&& target_type
.IsInterface
) {
120 if (TypeManager
.ImplementsInterface (expr_type
, target_type
))
121 return new EmptyCast (expr
, target_type
);
126 // from an array-type S to an array-type of type T
127 if (expr_type
.IsArray
&& target_type
.IsArray
) {
128 if (expr_type
.GetArrayRank () == target_type
.GetArrayRank ()) {
130 Type expr_element_type
= TypeManager
.GetElementType (expr_type
);
132 if (MyEmptyExpr
== null)
133 MyEmptyExpr
= new EmptyExpression ();
135 MyEmptyExpr
.SetType (expr_element_type
);
136 Type target_element_type
= TypeManager
.GetElementType (target_type
);
138 if (!expr_element_type
.IsValueType
&& !target_element_type
.IsValueType
)
139 if (ImplicitStandardConversionExists (MyEmptyExpr
,
140 target_element_type
))
141 return new EmptyCast (expr
, target_type
);
145 // from an array-type to System.Array
146 if (expr_type
.IsArray
&& target_type
== TypeManager
.array_type
)
147 return new EmptyCast (expr
, target_type
);
149 // from any delegate type to System.Delegate
150 if ((expr_type
== TypeManager
.delegate_type
||
151 expr_type
.IsSubclassOf (TypeManager
.delegate_type
)) &&
152 target_type
== TypeManager
.delegate_type
)
153 return new EmptyCast (expr
, target_type
);
155 // from any array-type or delegate type into System.ICloneable.
156 if (expr_type
.IsArray
||
157 expr_type
== TypeManager
.delegate_type
||
158 expr_type
.IsSubclassOf (TypeManager
.delegate_type
))
159 if (target_type
== TypeManager
.icloneable_type
)
160 return new EmptyCast (expr
, target_type
);
166 // Tests whether an implicit reference conversion exists between expr_type
169 static bool ImplicitReferenceConversionExists (Expression expr
, Type target_type
)
171 if (target_type
.IsValueType
)
174 Type expr_type
= expr
.Type
;
177 // This is the boxed case.
179 if (target_type
== TypeManager
.object_type
) {
180 if (expr_type
.IsClass
|| expr_type
.IsValueType
||
181 expr_type
.IsInterface
|| expr_type
== TypeManager
.enum_type
)
182 if (target_type
!= TypeManager
.anonymous_method_type
)
186 } else if (expr_type
.IsSubclassOf (target_type
))
189 // Please remember that all code below actually comes
190 // from ImplicitReferenceConversion so make sure code remains in sync
192 // from any class-type S to any interface-type T.
193 if (target_type
.IsInterface
) {
194 if (target_type
!= TypeManager
.iconvertible_type
&&
195 expr_type
.IsValueType
&& (expr
is Constant
) &&
196 !(expr
is IntLiteral
|| expr
is BoolLiteral
||
197 expr
is FloatLiteral
|| expr
is DoubleLiteral
||
198 expr
is LongLiteral
|| expr
is CharLiteral
||
199 expr
is StringLiteral
|| expr
is DecimalLiteral
||
200 expr
is UIntLiteral
|| expr
is ULongLiteral
)) {
204 if (TypeManager
.ImplementsInterface (expr_type
, target_type
))
208 // from any interface type S to interface-type T.
209 if (expr_type
.IsInterface
&& target_type
.IsInterface
)
210 if (TypeManager
.ImplementsInterface (expr_type
, target_type
))
213 // from an array-type S to an array-type of type T
214 if (expr_type
.IsArray
&& target_type
.IsArray
) {
215 if (expr_type
.GetArrayRank () == target_type
.GetArrayRank ()) {
217 Type expr_element_type
= expr_type
.GetElementType ();
219 if (MyEmptyExpr
== null)
220 MyEmptyExpr
= new EmptyExpression ();
222 MyEmptyExpr
.SetType (expr_element_type
);
223 Type target_element_type
= TypeManager
.GetElementType (target_type
);
225 if (!expr_element_type
.IsValueType
&& !target_element_type
.IsValueType
)
226 if (ImplicitStandardConversionExists (MyEmptyExpr
,
227 target_element_type
))
232 // from an array-type to System.Array
233 if (expr_type
.IsArray
&& (target_type
== TypeManager
.array_type
))
236 // from any delegate type to System.Delegate
237 if ((expr_type
== TypeManager
.delegate_type
||
238 expr_type
.IsSubclassOf (TypeManager
.delegate_type
)) &&
239 target_type
== TypeManager
.delegate_type
)
240 if (target_type
.IsAssignableFrom (expr_type
))
243 // from any array-type or delegate type into System.ICloneable.
244 if (expr_type
.IsArray
||
245 expr_type
== TypeManager
.delegate_type
||
246 expr_type
.IsSubclassOf (TypeManager
.delegate_type
))
247 if (target_type
== TypeManager
.icloneable_type
)
250 // from the null type to any reference-type.
251 if (expr_type
== TypeManager
.null_type
){
252 if (target_type
.IsPointer
)
255 if (!target_type
.IsValueType
)
262 /// Implicit Numeric Conversions.
264 /// expr is the expression to convert, returns a new expression of type
265 /// target_type or null if an implicit conversion is not possible.
267 static public Expression
ImplicitNumericConversion (Expression expr
,
270 Type expr_type
= expr
.Type
;
273 // Attempt to do the implicit constant expression conversions
275 if (expr
is Constant
){
276 if (expr
is IntConstant
){
279 e
= TryImplicitIntConversion (target_type
, (IntConstant
) expr
);
283 } else if (expr
is LongConstant
&& target_type
== TypeManager
.uint64_type
){
285 // Try the implicit constant expression conversion
286 // from long to ulong, instead of a nice routine,
289 long v
= ((LongConstant
) expr
).Value
;
291 return new ULongConstant ((ulong) v
, expr
.Location
);
295 Type real_target_type
= target_type
;
297 if (expr_type
== TypeManager
.sbyte_type
){
299 // From sbyte to short, int, long, float, double, decimal
301 if (real_target_type
== TypeManager
.int32_type
)
302 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I4
);
303 if (real_target_type
== TypeManager
.int64_type
)
304 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
305 if (real_target_type
== TypeManager
.double_type
)
306 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
307 if (real_target_type
== TypeManager
.float_type
)
308 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
309 if (real_target_type
== TypeManager
.short_type
)
310 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I2
);
311 if (real_target_type
== TypeManager
.decimal_type
)
312 return new CastToDecimal (expr
);
313 } else if (expr_type
== TypeManager
.byte_type
){
315 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
317 if ((real_target_type
== TypeManager
.short_type
) ||
318 (real_target_type
== TypeManager
.ushort_type
) ||
319 (real_target_type
== TypeManager
.int32_type
) ||
320 (real_target_type
== TypeManager
.uint32_type
))
321 return new EmptyCast (expr
, target_type
);
323 if (real_target_type
== TypeManager
.uint64_type
)
324 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
325 if (real_target_type
== TypeManager
.int64_type
)
326 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
327 if (real_target_type
== TypeManager
.float_type
)
328 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
329 if (real_target_type
== TypeManager
.double_type
)
330 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
331 if (real_target_type
== TypeManager
.decimal_type
)
332 return new CastToDecimal (expr
);
334 } else if (expr_type
== TypeManager
.short_type
){
336 // From short to int, long, float, double, decimal
338 if (real_target_type
== TypeManager
.int32_type
)
339 return new EmptyCast (expr
, target_type
);
340 if (real_target_type
== TypeManager
.int64_type
)
341 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
342 if (real_target_type
== TypeManager
.double_type
)
343 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
344 if (real_target_type
== TypeManager
.float_type
)
345 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
346 if (real_target_type
== TypeManager
.decimal_type
)
347 return new CastToDecimal (expr
);
349 } else if (expr_type
== TypeManager
.ushort_type
){
351 // From ushort to int, uint, long, ulong, float, double, decimal
353 if (real_target_type
== TypeManager
.uint32_type
)
354 return new EmptyCast (expr
, target_type
);
356 if (real_target_type
== TypeManager
.uint64_type
)
357 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
358 if (real_target_type
== TypeManager
.int32_type
)
359 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I4
);
360 if (real_target_type
== TypeManager
.int64_type
)
361 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
362 if (real_target_type
== TypeManager
.double_type
)
363 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
364 if (real_target_type
== TypeManager
.float_type
)
365 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
366 if (real_target_type
== TypeManager
.decimal_type
)
367 return new CastToDecimal (expr
);
368 } else if (expr_type
== TypeManager
.int32_type
){
370 // From int to long, float, double, decimal
372 if (real_target_type
== TypeManager
.int64_type
)
373 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
374 if (real_target_type
== TypeManager
.double_type
)
375 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
376 if (real_target_type
== TypeManager
.float_type
)
377 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
378 if (real_target_type
== TypeManager
.decimal_type
)
379 return new CastToDecimal (expr
);
380 } else if (expr_type
== TypeManager
.uint32_type
){
382 // From uint to long, ulong, float, double, decimal
384 if (real_target_type
== TypeManager
.int64_type
)
385 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
386 if (real_target_type
== TypeManager
.uint64_type
)
387 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
388 if (real_target_type
== TypeManager
.double_type
)
389 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
,
391 if (real_target_type
== TypeManager
.float_type
)
392 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
,
394 if (real_target_type
== TypeManager
.decimal_type
)
395 return new CastToDecimal (expr
);
396 } else if (expr_type
== TypeManager
.int64_type
){
398 // From long/ulong to float, double
400 if (real_target_type
== TypeManager
.double_type
)
401 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
402 if (real_target_type
== TypeManager
.float_type
)
403 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
404 if (real_target_type
== TypeManager
.decimal_type
)
405 return new CastToDecimal (expr
);
406 } else if (expr_type
== TypeManager
.uint64_type
){
408 // From ulong to float, double
410 if (real_target_type
== TypeManager
.double_type
)
411 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
,
413 if (real_target_type
== TypeManager
.float_type
)
414 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
,
416 if (real_target_type
== TypeManager
.decimal_type
)
417 return new CastToDecimal (expr
);
418 } else if (expr_type
== TypeManager
.char_type
){
420 // From char to ushort, int, uint, long, ulong, float, double, decimal
422 if ((real_target_type
== TypeManager
.ushort_type
) ||
423 (real_target_type
== TypeManager
.int32_type
) ||
424 (real_target_type
== TypeManager
.uint32_type
))
425 return new EmptyCast (expr
, target_type
);
426 if (real_target_type
== TypeManager
.uint64_type
)
427 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
428 if (real_target_type
== TypeManager
.int64_type
)
429 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
430 if (real_target_type
== TypeManager
.float_type
)
431 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
432 if (real_target_type
== TypeManager
.double_type
)
433 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
434 if (real_target_type
== TypeManager
.decimal_type
)
435 return new CastToDecimal (expr
);
436 } else if (expr_type
== TypeManager
.float_type
){
440 if (real_target_type
== TypeManager
.double_type
)
441 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
448 /// Same as ImplicitStandardConversionExists except that it also looks at
449 /// implicit user defined conversions - needed for overload resolution
451 public static bool ImplicitConversionExists (EmitContext ec
, Expression expr
, Type target_type
)
453 if (ImplicitStandardConversionExists (expr
, target_type
))
456 return ImplicitUserConversion (ec
, expr
, target_type
, Location
.Null
) != null;
459 public static bool ImplicitUserConversionExists (EmitContext ec
, Type source
, Type target
)
461 return ImplicitUserConversion (ec
, new EmptyExpression (source
), target
, Location
.Null
) != null;
465 /// Determines if a standard implicit conversion exists from
466 /// expr_type to target_type
468 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
470 public static bool ImplicitStandardConversionExists (Expression expr
, Type target_type
)
472 Type expr_type
= expr
.Type
;
474 if (expr_type
== TypeManager
.void_type
)
477 if (expr_type
== target_type
)
481 // First numeric conversions
483 if (expr_type
== TypeManager
.sbyte_type
){
485 // From sbyte to short, int, long, float, double, decimal
487 if ((target_type
== TypeManager
.int32_type
) ||
488 (target_type
== TypeManager
.int64_type
) ||
489 (target_type
== TypeManager
.double_type
) ||
490 (target_type
== TypeManager
.float_type
) ||
491 (target_type
== TypeManager
.short_type
) ||
492 (target_type
== TypeManager
.decimal_type
))
495 } else if (expr_type
== TypeManager
.byte_type
){
497 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
499 if ((target_type
== TypeManager
.short_type
) ||
500 (target_type
== TypeManager
.ushort_type
) ||
501 (target_type
== TypeManager
.int32_type
) ||
502 (target_type
== TypeManager
.uint32_type
) ||
503 (target_type
== TypeManager
.uint64_type
) ||
504 (target_type
== TypeManager
.int64_type
) ||
505 (target_type
== TypeManager
.float_type
) ||
506 (target_type
== TypeManager
.double_type
) ||
507 (target_type
== TypeManager
.decimal_type
))
510 } else if (expr_type
== TypeManager
.short_type
){
512 // From short to int, long, double, float, decimal
514 if ((target_type
== TypeManager
.int32_type
) ||
515 (target_type
== TypeManager
.int64_type
) ||
516 (target_type
== TypeManager
.double_type
) ||
517 (target_type
== TypeManager
.float_type
) ||
518 (target_type
== TypeManager
.decimal_type
))
521 } else if (expr_type
== TypeManager
.ushort_type
){
523 // From ushort to int, uint, long, ulong, double, float, decimal
525 if ((target_type
== TypeManager
.uint32_type
) ||
526 (target_type
== TypeManager
.uint64_type
) ||
527 (target_type
== TypeManager
.int32_type
) ||
528 (target_type
== TypeManager
.int64_type
) ||
529 (target_type
== TypeManager
.double_type
) ||
530 (target_type
== TypeManager
.float_type
) ||
531 (target_type
== TypeManager
.decimal_type
))
534 } else if (expr_type
== TypeManager
.int32_type
){
536 // From int to long, double, float, decimal
538 if ((target_type
== TypeManager
.int64_type
) ||
539 (target_type
== TypeManager
.double_type
) ||
540 (target_type
== TypeManager
.float_type
) ||
541 (target_type
== TypeManager
.decimal_type
))
544 } else if (expr_type
== TypeManager
.uint32_type
){
546 // From uint to long, ulong, double, float, decimal
548 if ((target_type
== TypeManager
.int64_type
) ||
549 (target_type
== TypeManager
.uint64_type
) ||
550 (target_type
== TypeManager
.double_type
) ||
551 (target_type
== TypeManager
.float_type
) ||
552 (target_type
== TypeManager
.decimal_type
))
555 } else if ((expr_type
== TypeManager
.uint64_type
) ||
556 (expr_type
== TypeManager
.int64_type
)) {
558 // From long/ulong to double, float, decimal
560 if ((target_type
== TypeManager
.double_type
) ||
561 (target_type
== TypeManager
.float_type
) ||
562 (target_type
== TypeManager
.decimal_type
))
565 } else if (expr_type
== TypeManager
.char_type
){
567 // From char to ushort, int, uint, ulong, long, float, double, decimal
569 if ((target_type
== TypeManager
.ushort_type
) ||
570 (target_type
== TypeManager
.int32_type
) ||
571 (target_type
== TypeManager
.uint32_type
) ||
572 (target_type
== TypeManager
.uint64_type
) ||
573 (target_type
== TypeManager
.int64_type
) ||
574 (target_type
== TypeManager
.float_type
) ||
575 (target_type
== TypeManager
.double_type
) ||
576 (target_type
== TypeManager
.decimal_type
))
579 } else if (expr_type
== TypeManager
.float_type
){
583 if (target_type
== TypeManager
.double_type
)
587 if (expr
.eclass
== ExprClass
.MethodGroup
){
588 if (TypeManager
.IsDelegateType (target_type
) && RootContext
.Version
!= LanguageVersion
.ISO_1
){
589 MethodGroupExpr mg
= expr
as MethodGroupExpr
;
591 return DelegateCreation
.ImplicitStandardConversionExists (mg
, target_type
) != null;
596 if (ImplicitReferenceConversionExists (expr
, target_type
))
600 // Implicit Constant Expression Conversions
602 if (expr
is IntConstant
){
603 int value = ((IntConstant
) expr
).Value
;
605 if (target_type
== TypeManager
.sbyte_type
){
606 if (value >= SByte
.MinValue
&& value <= SByte
.MaxValue
)
608 } else if (target_type
== TypeManager
.byte_type
){
609 if (value >= 0 && value <= Byte
.MaxValue
)
611 } else if (target_type
== TypeManager
.short_type
){
612 if (value >= Int16
.MinValue
&& value <= Int16
.MaxValue
)
614 } else if (target_type
== TypeManager
.ushort_type
){
615 if (value >= UInt16
.MinValue
&& value <= UInt16
.MaxValue
)
617 } else if (target_type
== TypeManager
.uint32_type
){
620 } else if (target_type
== TypeManager
.uint64_type
){
622 // we can optimize this case: a positive int32
623 // always fits on a uint64. But we need an opcode
630 if (value == 0 && expr
is IntLiteral
&& TypeManager
.IsEnumType (target_type
))
634 if (expr
is LongConstant
&& target_type
== TypeManager
.uint64_type
){
636 // Try the implicit constant expression conversion
637 // from long to ulong, instead of a nice routine,
640 long v
= ((LongConstant
) expr
).Value
;
645 if ((target_type
== TypeManager
.enum_type
||
646 target_type
.IsSubclassOf (TypeManager
.enum_type
)) &&
648 IntLiteral i
= (IntLiteral
) expr
;
655 // If `expr_type' implements `target_type' (which is an iface)
656 // see TryImplicitIntConversion
658 if (target_type
.IsInterface
&& target_type
.IsAssignableFrom (expr_type
))
661 if (target_type
== TypeManager
.void_ptr_type
&& expr_type
.IsPointer
)
664 if (expr_type
== TypeManager
.anonymous_method_type
){
665 if (!TypeManager
.IsDelegateType (target_type
))
668 AnonymousMethod am
= (AnonymousMethod
) expr
;
669 return am
.ImplicitStandardConversionExists (target_type
);
676 /// Finds "most encompassed type" according to the spec (13.4.2)
677 /// amongst the methods in the MethodGroupExpr
679 static Type
FindMostEncompassedType (ArrayList types
)
683 if (types
.Count
== 0)
686 if (types
.Count
== 1)
687 return (Type
) types
[0];
689 EmptyExpression expr
= EmptyExpression
.Grab ();
691 foreach (Type t
in types
) {
698 if (ImplicitStandardConversionExists (expr
, best
))
703 foreach (Type t
in types
) {
706 if (!ImplicitStandardConversionExists (expr
, t
)) {
712 EmptyExpression
.Release (expr
);
718 /// Finds "most encompassing type" according to the spec (13.4.2)
719 /// amongst the types in the given set
721 static Type
FindMostEncompassingType (ArrayList types
)
725 if (types
.Count
== 0)
728 if (types
.Count
== 1)
729 return (Type
) types
[0];
731 EmptyExpression expr
= EmptyExpression
.Grab ();
733 foreach (Type t
in types
) {
740 if (ImplicitStandardConversionExists (expr
, t
))
744 foreach (Type t
in types
) {
748 if (!ImplicitStandardConversionExists (expr
, best
)) {
754 EmptyExpression
.Release (expr
);
760 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
761 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
762 /// for explicit and implicit conversion operators.
764 static public Type
FindMostSpecificSource (IList list
,
765 Expression source
, bool apply_explicit_conv_rules
)
767 ArrayList src_types_set
= new ArrayList ();
770 // If any operator converts from S then Sx = S
772 Type source_type
= source
.Type
;
773 foreach (MethodBase mb
in list
){
774 ParameterData pd
= TypeManager
.GetParameterData (mb
);
775 Type param_type
= pd
.ParameterType (0);
777 if (param_type
== source_type
)
780 src_types_set
.Add (param_type
);
784 // Explicit Conv rules
786 if (apply_explicit_conv_rules
) {
787 ArrayList candidate_set
= new ArrayList ();
789 foreach (Type param_type
in src_types_set
){
790 if (ImplicitStandardConversionExists (source
, param_type
))
791 candidate_set
.Add (param_type
);
794 if (candidate_set
.Count
!= 0)
795 return FindMostEncompassedType (candidate_set
);
801 if (apply_explicit_conv_rules
)
802 return FindMostEncompassingType (src_types_set
);
804 return FindMostEncompassedType (src_types_set
);
808 /// Finds the most specific target Tx according to section 13.4.4
810 static public Type
FindMostSpecificTarget (IList list
,
811 Type target
, bool apply_explicit_conv_rules
)
813 ArrayList tgt_types_set
= new ArrayList ();
816 // If any operator converts to T then Tx = T
818 foreach (MethodInfo mi
in list
){
819 Type ret_type
= mi
.ReturnType
;
820 if (ret_type
== target
)
823 tgt_types_set
.Add (ret_type
);
827 // Explicit conv rules
829 if (apply_explicit_conv_rules
) {
830 ArrayList candidate_set
= new ArrayList ();
832 EmptyExpression expr
= EmptyExpression
.Grab ();
834 foreach (Type ret_type
in tgt_types_set
){
835 expr
.SetType (ret_type
);
837 if (ImplicitStandardConversionExists (expr
, target
))
838 candidate_set
.Add (ret_type
);
841 EmptyExpression
.Release (expr
);
843 if (candidate_set
.Count
!= 0)
844 return FindMostEncompassingType (candidate_set
);
848 // Okay, final case !
850 if (apply_explicit_conv_rules
)
851 return FindMostEncompassedType (tgt_types_set
);
853 return FindMostEncompassingType (tgt_types_set
);
857 /// User-defined Implicit conversions
859 static public Expression
ImplicitUserConversion (EmitContext ec
, Expression source
,
860 Type target
, Location loc
)
862 return UserDefinedConversion (ec
, source
, target
, loc
, false);
866 /// User-defined Explicit conversions
868 static public Expression
ExplicitUserConversion (EmitContext ec
, Expression source
,
869 Type target
, Location loc
)
871 return UserDefinedConversion (ec
, source
, target
, loc
, true);
874 static void AddConversionOperators (ArrayList list
,
875 Expression source
, Type target_type
,
876 bool look_for_explicit
,
882 Type source_type
= source
.Type
;
883 EmptyExpression expr
= EmptyExpression
.Grab ();
884 foreach (MethodInfo m
in mg
.Methods
) {
885 ParameterData pd
= TypeManager
.GetParameterData (m
);
886 Type return_type
= m
.ReturnType
;
887 Type arg_type
= pd
.ParameterType (0);
889 if (source_type
!= arg_type
) {
890 if (!ImplicitStandardConversionExists (source
, arg_type
)) {
891 if (!look_for_explicit
)
893 expr
.SetType (arg_type
);
894 if (!ImplicitStandardConversionExists (expr
, source_type
))
899 if (target_type
!= return_type
) {
900 expr
.SetType (return_type
);
901 if (!ImplicitStandardConversionExists (expr
, target_type
)) {
902 if (!look_for_explicit
)
904 expr
.SetType (target_type
);
905 if (!ImplicitStandardConversionExists (expr
, return_type
))
913 EmptyExpression
.Release (expr
);
917 /// Compute the user-defined conversion operator from source_type to target_type.
918 /// `look_for_explicit' controls whether we should also include the list of explicit operators
920 static MethodInfo
GetConversionOperator (EmitContext ec
, Expression source
, Type target_type
, bool look_for_explicit
)
922 ArrayList ops
= new ArrayList (4);
924 Type source_type
= source
.Type
;
926 if (source_type
!= TypeManager
.decimal_type
) {
927 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
928 Expression
.MethodLookup (ec
, source_type
, "op_Implicit", Location
.Null
) as MethodGroupExpr
);
929 if (look_for_explicit
) {
930 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
931 Expression
.MethodLookup (
932 ec
, source_type
, "op_Explicit", Location
.Null
) as MethodGroupExpr
);
936 if (target_type
!= TypeManager
.decimal_type
) {
937 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
938 Expression
.MethodLookup (ec
, target_type
, "op_Implicit", Location
.Null
) as MethodGroupExpr
);
939 if (look_for_explicit
) {
940 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
941 Expression
.MethodLookup (
942 ec
, target_type
, "op_Explicit", Location
.Null
) as MethodGroupExpr
);
949 Type most_specific_source
= FindMostSpecificSource (ops
, source
, look_for_explicit
);
950 if (most_specific_source
== null)
953 Type most_specific_target
= FindMostSpecificTarget (ops
, target_type
, look_for_explicit
);
954 if (most_specific_target
== null)
957 MethodInfo method
= null;
959 foreach (MethodInfo m
in ops
) {
960 if (m
.ReturnType
!= most_specific_target
)
962 if (TypeManager
.GetParameterData (m
).ParameterType (0) != most_specific_source
)
964 // Ambiguous: more than one conversion operator satisfies the signature.
973 static DoubleHash explicit_conv
= new DoubleHash (100);
974 static DoubleHash implicit_conv
= new DoubleHash (100);
977 /// User-defined conversions
979 static public Expression
UserDefinedConversion (EmitContext ec
, Expression source
,
980 Type target
, Location loc
,
981 bool look_for_explicit
)
983 Type source_type
= source
.Type
;
984 MethodInfo method
= null;
987 DoubleHash hash
= look_for_explicit
? explicit_conv
: implicit_conv
;
989 if (!(source
is Constant
) && hash
.Lookup (source_type
, target
, out o
)) {
990 method
= (MethodInfo
) o
;
992 method
= GetConversionOperator (ec
, source
, target
, look_for_explicit
);
993 if (!(source
is Constant
))
994 hash
.Insert (source_type
, target
, method
);
1000 Type most_specific_source
= TypeManager
.GetParameterData (method
).ParameterType (0);
1003 // This will do the conversion to the best match that we
1004 // found. Now we need to perform an implict standard conversion
1005 // if the best match was not the type that we were requested
1008 if (look_for_explicit
)
1009 source
= ExplicitConversionStandard (ec
, source
, most_specific_source
, loc
);
1011 source
= ImplicitConversionStandard (ec
, source
, most_specific_source
, loc
);
1017 e
= new UserCast (method
, source
, loc
);
1018 if (e
.Type
!= target
){
1019 if (!look_for_explicit
)
1020 e
= ImplicitConversionStandard (ec
, e
, target
, loc
);
1022 e
= ExplicitConversionStandard (ec
, e
, target
, loc
);
1029 /// Converts implicitly the resolved expression `expr' into the
1030 /// `target_type'. It returns a new expression that can be used
1031 /// in a context that expects a `target_type'.
1033 static public Expression
ImplicitConversion (EmitContext ec
, Expression expr
,
1034 Type target_type
, Location loc
)
1038 if (target_type
== null)
1039 throw new Exception ("Target type is null");
1041 e
= ImplicitConversionStandard (ec
, expr
, target_type
, loc
);
1045 e
= ImplicitUserConversion (ec
, expr
, target_type
, loc
);
1054 /// Attempts to apply the `Standard Implicit
1055 /// Conversion' rules to the expression `expr' into
1056 /// the `target_type'. It returns a new expression
1057 /// that can be used in a context that expects a
1060 /// This is different from `ImplicitConversion' in that the
1061 /// user defined implicit conversions are excluded.
1063 static public Expression
ImplicitConversionStandard (EmitContext ec
, Expression expr
,
1064 Type target_type
, Location loc
)
1066 Type expr_type
= expr
.Type
;
1069 if (expr
.eclass
== ExprClass
.MethodGroup
){
1070 if (!TypeManager
.IsDelegateType (target_type
)){
1075 // Only allow anonymous method conversions on post ISO_1
1077 if (RootContext
.Version
!= LanguageVersion
.ISO_1
){
1078 MethodGroupExpr mg
= expr
as MethodGroupExpr
;
1080 return ImplicitDelegateCreation
.Create (
1081 ec
, mg
, target_type
, loc
);
1085 if (expr_type
== target_type
&& expr_type
!= TypeManager
.null_type
)
1088 e
= ImplicitNumericConversion (expr
, target_type
);
1092 e
= ImplicitReferenceConversion (expr
, target_type
);
1096 if (TypeManager
.IsEnumType (target_type
) && expr
is IntLiteral
){
1097 IntLiteral i
= (IntLiteral
) expr
;
1100 return new EnumConstant ((Constant
) expr
, target_type
);
1104 if (expr_type
.IsPointer
){
1105 if (target_type
== TypeManager
.void_ptr_type
)
1106 return new EmptyCast (expr
, target_type
);
1109 // yep, comparing pointer types cant be done with
1110 // t1 == t2, we have to compare their element types.
1112 if (target_type
.IsPointer
){
1113 if (TypeManager
.GetElementType(target_type
) == TypeManager
.GetElementType(expr_type
))
1120 if (expr_type
== TypeManager
.null_type
&& target_type
.IsPointer
)
1121 return new EmptyCast (NullPointer
.Null
, target_type
);
1124 if (expr_type
== TypeManager
.anonymous_method_type
){
1125 if (!TypeManager
.IsDelegateType (target_type
)){
1126 Report
.Error (1660, loc
,
1127 "Cannot convert anonymous method block to type `{0}' because it is not a delegate type",
1128 TypeManager
.CSharpName (target_type
));
1132 AnonymousMethod am
= (AnonymousMethod
) expr
;
1133 int errors
= Report
.Errors
;
1135 Expression conv
= am
.Compatible (ec
, target_type
);
1140 // We return something instead of null, to avoid
1141 // the duplicate error, since am.Compatible would have
1142 // reported that already
1144 if (errors
!= Report
.Errors
)
1145 return new EmptyCast (expr
, target_type
);
1152 /// Attempts to perform an implicit constant conversion of the IntConstant
1153 /// into a different data type using casts (See Implicit Constant
1154 /// Expression Conversions)
1156 static public Expression
TryImplicitIntConversion (Type target_type
, IntConstant ic
)
1158 int value = ic
.Value
;
1160 if (target_type
== TypeManager
.sbyte_type
){
1161 if (value >= SByte
.MinValue
&& value <= SByte
.MaxValue
)
1162 return new SByteConstant ((sbyte) value, ic
.Location
);
1163 } else if (target_type
== TypeManager
.byte_type
){
1164 if (value >= Byte
.MinValue
&& value <= Byte
.MaxValue
)
1165 return new ByteConstant ((byte) value, ic
.Location
);
1166 } else if (target_type
== TypeManager
.short_type
){
1167 if (value >= Int16
.MinValue
&& value <= Int16
.MaxValue
)
1168 return new ShortConstant ((short) value, ic
.Location
);
1169 } else if (target_type
== TypeManager
.ushort_type
){
1170 if (value >= UInt16
.MinValue
&& value <= UInt16
.MaxValue
)
1171 return new UShortConstant ((ushort) value, ic
.Location
);
1172 } else if (target_type
== TypeManager
.uint32_type
){
1174 return new UIntConstant ((uint) value, ic
.Location
);
1175 } else if (target_type
== TypeManager
.uint64_type
){
1177 // we can optimize this case: a positive int32
1178 // always fits on a uint64. But we need an opcode
1182 return new ULongConstant ((ulong) value, ic
.Location
);
1183 } else if (target_type
== TypeManager
.double_type
)
1184 return new DoubleConstant ((double) value, ic
.Location
);
1185 else if (target_type
== TypeManager
.float_type
)
1186 return new FloatConstant ((float) value, ic
.Location
);
1188 if (value == 0 && ic
is IntLiteral
&& TypeManager
.IsEnumType (target_type
)){
1189 Type underlying
= TypeManager
.EnumToUnderlying (target_type
);
1190 Constant e
= (Constant
) ic
;
1193 // Possibly, we need to create a different 0 literal before passing
1196 if (underlying
== TypeManager
.int64_type
)
1197 e
= new LongLiteral (0, ic
.Location
);
1198 else if (underlying
== TypeManager
.uint64_type
)
1199 e
= new ULongLiteral (0, ic
.Location
);
1201 return new EnumConstant (e
, target_type
);
1205 // If `target_type' is an interface and the type of `ic' implements the interface
1206 // e.g. target_type is IComparable, IConvertible, IFormattable
1208 if (target_type
.IsInterface
&& target_type
.IsAssignableFrom (ic
.Type
))
1209 return new BoxedCast (ic
, target_type
);
1215 /// Attempts to implicitly convert `source' into `target_type', using
1216 /// ImplicitConversion. If there is no implicit conversion, then
1217 /// an error is signaled
1219 static public Expression
ImplicitConversionRequired (EmitContext ec
, Expression source
,
1220 Type target_type
, Location loc
)
1222 Expression e
= ImplicitConversion (ec
, source
, target_type
, loc
);
1226 source
.Error_ValueCannotBeConverted (loc
, target_type
, false);
1231 /// Performs the explicit numeric conversions
1233 public static Expression
ExplicitNumericConversion (Expression expr
, Type target_type
)
1235 Type expr_type
= expr
.Type
;
1236 Type real_target_type
= target_type
;
1238 if (expr_type
== TypeManager
.sbyte_type
){
1240 // From sbyte to byte, ushort, uint, ulong, char
1242 if (real_target_type
== TypeManager
.byte_type
)
1243 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U1
);
1244 if (real_target_type
== TypeManager
.ushort_type
)
1245 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U2
);
1246 if (real_target_type
== TypeManager
.uint32_type
)
1247 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U4
);
1248 if (real_target_type
== TypeManager
.uint64_type
)
1249 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U8
);
1250 if (real_target_type
== TypeManager
.char_type
)
1251 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_CH
);
1252 } else if (expr_type
== TypeManager
.byte_type
){
1254 // From byte to sbyte and char
1256 if (real_target_type
== TypeManager
.sbyte_type
)
1257 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U1_I1
);
1258 if (real_target_type
== TypeManager
.char_type
)
1259 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U1_CH
);
1260 } else if (expr_type
== TypeManager
.short_type
){
1262 // From short to sbyte, byte, ushort, uint, ulong, char
1264 if (real_target_type
== TypeManager
.sbyte_type
)
1265 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_I1
);
1266 if (real_target_type
== TypeManager
.byte_type
)
1267 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U1
);
1268 if (real_target_type
== TypeManager
.ushort_type
)
1269 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U2
);
1270 if (real_target_type
== TypeManager
.uint32_type
)
1271 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U4
);
1272 if (real_target_type
== TypeManager
.uint64_type
)
1273 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U8
);
1274 if (real_target_type
== TypeManager
.char_type
)
1275 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_CH
);
1276 } else if (expr_type
== TypeManager
.ushort_type
){
1278 // From ushort to sbyte, byte, short, char
1280 if (real_target_type
== TypeManager
.sbyte_type
)
1281 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_I1
);
1282 if (real_target_type
== TypeManager
.byte_type
)
1283 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_U1
);
1284 if (real_target_type
== TypeManager
.short_type
)
1285 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_I2
);
1286 if (real_target_type
== TypeManager
.char_type
)
1287 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_CH
);
1288 } else if (expr_type
== TypeManager
.int32_type
){
1290 // From int to sbyte, byte, short, ushort, uint, ulong, char
1292 if (real_target_type
== TypeManager
.sbyte_type
)
1293 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_I1
);
1294 if (real_target_type
== TypeManager
.byte_type
)
1295 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U1
);
1296 if (real_target_type
== TypeManager
.short_type
)
1297 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_I2
);
1298 if (real_target_type
== TypeManager
.ushort_type
)
1299 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U2
);
1300 if (real_target_type
== TypeManager
.uint32_type
)
1301 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U4
);
1302 if (real_target_type
== TypeManager
.uint64_type
)
1303 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U8
);
1304 if (real_target_type
== TypeManager
.char_type
)
1305 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_CH
);
1306 } else if (expr_type
== TypeManager
.uint32_type
){
1308 // From uint to sbyte, byte, short, ushort, int, char
1310 if (real_target_type
== TypeManager
.sbyte_type
)
1311 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I1
);
1312 if (real_target_type
== TypeManager
.byte_type
)
1313 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_U1
);
1314 if (real_target_type
== TypeManager
.short_type
)
1315 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I2
);
1316 if (real_target_type
== TypeManager
.ushort_type
)
1317 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_U2
);
1318 if (real_target_type
== TypeManager
.int32_type
)
1319 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I4
);
1320 if (real_target_type
== TypeManager
.char_type
)
1321 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_CH
);
1322 } else if (expr_type
== TypeManager
.int64_type
){
1324 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1326 if (real_target_type
== TypeManager
.sbyte_type
)
1327 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I1
);
1328 if (real_target_type
== TypeManager
.byte_type
)
1329 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U1
);
1330 if (real_target_type
== TypeManager
.short_type
)
1331 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I2
);
1332 if (real_target_type
== TypeManager
.ushort_type
)
1333 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U2
);
1334 if (real_target_type
== TypeManager
.int32_type
)
1335 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I4
);
1336 if (real_target_type
== TypeManager
.uint32_type
)
1337 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U4
);
1338 if (real_target_type
== TypeManager
.uint64_type
)
1339 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U8
);
1340 if (real_target_type
== TypeManager
.char_type
)
1341 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_CH
);
1342 } else if (expr_type
== TypeManager
.uint64_type
){
1344 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1346 if (real_target_type
== TypeManager
.sbyte_type
)
1347 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I1
);
1348 if (real_target_type
== TypeManager
.byte_type
)
1349 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U1
);
1350 if (real_target_type
== TypeManager
.short_type
)
1351 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I2
);
1352 if (real_target_type
== TypeManager
.ushort_type
)
1353 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U2
);
1354 if (real_target_type
== TypeManager
.int32_type
)
1355 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I4
);
1356 if (real_target_type
== TypeManager
.uint32_type
)
1357 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U4
);
1358 if (real_target_type
== TypeManager
.int64_type
)
1359 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I8
);
1360 if (real_target_type
== TypeManager
.char_type
)
1361 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_CH
);
1362 } else if (expr_type
== TypeManager
.char_type
){
1364 // From char to sbyte, byte, short
1366 if (real_target_type
== TypeManager
.sbyte_type
)
1367 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_I1
);
1368 if (real_target_type
== TypeManager
.byte_type
)
1369 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_U1
);
1370 if (real_target_type
== TypeManager
.short_type
)
1371 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_I2
);
1372 } else if (expr_type
== TypeManager
.float_type
){
1374 // From float to sbyte, byte, short,
1375 // ushort, int, uint, long, ulong, char
1378 if (real_target_type
== TypeManager
.sbyte_type
)
1379 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I1
);
1380 if (real_target_type
== TypeManager
.byte_type
)
1381 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U1
);
1382 if (real_target_type
== TypeManager
.short_type
)
1383 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I2
);
1384 if (real_target_type
== TypeManager
.ushort_type
)
1385 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U2
);
1386 if (real_target_type
== TypeManager
.int32_type
)
1387 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I4
);
1388 if (real_target_type
== TypeManager
.uint32_type
)
1389 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U4
);
1390 if (real_target_type
== TypeManager
.int64_type
)
1391 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I8
);
1392 if (real_target_type
== TypeManager
.uint64_type
)
1393 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U8
);
1394 if (real_target_type
== TypeManager
.char_type
)
1395 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_CH
);
1396 if (real_target_type
== TypeManager
.decimal_type
)
1397 return new CastToDecimal (expr
, true);
1398 } else if (expr_type
== TypeManager
.double_type
){
1400 // From double to sbyte, byte, short,
1401 // ushort, int, uint, long, ulong,
1402 // char, float or decimal
1404 if (real_target_type
== TypeManager
.sbyte_type
)
1405 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I1
);
1406 if (real_target_type
== TypeManager
.byte_type
)
1407 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U1
);
1408 if (real_target_type
== TypeManager
.short_type
)
1409 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I2
);
1410 if (real_target_type
== TypeManager
.ushort_type
)
1411 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U2
);
1412 if (real_target_type
== TypeManager
.int32_type
)
1413 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I4
);
1414 if (real_target_type
== TypeManager
.uint32_type
)
1415 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U4
);
1416 if (real_target_type
== TypeManager
.int64_type
)
1417 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I8
);
1418 if (real_target_type
== TypeManager
.uint64_type
)
1419 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U8
);
1420 if (real_target_type
== TypeManager
.char_type
)
1421 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_CH
);
1422 if (real_target_type
== TypeManager
.float_type
)
1423 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_R4
);
1424 if (real_target_type
== TypeManager
.decimal_type
)
1425 return new CastToDecimal (expr
, true);
1426 } else if (expr_type
== TypeManager
.decimal_type
) {
1427 return new CastFromDecimal (expr
, target_type
).Resolve ();
1433 /// Returns whether an explicit reference conversion can be performed
1434 /// from source_type to target_type
1436 public static bool ExplicitReferenceConversionExists (Type source_type
, Type target_type
)
1438 bool target_is_value_type
= target_type
.IsValueType
;
1440 if (source_type
== target_type
)
1444 // From object to any reference type
1446 if (source_type
== TypeManager
.object_type
&& !target_is_value_type
)
1450 // From any class S to any class-type T, provided S is a base class of T
1452 if (target_type
.IsSubclassOf (source_type
))
1456 // From any interface type S to any interface T provided S is not derived from T
1458 if (source_type
.IsInterface
&& target_type
.IsInterface
){
1459 if (!target_type
.IsSubclassOf (source_type
))
1464 // From any class type S to any interface T, provided S is not sealed
1465 // and provided S does not implement T.
1467 if (target_type
.IsInterface
&& !source_type
.IsSealed
&&
1468 !TypeManager
.ImplementsInterface (source_type
, target_type
))
1472 // From any interface-type S to to any class type T, provided T is not
1473 // sealed, or provided T implements S.
1475 if (source_type
.IsInterface
&&
1476 (!target_type
.IsSealed
|| TypeManager
.ImplementsInterface (target_type
, source_type
)))
1480 // From an array type S with an element type Se to an array type T with an
1481 // element type Te provided all the following are true:
1482 // * S and T differe only in element type, in other words, S and T
1483 // have the same number of dimensions.
1484 // * Both Se and Te are reference types
1485 // * An explicit referenc conversions exist from Se to Te
1487 if (source_type
.IsArray
&& target_type
.IsArray
) {
1488 if (source_type
.GetArrayRank () == target_type
.GetArrayRank ()) {
1490 Type source_element_type
= TypeManager
.GetElementType (source_type
);
1491 Type target_element_type
= TypeManager
.GetElementType (target_type
);
1493 if (!source_element_type
.IsValueType
&& !target_element_type
.IsValueType
)
1494 if (ExplicitReferenceConversionExists (source_element_type
,
1495 target_element_type
))
1501 // From System.Array to any array-type
1502 if (source_type
== TypeManager
.array_type
&&
1503 target_type
.IsArray
){
1508 // From System delegate to any delegate-type
1510 if (source_type
== TypeManager
.delegate_type
&&
1511 target_type
.IsSubclassOf (TypeManager
.delegate_type
))
1515 // From ICloneable to Array or Delegate types
1517 if (source_type
== TypeManager
.icloneable_type
&&
1518 (target_type
== TypeManager
.array_type
||
1519 target_type
== TypeManager
.delegate_type
))
1526 /// Implements Explicit Reference conversions
1528 static Expression
ExplicitReferenceConversion (Expression source
, Type target_type
)
1530 Type source_type
= source
.Type
;
1531 bool target_is_value_type
= target_type
.IsValueType
;
1534 // From object to any reference type
1536 if (source_type
== TypeManager
.object_type
&& !target_is_value_type
)
1537 return new ClassCast (source
, target_type
);
1540 // Unboxing conversion.
1542 if (((source_type
== TypeManager
.enum_type
&&
1543 !(source
is EmptyCast
)) ||
1544 source_type
== TypeManager
.value_type
) && target_is_value_type
)
1545 return new UnboxCast (source
, target_type
);
1548 // From any class S to any class-type T, provided S is a base class of T
1550 if (target_type
.IsSubclassOf (source_type
))
1551 return new ClassCast (source
, target_type
);
1554 // From any interface type S to any interface T provided S is not derived from T
1556 if (source_type
.IsInterface
&& target_type
.IsInterface
){
1557 if (TypeManager
.ImplementsInterface (source_type
, target_type
))
1560 return new ClassCast (source
, target_type
);
1564 // From any class type S to any interface T, provides S is not sealed
1565 // and provided S does not implement T.
1567 if (target_type
.IsInterface
&& !source_type
.IsSealed
) {
1568 if (TypeManager
.ImplementsInterface (source_type
, target_type
))
1571 return new ClassCast (source
, target_type
);
1576 // From any interface-type S to to any class type T, provided T is not
1577 // sealed, or provided T implements S.
1579 if (source_type
.IsInterface
) {
1580 if (!target_type
.IsSealed
|| TypeManager
.ImplementsInterface (target_type
, source_type
)) {
1581 if (target_type
.IsClass
)
1582 return new ClassCast (source
, target_type
);
1584 return new UnboxCast (source
, target_type
);
1590 // From an array type S with an element type Se to an array type T with an
1591 // element type Te provided all the following are true:
1592 // * S and T differe only in element type, in other words, S and T
1593 // have the same number of dimensions.
1594 // * Both Se and Te are reference types
1595 // * An explicit referenc conversions exist from Se to Te
1597 if (source_type
.IsArray
&& target_type
.IsArray
) {
1598 if (source_type
.GetArrayRank () == target_type
.GetArrayRank ()) {
1600 Type source_element_type
= TypeManager
.GetElementType (source_type
);
1601 Type target_element_type
= TypeManager
.GetElementType (target_type
);
1603 if (!source_element_type
.IsValueType
&& !target_element_type
.IsValueType
)
1604 if (ExplicitReferenceConversionExists (source_element_type
,
1605 target_element_type
))
1606 return new ClassCast (source
, target_type
);
1611 // From System.Array to any array-type
1612 if (source_type
== TypeManager
.array_type
&&
1613 target_type
.IsArray
) {
1614 return new ClassCast (source
, target_type
);
1618 // From System delegate to any delegate-type
1620 if (source_type
== TypeManager
.delegate_type
&&
1621 TypeManager
.IsDelegateType (target_type
))
1622 return new ClassCast (source
, target_type
);
1625 // From ICloneable to Array or Delegate types
1627 if (source_type
== TypeManager
.icloneable_type
&&
1628 (target_type
== TypeManager
.array_type
||
1629 target_type
== TypeManager
.delegate_type
))
1630 return new ClassCast (source
, target_type
);
1636 /// Performs an explicit conversion of the expression `expr' whose
1637 /// type is expr.Type to `target_type'.
1639 static public Expression
ExplicitConversionCore (EmitContext ec
, Expression expr
,
1640 Type target_type
, Location loc
)
1642 Type expr_type
= expr
.Type
;
1644 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1645 Expression ne
= ImplicitConversionStandard (ec
, expr
, target_type
, loc
);
1650 // Unboxing conversions; only object types can be convertible to enum
1652 if (expr_type
== TypeManager
.object_type
&& target_type
.IsValueType
|| expr_type
== TypeManager
.enum_type
)
1653 return new UnboxCast (expr
, target_type
);
1655 if (TypeManager
.IsEnumType (expr_type
)) {
1656 if (expr
is EnumConstant
)
1657 return ExplicitConversionCore (ec
, ((EnumConstant
) expr
).Child
, target_type
, loc
);
1659 return ExplicitConversionCore (ec
, new EmptyCast (expr
, TypeManager
.EnumToUnderlying (expr_type
)), target_type
, loc
);
1662 if (TypeManager
.IsEnumType (target_type
)){
1663 Expression ce
= ExplicitConversionCore (ec
, expr
, TypeManager
.EnumToUnderlying (target_type
), loc
);
1665 return new EmptyCast (ce
, target_type
);
1668 ne
= ExplicitNumericConversion (expr
, target_type
);
1673 // Skip the ExplicitReferenceConversion because we can not convert
1674 // from Null to a ValueType, and ExplicitReference wont check against
1675 // null literal explicitly
1677 if (expr_type
!= TypeManager
.null_type
){
1678 ne
= ExplicitReferenceConversion (expr
, target_type
);
1684 ne
= ExplicitUnsafe (expr
, target_type
);
1689 ne
= ExplicitUserConversion (ec
, expr
, target_type
, loc
);
1696 public static Expression
ExplicitUnsafe (Expression expr
, Type target_type
)
1698 Type expr_type
= expr
.Type
;
1700 if (target_type
.IsPointer
){
1701 if (expr_type
.IsPointer
)
1702 return new EmptyCast (expr
, target_type
);
1704 if (expr_type
== TypeManager
.sbyte_type
||
1705 expr_type
== TypeManager
.short_type
||
1706 expr_type
== TypeManager
.int32_type
||
1707 expr_type
== TypeManager
.int64_type
)
1708 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I
);
1710 if (expr_type
== TypeManager
.ushort_type
||
1711 expr_type
== TypeManager
.uint32_type
||
1712 expr_type
== TypeManager
.uint64_type
||
1713 expr_type
== TypeManager
.byte_type
)
1714 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U
);
1717 if (expr_type
.IsPointer
){
1718 if (target_type
== TypeManager
.sbyte_type
)
1719 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I1
);
1720 else if (target_type
== TypeManager
.byte_type
)
1721 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U1
);
1722 else if (target_type
== TypeManager
.short_type
)
1723 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I2
);
1724 else if (target_type
== TypeManager
.ushort_type
)
1725 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U2
);
1726 else if (target_type
== TypeManager
.int32_type
)
1727 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I4
);
1728 else if (target_type
== TypeManager
.uint32_type
)
1729 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U4
);
1730 else if (target_type
== TypeManager
.uint64_type
)
1731 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
1732 else if (target_type
== TypeManager
.int64_type
){
1733 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
1740 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1742 static public Expression
ExplicitConversionStandard (EmitContext ec
, Expression expr
,
1743 Type target_type
, Location l
)
1745 Expression ne
= ImplicitConversionStandard (ec
, expr
, target_type
, l
);
1749 ne
= ExplicitNumericConversion (expr
, target_type
);
1753 ne
= ExplicitReferenceConversion (expr
, target_type
);
1757 if (ec
.InUnsafe
&& expr
.Type
== TypeManager
.void_ptr_type
&& target_type
.IsPointer
)
1758 return new EmptyCast (expr
, target_type
);
1760 expr
.Error_ValueCannotBeConverted (l
, target_type
, true);
1765 /// Performs an explicit conversion of the expression `expr' whose
1766 /// type is expr.Type to `target_type'.
1768 static public Expression
ExplicitConversion (EmitContext ec
, Expression expr
,
1769 Type target_type
, Location loc
)
1771 Expression e
= ExplicitConversionCore (ec
, expr
, target_type
, loc
);
1775 expr
.Error_ValueCannotBeConverted (loc
, target_type
, true);