2 // conversion.cs: various routines for implementing conversions.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Ravi Pratap (ravi@ximian.com)
7 // Marek Safar (marek.safar@gmail.com)
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
21 // A container class for all the conversion operations
23 public class Convert {
25 static bool TypeParameter_to_Null (Type target_type)
27 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
31 if (gc.HasReferenceTypeConstraint)
33 if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
39 static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
41 ArrayList list = new ArrayList ();
42 list.Add (gc.EffectiveBaseClass);
43 foreach (Type t in gc.InterfaceConstraints) {
44 if (!TypeManager.IsGenericParameter (t))
47 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
49 list.Add (TypeParam_EffectiveBaseType (new_gc));
51 return FindMostEncompassedType (list);
56 // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
57 // interfaces of this interface, provided there is an implicit reference conversion
60 static bool Array_To_IList (Type array, Type list, bool isExplicit)
63 if ((array.GetArrayRank () != 1) || !list.IsGenericType)
66 Type gt = list.GetGenericTypeDefinition ();
67 if ((gt != TypeManager.generic_ilist_type) &&
68 (gt != TypeManager.generic_icollection_type) &&
69 (gt != TypeManager.generic_ienumerable_type))
72 Type element_type = TypeManager.GetElementType (array);
73 Type arg_type = TypeManager.GetTypeArguments (list) [0];
75 if (element_type == arg_type)
79 return ExplicitReferenceConversionExists (element_type, arg_type);
81 if (MyEmptyExpr == null)
82 MyEmptyExpr = new EmptyExpression ();
83 MyEmptyExpr.SetType (TypeManager.GetElementType (array));
85 return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
91 static bool IList_To_Array(Type list, Type array)
94 if (!list.IsGenericType || !array.IsArray || array.GetArrayRank() != 1)
97 Type gt = list.GetGenericTypeDefinition();
98 if (gt != TypeManager.generic_ilist_type &&
99 gt != TypeManager.generic_icollection_type &&
100 gt != TypeManager.generic_ienumerable_type)
103 Type arg_type = TypeManager.GetTypeArguments(list)[0];
104 Type element_type = TypeManager.GetElementType(array);
106 if (element_type == arg_type)
109 if (MyEmptyExpr == null)
110 MyEmptyExpr = new EmptyExpression();
111 MyEmptyExpr.SetType(element_type);
112 return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type);
118 static Expression ImplicitTypeParameterConversion (Expression expr,
122 Type expr_type = expr.Type;
124 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
127 if (target_type == TypeManager.object_type)
128 return new BoxedCast (expr, target_type);
133 // We're converting from a type parameter which is known to be a reference type.
134 Type base_type = TypeParam_EffectiveBaseType (gc);
136 if (TypeManager.IsSubclassOf (base_type, target_type))
137 return new ClassCast (expr, target_type);
139 if (target_type.IsInterface) {
140 if (TypeManager.ImplementsInterface (base_type, target_type))
141 return new ClassCast (expr, target_type);
143 foreach (Type t in gc.InterfaceConstraints) {
144 if (TypeManager.IsSubclassOf (t, target_type))
145 return new ClassCast (expr, target_type);
146 if (TypeManager.ImplementsInterface (t, target_type))
147 return new ClassCast (expr, target_type);
151 foreach (Type t in gc.InterfaceConstraints) {
152 if (!TypeManager.IsGenericParameter (t))
154 if (TypeManager.IsSubclassOf (t, target_type))
155 return new ClassCast (expr, target_type);
156 if (TypeManager.ImplementsInterface (t, target_type))
157 return new ClassCast (expr, target_type);
163 static bool ImplicitTypeParameterBoxingConversion (Type expr_type, Type target_type,
164 out bool use_class_cast)
167 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
170 use_class_cast = false;
171 return target_type == TypeManager.object_type;
174 use_class_cast = true;
176 if (!gc.HasReferenceTypeConstraint)
179 // We're converting from a type parameter which is known to be a reference type.
180 Type base_type = TypeParam_EffectiveBaseType (gc);
182 if (TypeManager.IsSubclassOf (base_type, target_type))
185 if (target_type.IsInterface) {
186 if (TypeManager.ImplementsInterface (base_type, target_type))
189 foreach (Type t in gc.InterfaceConstraints) {
190 if (TypeManager.IsSubclassOf (t, target_type))
192 if (TypeManager.ImplementsInterface (t, target_type))
197 foreach (Type t in gc.InterfaceConstraints) {
198 if (!TypeManager.IsGenericParameter (t))
200 if (TypeManager.IsSubclassOf (t, target_type))
202 if (TypeManager.ImplementsInterface (t, target_type))
207 use_class_cast = false;
211 static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type)
214 if (TypeManager.IsGenericParameter (target_type)) {
215 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
219 foreach (Type iface in gc.InterfaceConstraints) {
220 if (!TypeManager.IsGenericParameter (iface))
223 if (TypeManager.IsSubclassOf (source_type, iface))
224 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
228 if (target_type.IsInterface)
229 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
234 static EmptyExpression MyEmptyExpr;
235 static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast)
237 Type expr_type = expr.Type;
239 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
240 // if we are a method group, emit a warning
245 if (expr_type == TypeManager.void_type)
248 if (TypeManager.IsGenericParameter (expr_type))
249 return ImplicitTypeParameterConversion (expr, target_type);
252 // from the null type to any reference-type.
254 NullLiteral nl = expr as NullLiteral;
256 return nl.ConvertImplicitly(target_type);
259 if (ImplicitReferenceConversionExists (expr, target_type)) {
261 // Reduce implicit reference conversion to object
263 if (!explicit_cast && target_type == TypeManager.object_type)
266 return EmptyCast.Create (expr, target_type);
270 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) {
272 return new ClassCast (expr, target_type);
274 return new BoxedCast (expr, target_type);
281 // 6.1.6 Implicit reference conversions
283 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
285 if (target_type.IsValueType)
288 Type expr_type = expr.Type;
290 // from the null type to any reference-type.
291 if (expr_type == TypeManager.null_type)
292 return target_type != TypeManager.anonymous_method_type;
294 if (TypeManager.IsGenericParameter (expr_type))
295 return ImplicitTypeParameterConversion (expr, target_type) != null;
298 // notice that it is possible to write "ValueType v = 1", the ValueType here
299 // is an abstract class, and not really a value type, so we apply the same rules.
301 if (target_type == TypeManager.object_type) {
303 // A pointer type cannot be converted to object
305 if (expr_type.IsPointer)
308 if (TypeManager.IsValueType (expr_type))
310 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
311 return expr_type != TypeManager.anonymous_method_type;
315 } else if (target_type == TypeManager.value_type) {
316 return expr_type == TypeManager.enum_type;
317 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
319 // Special case: enumeration to System.Enum.
320 // System.Enum is not a value type, it is a class, so we need
321 // a boxing conversion
323 if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type))
329 // This code is kind of mirrored inside ImplicitStandardConversionExists
330 // with the small distinction that we only probe there
332 // Always ensure that the code here and there is in sync
334 // from any class-type S to any interface-type T.
335 if (target_type.IsInterface) {
336 if (TypeManager.ImplementsInterface (expr_type, target_type)){
337 return !TypeManager.IsGenericParameter (expr_type) &&
338 !TypeManager.IsValueType (expr_type);
342 if (expr_type.IsArray) {
343 // from an array-type S to an array-type of type T
344 if (target_type.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
347 // Both SE and TE are reference-types
349 Type expr_element_type = TypeManager.GetElementType (expr_type);
350 if (!TypeManager.IsReferenceType (expr_element_type))
353 Type target_element_type = TypeManager.GetElementType (target_type);
354 if (!TypeManager.IsReferenceType (target_element_type))
357 if (MyEmptyExpr == null)
358 MyEmptyExpr = new EmptyExpression ();
360 MyEmptyExpr.SetType (expr_element_type);
362 return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type);
365 // from an array-type to System.Array
366 if (target_type == TypeManager.array_type)
369 // from an array-type of type T to IList<T>
370 if (Array_To_IList (expr_type, target_type, false))
376 // from any interface type S to interface-type T.
377 if (expr_type.IsInterface && target_type.IsInterface) {
378 return TypeManager.ImplementsInterface (expr_type, target_type);
381 // from any delegate type to System.Delegate
382 if (target_type == TypeManager.delegate_type &&
383 (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)))
386 // from a generic type definition to a generic instance.
387 if (TypeManager.IsEqual (expr_type, target_type))
393 static public bool ImplicitBoxingConversionExists (Expression expr, Type target_type,
394 out bool use_class_cast)
396 Type expr_type = expr.Type;
397 use_class_cast = false;
400 // From any value-type to the type object.
402 if (target_type == TypeManager.object_type) {
404 // A pointer type cannot be converted to object
406 if (expr_type.IsPointer)
409 return TypeManager.IsValueType (expr_type);
413 // From any value-type to the type System.ValueType.
415 if (target_type == TypeManager.value_type)
416 return TypeManager.IsValueType (expr_type);
418 if (target_type == TypeManager.enum_type) {
420 // From any enum-type to the type System.Enum.
422 if (expr_type.IsEnum)
425 // From any nullable-type with an underlying enum-type to the type System.Enum
427 if (TypeManager.IsNullableType (expr_type))
428 return TypeManager.GetTypeArguments (expr_type) [0].IsEnum;
431 if (TypeManager.IsSubclassOf (expr_type, target_type)) {
433 // Don't box same type arguments
435 if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type)
441 // This code is kind of mirrored inside ImplicitStandardConversionExists
442 // with the small distinction that we only probe there
444 // Always ensure that the code here and there is in sync
446 // from any class-type S to any interface-type T.
447 if (target_type.IsInterface) {
448 if (TypeManager.ImplementsInterface (expr_type, target_type))
449 return TypeManager.IsGenericParameter (expr_type) ||
450 TypeManager.IsValueType (expr_type);
453 if (TypeManager.IsGenericParameter (expr_type))
454 return ImplicitTypeParameterBoxingConversion (
455 expr_type, target_type, out use_class_cast);
461 /// Implicit Numeric Conversions.
463 /// expr is the expression to convert, returns a new expression of type
464 /// target_type or null if an implicit conversion is not possible.
466 static public Expression ImplicitNumericConversion (Expression expr,
469 Type expr_type = expr.Type;
470 Type real_target_type = target_type;
472 if (expr_type == TypeManager.sbyte_type){
474 // From sbyte to short, int, long, float, double, decimal
476 if (real_target_type == TypeManager.int32_type)
477 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
478 if (real_target_type == TypeManager.int64_type)
479 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
480 if (real_target_type == TypeManager.double_type)
481 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
482 if (real_target_type == TypeManager.float_type)
483 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
484 if (real_target_type == TypeManager.short_type)
485 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
486 if (real_target_type == TypeManager.decimal_type)
487 return new CastToDecimal (expr);
488 } else if (expr_type == TypeManager.byte_type){
490 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
492 if (real_target_type == TypeManager.int32_type || real_target_type == TypeManager.uint32_type ||
493 real_target_type == TypeManager.short_type || real_target_type == TypeManager.ushort_type)
494 return EmptyCast.Create (expr, target_type);
496 if (real_target_type == TypeManager.uint64_type)
497 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
498 if (real_target_type == TypeManager.int64_type)
499 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
500 if (real_target_type == TypeManager.float_type)
501 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
502 if (real_target_type == TypeManager.double_type)
503 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
504 if (real_target_type == TypeManager.decimal_type)
505 return new CastToDecimal (expr);
507 } else if (expr_type == TypeManager.short_type){
509 // From short to int, long, float, double, decimal
511 if (real_target_type == TypeManager.int32_type)
512 return EmptyCast.Create (expr, target_type);
513 if (real_target_type == TypeManager.int64_type)
514 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
515 if (real_target_type == TypeManager.double_type)
516 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
517 if (real_target_type == TypeManager.float_type)
518 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
519 if (real_target_type == TypeManager.decimal_type)
520 return new CastToDecimal (expr);
522 } else if (expr_type == TypeManager.ushort_type){
524 // From ushort to int, uint, long, ulong, float, double, decimal
526 if (real_target_type == TypeManager.int32_type || real_target_type == TypeManager.uint32_type)
527 return EmptyCast.Create (expr, target_type);
529 if (real_target_type == TypeManager.uint64_type)
530 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
531 if (real_target_type == TypeManager.int64_type)
532 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
533 if (real_target_type == TypeManager.double_type)
534 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
535 if (real_target_type == TypeManager.float_type)
536 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
537 if (real_target_type == TypeManager.decimal_type)
538 return new CastToDecimal (expr);
539 } else if (expr_type == TypeManager.int32_type){
541 // From int to long, float, double, decimal
543 if (real_target_type == TypeManager.int64_type)
544 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
545 if (real_target_type == TypeManager.double_type)
546 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
547 if (real_target_type == TypeManager.float_type)
548 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
549 if (real_target_type == TypeManager.decimal_type)
550 return new CastToDecimal (expr);
551 } else if (expr_type == TypeManager.uint32_type){
553 // From uint to long, ulong, float, double, decimal
555 if (real_target_type == TypeManager.int64_type)
556 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
557 if (real_target_type == TypeManager.uint64_type)
558 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
559 if (real_target_type == TypeManager.double_type)
560 return new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
561 if (real_target_type == TypeManager.float_type)
562 return new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
563 if (real_target_type == TypeManager.decimal_type)
564 return new CastToDecimal (expr);
565 } else if (expr_type == TypeManager.int64_type){
567 // From long/ulong to float, double
569 if (real_target_type == TypeManager.double_type)
570 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
571 if (real_target_type == TypeManager.float_type)
572 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
573 if (real_target_type == TypeManager.decimal_type)
574 return new CastToDecimal (expr);
575 } else if (expr_type == TypeManager.uint64_type){
577 // From ulong to float, double
579 if (real_target_type == TypeManager.double_type)
580 return new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
581 if (real_target_type == TypeManager.float_type)
582 return new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
583 if (real_target_type == TypeManager.decimal_type)
584 return new CastToDecimal (expr);
585 } else if (expr_type == TypeManager.char_type){
587 // From char to ushort, int, uint, long, ulong, float, double, decimal
589 if ((real_target_type == TypeManager.ushort_type) ||
590 (real_target_type == TypeManager.int32_type) ||
591 (real_target_type == TypeManager.uint32_type))
592 return EmptyCast.Create (expr, target_type);
593 if (real_target_type == TypeManager.uint64_type)
594 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
595 if (real_target_type == TypeManager.int64_type)
596 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
597 if (real_target_type == TypeManager.float_type)
598 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
599 if (real_target_type == TypeManager.double_type)
600 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
601 if (real_target_type == TypeManager.decimal_type)
602 return new CastToDecimal (expr);
603 } else if (expr_type == TypeManager.float_type){
607 if (real_target_type == TypeManager.double_type)
608 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
615 /// Same as ImplicitStandardConversionExists except that it also looks at
616 /// implicit user defined conversions - needed for overload resolution
618 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
621 if (expr is NullLiteral) {
622 if (TypeManager.IsGenericParameter (target_type))
623 return TypeParameter_to_Null (target_type);
625 if (TypeManager.IsNullableType (target_type))
629 if (ImplicitStandardConversionExists (expr, target_type))
632 if (expr.Type == TypeManager.anonymous_method_type) {
633 if (!TypeManager.IsDelegateType (target_type) &&
634 TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type)
637 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
638 return ame.ImplicitStandardConversionExists (ec, target_type);
641 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
644 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
646 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
650 /// Determines if a standard implicit conversion exists from
651 /// expr_type to target_type
653 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
655 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
657 Type expr_type = expr.Type;
659 if (TypeManager.IsNullableType (target_type)) {
660 // if implicit standard conversion S -> T exists, S -> T? and S? -> T? also exists
661 target_type = TypeManager.GetTypeArguments (target_type) [0];
664 if (TypeManager.IsNullableType (expr_type)) {
665 EmptyExpression new_expr = EmptyExpression.Grab ();
666 new_expr.SetType (TypeManager.GetTypeArguments (expr_type) [0]);
667 bool retval = ImplicitStandardConversionExists (new_expr, target_type);
668 EmptyExpression.Release (new_expr);
673 if (expr_type == TypeManager.void_type)
676 if (expr.eclass == ExprClass.MethodGroup) {
677 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) {
678 MethodGroupExpr mg = expr as MethodGroupExpr;
680 return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null;
687 //Console.WriteLine ("Expr is {0}", expr);
688 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
689 if (TypeManager.IsEqual (expr_type, target_type))
693 // First numeric conversions
695 if (expr_type == TypeManager.sbyte_type){
697 // From sbyte to short, int, long, float, double, decimal
699 if ((target_type == TypeManager.int32_type) ||
700 (target_type == TypeManager.int64_type) ||
701 (target_type == TypeManager.double_type) ||
702 (target_type == TypeManager.float_type) ||
703 (target_type == TypeManager.short_type) ||
704 (target_type == TypeManager.decimal_type))
707 } else if (expr_type == TypeManager.byte_type){
709 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
711 if ((target_type == TypeManager.short_type) ||
712 (target_type == TypeManager.ushort_type) ||
713 (target_type == TypeManager.int32_type) ||
714 (target_type == TypeManager.uint32_type) ||
715 (target_type == TypeManager.uint64_type) ||
716 (target_type == TypeManager.int64_type) ||
717 (target_type == TypeManager.float_type) ||
718 (target_type == TypeManager.double_type) ||
719 (target_type == TypeManager.decimal_type))
722 } else if (expr_type == TypeManager.short_type){
724 // From short to int, long, double, float, decimal
726 if ((target_type == TypeManager.int32_type) ||
727 (target_type == TypeManager.int64_type) ||
728 (target_type == TypeManager.double_type) ||
729 (target_type == TypeManager.float_type) ||
730 (target_type == TypeManager.decimal_type))
733 } else if (expr_type == TypeManager.ushort_type){
735 // From ushort to int, uint, long, ulong, double, float, decimal
737 if ((target_type == TypeManager.uint32_type) ||
738 (target_type == TypeManager.uint64_type) ||
739 (target_type == TypeManager.int32_type) ||
740 (target_type == TypeManager.int64_type) ||
741 (target_type == TypeManager.double_type) ||
742 (target_type == TypeManager.float_type) ||
743 (target_type == TypeManager.decimal_type))
746 } else if (expr_type == TypeManager.int32_type){
748 // From int to long, double, float, decimal
750 if ((target_type == TypeManager.int64_type) ||
751 (target_type == TypeManager.double_type) ||
752 (target_type == TypeManager.float_type) ||
753 (target_type == TypeManager.decimal_type))
756 } else if (expr_type == TypeManager.uint32_type){
758 // From uint to long, ulong, double, float, decimal
760 if ((target_type == TypeManager.int64_type) ||
761 (target_type == TypeManager.uint64_type) ||
762 (target_type == TypeManager.double_type) ||
763 (target_type == TypeManager.float_type) ||
764 (target_type == TypeManager.decimal_type))
767 } else if ((expr_type == TypeManager.uint64_type) ||
768 (expr_type == TypeManager.int64_type)) {
770 // From long/ulong to double, float, decimal
772 if ((target_type == TypeManager.double_type) ||
773 (target_type == TypeManager.float_type) ||
774 (target_type == TypeManager.decimal_type))
777 } else if (expr_type == TypeManager.char_type){
779 // From char to ushort, int, uint, ulong, long, float, double, decimal
781 if ((target_type == TypeManager.ushort_type) ||
782 (target_type == TypeManager.int32_type) ||
783 (target_type == TypeManager.uint32_type) ||
784 (target_type == TypeManager.uint64_type) ||
785 (target_type == TypeManager.int64_type) ||
786 (target_type == TypeManager.float_type) ||
787 (target_type == TypeManager.double_type) ||
788 (target_type == TypeManager.decimal_type))
791 } else if (expr_type == TypeManager.float_type){
795 if (target_type == TypeManager.double_type)
799 if (ImplicitReferenceConversionExists (expr, target_type))
803 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
807 // Implicit Constant Expression Conversions
809 if (expr is IntConstant){
810 int value = ((IntConstant) expr).Value;
812 if (target_type == TypeManager.sbyte_type){
813 if (value >= SByte.MinValue && value <= SByte.MaxValue)
815 } else if (target_type == TypeManager.byte_type){
816 if (value >= 0 && value <= Byte.MaxValue)
818 } else if (target_type == TypeManager.short_type){
819 if (value >= Int16.MinValue && value <= Int16.MaxValue)
821 } else if (target_type == TypeManager.ushort_type){
822 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
824 } else if (target_type == TypeManager.uint32_type){
827 } else if (target_type == TypeManager.uint64_type){
829 // we can optimize this case: a positive int32
830 // always fits on a uint64. But we need an opcode
837 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
841 if (expr is LongConstant && target_type == TypeManager.uint64_type){
843 // Try the implicit constant expression conversion
844 // from long to ulong, instead of a nice routine,
847 long v = ((LongConstant) expr).Value;
853 // If `expr_type' implements `target_type' (which is an iface)
854 // see TryImplicitIntConversion
856 if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
859 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
866 /// Finds "most encompassed type" according to the spec (13.4.2)
867 /// amongst the methods in the MethodGroupExpr
869 static Type FindMostEncompassedType (ArrayList types)
873 if (types.Count == 0)
876 if (types.Count == 1)
877 return (Type) types [0];
879 EmptyExpression expr = EmptyExpression.Grab ();
881 foreach (Type t in types) {
888 if (ImplicitStandardConversionExists (expr, best))
893 foreach (Type t in types) {
896 if (!ImplicitStandardConversionExists (expr, t)) {
902 EmptyExpression.Release (expr);
908 /// Finds "most encompassing type" according to the spec (13.4.2)
909 /// amongst the types in the given set
911 static Type FindMostEncompassingType (ArrayList types)
915 if (types.Count == 0)
918 if (types.Count == 1)
919 return (Type) types [0];
921 EmptyExpression expr = EmptyExpression.Grab ();
923 foreach (Type t in types) {
930 if (ImplicitStandardConversionExists (expr, t))
934 foreach (Type t in types) {
938 if (!ImplicitStandardConversionExists (expr, best)) {
944 EmptyExpression.Release (expr);
950 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
951 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
952 /// for explicit and implicit conversion operators.
954 static public Type FindMostSpecificSource (IList list,
955 Expression source, bool apply_explicit_conv_rules)
957 ArrayList src_types_set = new ArrayList ();
960 // If any operator converts from S then Sx = S
962 Type source_type = source.Type;
963 foreach (MethodBase mb in list){
964 AParametersCollection pd = TypeManager.GetParameterData (mb);
965 Type param_type = pd.Types [0];
967 if (param_type == source_type)
970 src_types_set.Add (param_type);
974 // Explicit Conv rules
976 if (apply_explicit_conv_rules) {
977 ArrayList candidate_set = new ArrayList ();
979 foreach (Type param_type in src_types_set){
980 if (ImplicitStandardConversionExists (source, param_type))
981 candidate_set.Add (param_type);
984 if (candidate_set.Count != 0)
985 return FindMostEncompassedType (candidate_set);
991 if (apply_explicit_conv_rules)
992 return FindMostEncompassingType (src_types_set);
994 return FindMostEncompassedType (src_types_set);
998 /// Finds the most specific target Tx according to section 13.4.4
1000 static public Type FindMostSpecificTarget (IList list,
1001 Type target, bool apply_explicit_conv_rules)
1003 ArrayList tgt_types_set = new ArrayList ();
1006 // If any operator converts to T then Tx = T
1008 foreach (MethodInfo mi in list){
1009 Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType);
1010 if (ret_type == target)
1013 tgt_types_set.Add (ret_type);
1017 // Explicit conv rules
1019 if (apply_explicit_conv_rules) {
1020 ArrayList candidate_set = new ArrayList ();
1022 EmptyExpression expr = EmptyExpression.Grab ();
1024 foreach (Type ret_type in tgt_types_set){
1025 expr.SetType (ret_type);
1027 if (ImplicitStandardConversionExists (expr, target))
1028 candidate_set.Add (ret_type);
1031 EmptyExpression.Release (expr);
1033 if (candidate_set.Count != 0)
1034 return FindMostEncompassingType (candidate_set);
1038 // Okay, final case !
1040 if (apply_explicit_conv_rules)
1041 return FindMostEncompassedType (tgt_types_set);
1043 return FindMostEncompassingType (tgt_types_set);
1047 /// User-defined Implicit conversions
1049 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1050 Type target, Location loc)
1052 Expression expr = UserDefinedConversion (ec, source, target, loc, false);
1053 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
1054 expr = ImplicitConversionStandard (ec, expr, target, loc);
1060 /// User-defined Explicit conversions
1062 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1063 Type target, Location loc)
1065 Expression expr = UserDefinedConversion (ec, source, target, loc, true);
1066 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
1067 expr = ExplicitConversionStandard (ec, expr, target, loc);
1072 static void AddConversionOperators (ArrayList list,
1073 Expression source, Type target_type,
1074 bool look_for_explicit,
1080 Type source_type = source.Type;
1081 EmptyExpression expr = EmptyExpression.Grab ();
1084 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
1085 // IntPtr -> uint uses int
1086 // UIntPtr -> long uses ulong
1088 if (source_type == TypeManager.intptr_type) {
1089 if (target_type == TypeManager.uint32_type)
1090 target_type = TypeManager.int32_type;
1091 } else if (source_type == TypeManager.uintptr_type) {
1092 if (target_type == TypeManager.int64_type)
1093 target_type = TypeManager.uint64_type;
1096 foreach (MethodInfo m in mg.Methods) {
1097 AParametersCollection pd = TypeManager.GetParameterData (m);
1098 Type return_type = TypeManager.TypeToCoreType (m.ReturnType);
1099 Type arg_type = pd.Types [0];
1101 if (source_type != arg_type) {
1102 if (!ImplicitStandardConversionExists (source, arg_type)) {
1103 if (!look_for_explicit)
1105 expr.SetType (arg_type);
1106 if (!ImplicitStandardConversionExists (expr, source_type))
1111 if (target_type != return_type) {
1112 expr.SetType (return_type);
1113 if (!ImplicitStandardConversionExists (expr, target_type)) {
1114 if (!look_for_explicit)
1116 expr.SetType (target_type);
1117 if (!ImplicitStandardConversionExists (expr, return_type))
1122 // See LAMESPEC: Exclude IntPtr -> int conversion
1123 if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type)
1129 EmptyExpression.Release (expr);
1133 /// Compute the user-defined conversion operator from source_type to target_type.
1134 /// `look_for_explicit' controls whether we should also include the list of explicit operators
1136 static MethodInfo GetConversionOperator (Type container_type, Expression source, Type target_type, bool look_for_explicit)
1138 ArrayList ops = new ArrayList (4);
1140 Type source_type = source.Type;
1142 if (source_type != TypeManager.decimal_type) {
1143 AddConversionOperators (ops, source, target_type, look_for_explicit,
1144 Expression.MethodLookup (container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1145 if (look_for_explicit) {
1146 AddConversionOperators (ops, source, target_type, look_for_explicit,
1147 Expression.MethodLookup (
1148 container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1152 if (target_type != TypeManager.decimal_type) {
1153 AddConversionOperators (ops, source, target_type, look_for_explicit,
1154 Expression.MethodLookup (container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1155 if (look_for_explicit) {
1156 AddConversionOperators (ops, source, target_type, look_for_explicit,
1157 Expression.MethodLookup (
1158 container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1165 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
1166 if (most_specific_source == null)
1169 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
1170 if (most_specific_target == null)
1173 MethodInfo method = null;
1175 foreach (MethodInfo m in ops) {
1176 if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target)
1178 if (TypeManager.GetParameterData (m).Types [0] != most_specific_source)
1180 // Ambiguous: more than one conversion operator satisfies the signature.
1189 static DoubleHash explicit_conv = new DoubleHash (100);
1190 static DoubleHash implicit_conv = new DoubleHash (100);
1193 /// User-defined conversions
1195 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1196 Type target, Location loc,
1197 bool look_for_explicit)
1199 Type source_type = source.Type;
1200 MethodInfo method = null;
1204 if (look_for_explicit) {
1205 hash = explicit_conv;
1207 // Implicit user operators cannot convert to interfaces
1208 if (target.IsInterface)
1211 hash = implicit_conv;
1214 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1215 method = (MethodInfo) o;
1217 method = GetConversionOperator (null, source, target, look_for_explicit);
1218 if (!(source is Constant))
1219 hash.Insert (source_type, target, method);
1225 Type most_specific_source = TypeManager.GetParameterData (method).Types [0];
1228 // This will do the conversion to the best match that we
1229 // found. Now we need to perform an implict standard conversion
1230 // if the best match was not the type that we were requested
1233 if (look_for_explicit)
1234 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1236 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1241 return new UserCast (method, source, loc).DoResolve (ec);
1245 /// Converts implicitly the resolved expression `expr' into the
1246 /// `target_type'. It returns a new expression that can be used
1247 /// in a context that expects a `target_type'.
1249 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1250 Type target_type, Location loc)
1254 if (target_type == null)
1255 throw new Exception ("Target type is null");
1257 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1261 e = ImplicitUserConversion (ec, expr, target_type, loc);
1270 /// Attempts to apply the `Standard Implicit
1271 /// Conversion' rules to the expression `expr' into
1272 /// the `target_type'. It returns a new expression
1273 /// that can be used in a context that expects a
1276 /// This is different from `ImplicitConversion' in that the
1277 /// user defined implicit conversions are excluded.
1279 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1280 Type target_type, Location loc)
1282 return ImplicitConversionStandard (ec, expr, target_type, loc, false);
1285 static Expression ImplicitConversionStandard (EmitContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast)
1287 Type expr_type = expr.Type;
1291 if (TypeManager.IsNullableType (target_type)) {
1293 // From null to any nullable type
1295 if (expr_type == TypeManager.null_type)
1296 return Nullable.LiftedNull.Create (target_type, loc);
1298 Type target = TypeManager.GetTypeArguments (target_type) [0];
1300 if (TypeManager.IsNullableType (expr_type)) {
1301 Type etype = TypeManager.GetTypeArguments (expr_type) [0];
1302 if (TypeManager.IsEqual (etype, target))
1305 return new Nullable.LiftedConversion (
1306 expr, target_type, false, false, loc).Resolve (ec);
1308 e = ImplicitConversion (ec, expr, target, loc);
1310 return Nullable.Wrap.Create (e, target_type);
1314 if (expr.eclass == ExprClass.MethodGroup){
1315 if (!TypeManager.IsDelegateType (target_type)){
1320 // Only allow anonymous method conversions on post ISO_1
1322 if (RootContext.Version != LanguageVersion.ISO_1){
1323 MethodGroupExpr mg = expr as MethodGroupExpr;
1325 return ImplicitDelegateCreation.Create (
1326 ec, mg, target_type, loc);
1330 if (expr_type.Equals (target_type)) {
1331 if (expr_type != TypeManager.null_type && expr_type != TypeManager.anonymous_method_type)
1337 // Attempt to do the implicit constant expression conversions
1339 Constant c = expr as Constant;
1342 // If `target_type' is an interface and the type of `ic' implements the interface
1343 // e.g. target_type is IComparable, IConvertible, IFormattable
1345 if (c.Type == TypeManager.int32_type && target_type.IsInterface && target_type.IsAssignableFrom (c.Type))
1346 return new BoxedCast (c, target_type);
1349 c = c.ConvertImplicitly (target_type);
1351 Console.WriteLine ("Conversion error happened in line {0}", loc);
1358 e = ImplicitNumericConversion (expr, target_type);
1362 e = ImplicitReferenceConversion (expr, target_type, explicit_cast);
1366 if (expr is IntConstant && TypeManager.IsEnumType (target_type)){
1367 Constant i = (Constant) expr;
1369 // LAMESPEC: Conversion from any 0 constant is allowed
1371 // An implicit enumeration conversion permits the decimal-integer-literal 0
1372 // to be converted to any enum-type and to any nullable-type whose underlying
1373 // type is an enum-type
1375 if (i.IsDefaultValue)
1376 return new EnumConstant (i, target_type);
1380 if (expr_type.IsPointer){
1381 if (target_type == TypeManager.void_ptr_type)
1382 return EmptyCast.Create (expr, target_type);
1385 // yep, comparing pointer types cant be done with
1386 // t1 == t2, we have to compare their element types.
1388 if (target_type.IsPointer){
1389 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1396 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1397 return EmptyCast.Create (new NullPointer (loc), target_type);
1400 if (expr_type == TypeManager.anonymous_method_type){
1401 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
1402 Expression am = ame.Compatible (ec, target_type);
1404 return am.DoResolve (ec);
1411 /// Attempts to implicitly convert `source' into `target_type', using
1412 /// ImplicitConversion. If there is no implicit conversion, then
1413 /// an error is signaled
1415 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1416 Type target_type, Location loc)
1418 Expression e = ImplicitConversion (ec, source, target_type, loc);
1422 source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
1427 /// Performs the explicit numeric conversions
1429 /// There are a few conversions that are not part of the C# standard,
1430 /// they were interim hacks in the C# compiler that were supposed to
1431 /// become explicit operators in the UIntPtr class and IntPtr class,
1432 /// but for historical reasons it did not happen, so the C# compiler
1433 /// ended up with these special hacks.
1435 /// See bug 59800 for details.
1437 /// The conversion are:
1447 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1449 Type expr_type = expr.Type;
1450 Type real_target_type = target_type;
1452 if (expr_type == TypeManager.sbyte_type){
1454 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1456 if (real_target_type == TypeManager.byte_type)
1457 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1458 if (real_target_type == TypeManager.ushort_type)
1459 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1460 if (real_target_type == TypeManager.uint32_type)
1461 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1462 if (real_target_type == TypeManager.uint64_type)
1463 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1464 if (real_target_type == TypeManager.char_type)
1465 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1467 // One of the built-in conversions that belonged in the class library
1468 if (real_target_type == TypeManager.uintptr_type){
1469 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I1_U8);
1471 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1473 } else if (expr_type == TypeManager.byte_type){
1475 // From byte to sbyte and char
1477 if (real_target_type == TypeManager.sbyte_type)
1478 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1479 if (real_target_type == TypeManager.char_type)
1480 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1481 } else if (expr_type == TypeManager.short_type){
1483 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1485 if (real_target_type == TypeManager.sbyte_type)
1486 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1487 if (real_target_type == TypeManager.byte_type)
1488 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1489 if (real_target_type == TypeManager.ushort_type)
1490 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1491 if (real_target_type == TypeManager.uint32_type)
1492 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1493 if (real_target_type == TypeManager.uint64_type)
1494 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1495 if (real_target_type == TypeManager.char_type)
1496 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1498 // One of the built-in conversions that belonged in the class library
1499 if (real_target_type == TypeManager.uintptr_type){
1500 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1502 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1504 } else if (expr_type == TypeManager.ushort_type){
1506 // From ushort to sbyte, byte, short, char
1508 if (real_target_type == TypeManager.sbyte_type)
1509 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1510 if (real_target_type == TypeManager.byte_type)
1511 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1512 if (real_target_type == TypeManager.short_type)
1513 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1514 if (real_target_type == TypeManager.char_type)
1515 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1516 } else if (expr_type == TypeManager.int32_type){
1518 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1520 if (real_target_type == TypeManager.sbyte_type)
1521 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1522 if (real_target_type == TypeManager.byte_type)
1523 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1524 if (real_target_type == TypeManager.short_type)
1525 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1526 if (real_target_type == TypeManager.ushort_type)
1527 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1528 if (real_target_type == TypeManager.uint32_type)
1529 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1530 if (real_target_type == TypeManager.uint64_type)
1531 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1532 if (real_target_type == TypeManager.char_type)
1533 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1535 // One of the built-in conversions that belonged in the class library
1536 if (real_target_type == TypeManager.uintptr_type){
1537 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1539 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1541 } else if (expr_type == TypeManager.uint32_type){
1543 // From uint to sbyte, byte, short, ushort, int, char
1545 if (real_target_type == TypeManager.sbyte_type)
1546 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1547 if (real_target_type == TypeManager.byte_type)
1548 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1549 if (real_target_type == TypeManager.short_type)
1550 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1551 if (real_target_type == TypeManager.ushort_type)
1552 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1553 if (real_target_type == TypeManager.int32_type)
1554 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1555 if (real_target_type == TypeManager.char_type)
1556 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1557 } else if (expr_type == TypeManager.int64_type){
1559 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1561 if (real_target_type == TypeManager.sbyte_type)
1562 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1563 if (real_target_type == TypeManager.byte_type)
1564 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1565 if (real_target_type == TypeManager.short_type)
1566 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1567 if (real_target_type == TypeManager.ushort_type)
1568 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1569 if (real_target_type == TypeManager.int32_type)
1570 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1571 if (real_target_type == TypeManager.uint32_type)
1572 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1573 if (real_target_type == TypeManager.uint64_type)
1574 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1575 if (real_target_type == TypeManager.char_type)
1576 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1577 } else if (expr_type == TypeManager.uint64_type){
1579 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1581 if (real_target_type == TypeManager.sbyte_type)
1582 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1583 if (real_target_type == TypeManager.byte_type)
1584 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1585 if (real_target_type == TypeManager.short_type)
1586 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1587 if (real_target_type == TypeManager.ushort_type)
1588 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1589 if (real_target_type == TypeManager.int32_type)
1590 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1591 if (real_target_type == TypeManager.uint32_type)
1592 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1593 if (real_target_type == TypeManager.int64_type)
1594 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1595 if (real_target_type == TypeManager.char_type)
1596 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1598 // One of the built-in conversions that belonged in the class library
1599 if (real_target_type == TypeManager.intptr_type){
1600 return new OperatorCast (EmptyCast.Create (expr, TypeManager.int64_type),
1601 TypeManager.intptr_type, true);
1603 } else if (expr_type == TypeManager.char_type){
1605 // From char to sbyte, byte, short
1607 if (real_target_type == TypeManager.sbyte_type)
1608 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1609 if (real_target_type == TypeManager.byte_type)
1610 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1611 if (real_target_type == TypeManager.short_type)
1612 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1613 } else if (expr_type == TypeManager.float_type){
1615 // From float to sbyte, byte, short,
1616 // ushort, int, uint, long, ulong, char
1619 if (real_target_type == TypeManager.sbyte_type)
1620 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1621 if (real_target_type == TypeManager.byte_type)
1622 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1623 if (real_target_type == TypeManager.short_type)
1624 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1625 if (real_target_type == TypeManager.ushort_type)
1626 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1627 if (real_target_type == TypeManager.int32_type)
1628 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1629 if (real_target_type == TypeManager.uint32_type)
1630 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1631 if (real_target_type == TypeManager.int64_type)
1632 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1633 if (real_target_type == TypeManager.uint64_type)
1634 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1635 if (real_target_type == TypeManager.char_type)
1636 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1637 if (real_target_type == TypeManager.decimal_type)
1638 return new CastToDecimal (expr, true);
1639 } else if (expr_type == TypeManager.double_type){
1641 // From double to sbyte, byte, short,
1642 // ushort, int, uint, long, ulong,
1643 // char, float or decimal
1645 if (real_target_type == TypeManager.sbyte_type)
1646 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1647 if (real_target_type == TypeManager.byte_type)
1648 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1649 if (real_target_type == TypeManager.short_type)
1650 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1651 if (real_target_type == TypeManager.ushort_type)
1652 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1653 if (real_target_type == TypeManager.int32_type)
1654 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1655 if (real_target_type == TypeManager.uint32_type)
1656 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1657 if (real_target_type == TypeManager.int64_type)
1658 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1659 if (real_target_type == TypeManager.uint64_type)
1660 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1661 if (real_target_type == TypeManager.char_type)
1662 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1663 if (real_target_type == TypeManager.float_type)
1664 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1665 if (real_target_type == TypeManager.decimal_type)
1666 return new CastToDecimal (expr, true);
1667 } else if (expr_type == TypeManager.uintptr_type){
1669 // Various built-in conversions that belonged in the class library
1671 // from uintptr to sbyte, short, int32
1673 if (real_target_type == TypeManager.sbyte_type){
1674 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1675 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I1);
1677 if (real_target_type == TypeManager.short_type){
1678 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1679 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I2);
1681 if (real_target_type == TypeManager.int32_type){
1682 return EmptyCast.Create (new OperatorCast (expr, TypeManager.uint32_type, true),
1683 TypeManager.int32_type);
1685 } else if (expr_type == TypeManager.intptr_type){
1686 if (real_target_type == TypeManager.uint64_type){
1687 return EmptyCast.Create (new OperatorCast (expr, TypeManager.int64_type, true),
1688 TypeManager.uint64_type);
1690 } else if (expr_type == TypeManager.decimal_type) {
1691 return new CastFromDecimal (expr, target_type).Resolve ();
1697 /// Returns whether an explicit reference conversion can be performed
1698 /// from source_type to target_type
1700 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1702 Expression e = ExplicitReferenceConversion (null, source_type, target_type);
1706 if (e == EmptyExpression.Null)
1709 throw new InternalErrorException ("Invalid probing conversion result");
1713 /// Implements Explicit Reference conversions
1715 static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type)
1717 bool target_is_value_type = target_type.IsValueType;
1720 // From object to a generic parameter
1722 if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type))
1723 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1726 // Explicit type parameter conversion.
1728 if (TypeManager.IsGenericParameter (source_type))
1729 return ExplicitTypeParameterConversion (source, source_type, target_type);
1732 // From object to any reference type
1734 if (source_type == TypeManager.object_type && !target_is_value_type)
1735 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1738 // Unboxing conversion.
1740 if (((source_type == TypeManager.enum_type &&
1741 !(source is TypeCast)) ||
1742 source_type == TypeManager.value_type) && target_is_value_type)
1743 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1746 // From any class S to any class-type T, provided S is a base class of T
1748 if (TypeManager.IsSubclassOf (target_type, source_type))
1749 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1752 // From any class type S to any interface T, provides S is not sealed
1753 // and provided S does not implement T.
1755 if (target_type.IsInterface && !source_type.IsSealed &&
1756 !TypeManager.ImplementsInterface (source_type, target_type)) {
1757 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1761 // From any interface-type S to to any class type T, provided T is not
1762 // sealed, or provided T implements S.
1764 if (source_type.IsInterface) {
1765 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1766 if (target_type.IsClass)
1767 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1769 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1773 // From System.Collecitons.Generic.IList<T> and its base interfaces to a one-dimensional
1774 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1776 if (IList_To_Array (source_type, target_type))
1777 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1782 if (source_type.IsArray) {
1783 if (target_type.IsArray) {
1785 // From System.Array to any array-type
1787 if (source_type == TypeManager.array_type)
1788 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1791 // From an array type S with an element type Se to an array type T with an
1792 // element type Te provided all the following are true:
1793 // * S and T differe only in element type, in other words, S and T
1794 // have the same number of dimensions.
1795 // * Both Se and Te are reference types
1796 // * An explicit reference conversions exist from Se to Te
1798 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1800 source_type = TypeManager.GetElementType (source_type);
1801 if (!TypeManager.IsReferenceType (source_type))
1804 Type target_type_element = TypeManager.GetElementType (target_type);
1805 if (!TypeManager.IsReferenceType (target_type_element))
1808 if (ExplicitReferenceConversionExists (source_type, target_type_element))
1809 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1816 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1817 // provided that there is an explicit reference conversion from S to T
1819 if (Array_To_IList (source_type, target_type, true))
1820 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1826 // From System delegate to any delegate-type
1828 if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
1829 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1835 /// Performs an explicit conversion of the expression `expr' whose
1836 /// type is expr.Type to `target_type'.
1838 static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
1839 Type target_type, Location loc)
1841 Type expr_type = expr.Type;
1843 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1844 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true);
1849 // Unboxing conversions; only object types can be convertible to enum
1851 if (expr_type == TypeManager.object_type && target_type.IsValueType)
1852 return new UnboxCast (expr, target_type);
1854 if (TypeManager.IsEnumType (expr_type)) {
1855 Expression underlying = EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type));
1856 expr = ExplicitConversionCore (ec, underlying, target_type, loc);
1860 return ExplicitUserConversion (ec, underlying, target_type, loc);
1863 if (TypeManager.IsEnumType (target_type)){
1864 if (expr_type == TypeManager.enum_type)
1865 return new UnboxCast (expr, target_type);
1867 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1869 return EmptyCast.Create (ce, target_type);
1872 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1874 if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
1875 ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1877 return ExplicitConversionCore (ec, ne, target_type, loc);
1883 ne = ExplicitNumericConversion (expr, target_type);
1888 // Skip the ExplicitReferenceConversion because we can not convert
1889 // from Null to a ValueType, and ExplicitReference wont check against
1890 // null literal explicitly
1892 if (expr_type != TypeManager.null_type){
1893 ne = ExplicitReferenceConversion (expr, expr_type, target_type);
1899 ne = ExplicitUnsafe (expr, target_type);
1907 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1909 Type expr_type = expr.Type;
1911 if (target_type.IsPointer){
1912 if (expr_type.IsPointer)
1913 return EmptyCast.Create (expr, target_type);
1915 if (expr_type == TypeManager.sbyte_type ||
1916 expr_type == TypeManager.short_type ||
1917 expr_type == TypeManager.int32_type)
1918 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1920 if (expr_type == TypeManager.ushort_type ||
1921 expr_type == TypeManager.uint32_type ||
1922 expr_type == TypeManager.uint64_type || expr_type == TypeManager.int64_type ||
1923 expr_type == TypeManager.byte_type)
1924 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1927 if (expr_type.IsPointer){
1928 if (target_type == TypeManager.sbyte_type)
1929 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1930 else if (target_type == TypeManager.byte_type)
1931 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1932 else if (target_type == TypeManager.short_type)
1933 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1934 else if (target_type == TypeManager.ushort_type)
1935 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1936 else if (target_type == TypeManager.int32_type)
1937 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1938 else if (target_type == TypeManager.uint32_type)
1939 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1940 else if (target_type == TypeManager.uint64_type || target_type == TypeManager.int64_type)
1941 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1947 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1949 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1950 Type target_type, Location l)
1952 int errors = Report.Errors;
1953 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1954 if (Report.Errors > errors)
1960 ne = ExplicitNumericConversion (expr, target_type);
1964 ne = ExplicitReferenceConversion (expr, expr.Type, target_type);
1968 if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1969 return EmptyCast.Create (expr, target_type);
1971 expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
1976 /// Performs an explicit conversion of the expression `expr' whose
1977 /// type is expr.Type to `target_type'.
1979 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1980 Type target_type, Location loc)
1984 Type expr_type = expr.Type;
1985 if (TypeManager.IsNullableType (target_type)) {
1986 if (TypeManager.IsNullableType (expr_type)) {
1987 e = new Nullable.LiftedConversion (
1988 expr, target_type, false, true, loc).Resolve (ec);
1991 } else if (expr_type == TypeManager.object_type) {
1992 return new UnboxCast (expr, target_type);
1994 Type target = TypeManager.GetTypeArguments (target_type) [0];
1996 e = ExplicitConversionCore (ec, expr, target, loc);
1998 return Nullable.Wrap.Create (e, target_type);
2000 } else if (TypeManager.IsNullableType (expr_type)) {
2001 e = Nullable.Unwrap.Create (expr, ec);
2003 bool use_class_cast;
2004 if (ImplicitBoxingConversionExists (e, target_type, out use_class_cast))
2005 return new BoxedCast (expr, target_type);
2007 e = ExplicitConversion (ec, e, target_type, loc);
2009 e = EmptyCast.Create (e, target_type);
2013 e = ExplicitConversionCore (ec, expr, target_type, loc);
2017 e = ExplicitUserConversion (ec, expr, target_type, loc);
2021 expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);