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 static class Convert {
25 static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
27 ArrayList list = new ArrayList ();
28 list.Add (gc.EffectiveBaseClass);
29 foreach (Type t in gc.InterfaceConstraints) {
30 if (!TypeManager.IsGenericParameter (t))
33 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
35 list.Add (TypeParam_EffectiveBaseType (new_gc));
37 return FindMostEncompassedType (list);
42 // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
43 // interfaces of this interface, provided there is an implicit reference conversion
46 static bool Array_To_IList (Type array, Type list, bool isExplicit)
49 if ((array.GetArrayRank () != 1) || !list.IsGenericType)
52 Type gt = list.GetGenericTypeDefinition ();
53 if ((gt != TypeManager.generic_ilist_type) &&
54 (gt != TypeManager.generic_icollection_type) &&
55 (gt != TypeManager.generic_ienumerable_type))
58 Type element_type = TypeManager.GetElementType (array);
59 Type arg_type = TypeManager.GetTypeArguments (list) [0];
61 if (element_type == arg_type)
65 return ExplicitReferenceConversionExists (element_type, arg_type);
67 if (MyEmptyExpr == null)
68 MyEmptyExpr = new EmptyExpression ();
69 MyEmptyExpr.SetType (TypeManager.GetElementType (array));
71 return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
77 static bool IList_To_Array(Type list, Type array)
80 if (!list.IsGenericType || !array.IsArray || array.GetArrayRank() != 1)
83 Type gt = list.GetGenericTypeDefinition();
84 if (gt != TypeManager.generic_ilist_type &&
85 gt != TypeManager.generic_icollection_type &&
86 gt != TypeManager.generic_ienumerable_type)
89 Type arg_type = TypeManager.GetTypeArguments(list)[0];
90 Type element_type = TypeManager.GetElementType(array);
92 if (element_type == arg_type)
95 if (MyEmptyExpr == null)
96 MyEmptyExpr = new EmptyExpression();
97 MyEmptyExpr.SetType(element_type);
98 return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type);
104 static Expression ImplicitTypeParameterConversion (Expression expr,
108 Type expr_type = expr.Type;
110 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
113 if (target_type == TypeManager.object_type)
114 return new BoxedCast (expr, target_type);
119 // We're converting from a type parameter which is known to be a reference type.
120 Type base_type = TypeParam_EffectiveBaseType (gc);
122 if (TypeManager.IsSubclassOf (base_type, target_type))
123 return new ClassCast (expr, target_type);
125 if (target_type.IsInterface) {
126 if (TypeManager.ImplementsInterface (base_type, target_type))
127 return new ClassCast (expr, target_type);
129 foreach (Type t in gc.InterfaceConstraints) {
130 if (TypeManager.IsSubclassOf (t, target_type))
131 return new ClassCast (expr, target_type);
132 if (TypeManager.ImplementsInterface (t, target_type))
133 return new ClassCast (expr, target_type);
137 foreach (Type t in gc.InterfaceConstraints) {
138 if (!TypeManager.IsGenericParameter (t))
140 if (TypeManager.IsSubclassOf (t, target_type))
141 return new ClassCast (expr, target_type);
142 if (TypeManager.ImplementsInterface (t, target_type))
143 return new ClassCast (expr, target_type);
149 static bool ImplicitTypeParameterBoxingConversion (Type expr_type, Type target_type,
150 out bool use_class_cast)
153 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
156 use_class_cast = false;
157 return target_type == TypeManager.object_type;
160 use_class_cast = true;
162 if (!gc.HasReferenceTypeConstraint)
165 // We're converting from a type parameter which is known to be a reference type.
166 Type base_type = TypeParam_EffectiveBaseType (gc);
168 if (TypeManager.IsSubclassOf (base_type, target_type))
171 if (target_type.IsInterface) {
172 if (TypeManager.ImplementsInterface (base_type, target_type))
175 foreach (Type t in gc.InterfaceConstraints) {
176 if (TypeManager.IsSubclassOf (t, target_type))
178 if (TypeManager.ImplementsInterface (t, target_type))
183 foreach (Type t in gc.InterfaceConstraints) {
184 if (!TypeManager.IsGenericParameter (t))
186 if (TypeManager.IsSubclassOf (t, target_type))
188 if (TypeManager.ImplementsInterface (t, target_type))
193 use_class_cast = false;
197 static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type)
200 if (TypeManager.IsGenericParameter (target_type)) {
201 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
205 foreach (Type iface in gc.InterfaceConstraints) {
206 if (!TypeManager.IsGenericParameter (iface))
209 if (TypeManager.IsSubclassOf (source_type, iface))
210 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
214 if (target_type.IsInterface)
215 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
220 static EmptyExpression MyEmptyExpr;
221 static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast)
223 Type expr_type = expr.Type;
225 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
226 // if we are a method group, emit a warning
231 if (expr_type == TypeManager.void_type)
234 if (TypeManager.IsGenericParameter (expr_type))
235 return ImplicitTypeParameterConversion (expr, target_type);
238 // from the null type to any reference-type.
240 NullLiteral nl = expr as NullLiteral;
242 return nl.ConvertImplicitly(target_type);
245 if (ImplicitReferenceConversionExists (expr, target_type)) {
247 // Reduce implicit reference conversion to object
249 if (!explicit_cast && target_type == TypeManager.object_type)
252 return EmptyCast.Create (expr, target_type);
256 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) {
258 return new ClassCast (expr, target_type);
260 return new BoxedCast (expr, target_type);
267 // 6.1.6 Implicit reference conversions
269 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
271 if (target_type.IsValueType)
274 Type expr_type = expr.Type;
276 // from the null type to any reference-type.
277 if (expr_type == TypeManager.null_type)
278 return target_type != TypeManager.anonymous_method_type;
280 if (TypeManager.IsGenericParameter (expr_type))
281 return ImplicitTypeParameterConversion (expr, target_type) != null;
284 // notice that it is possible to write "ValueType v = 1", the ValueType here
285 // is an abstract class, and not really a value type, so we apply the same rules.
287 if (target_type == TypeManager.object_type) {
289 // A pointer type cannot be converted to object
291 if (expr_type.IsPointer)
294 if (TypeManager.IsValueType (expr_type))
296 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
297 return expr_type != TypeManager.anonymous_method_type;
301 } else if (target_type == TypeManager.value_type) {
302 return expr_type == TypeManager.enum_type;
303 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
305 // Special case: enumeration to System.Enum.
306 // System.Enum is not a value type, it is a class, so we need
307 // a boxing conversion
309 if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type))
315 // This code is kind of mirrored inside ImplicitStandardConversionExists
316 // with the small distinction that we only probe there
318 // Always ensure that the code here and there is in sync
320 // from any class-type S to any interface-type T.
321 if (target_type.IsInterface) {
322 if (TypeManager.ImplementsInterface (expr_type, target_type)){
323 return !TypeManager.IsGenericParameter (expr_type) &&
324 !TypeManager.IsValueType (expr_type);
328 if (expr_type.IsArray) {
329 // from an array-type S to an array-type of type T
330 if (target_type.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
333 // Both SE and TE are reference-types
335 Type expr_element_type = TypeManager.GetElementType (expr_type);
336 if (!TypeManager.IsReferenceType (expr_element_type))
339 Type target_element_type = TypeManager.GetElementType (target_type);
340 if (!TypeManager.IsReferenceType (target_element_type))
343 if (MyEmptyExpr == null)
344 MyEmptyExpr = new EmptyExpression ();
346 MyEmptyExpr.SetType (expr_element_type);
348 return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type);
351 // from an array-type to System.Array
352 if (target_type == TypeManager.array_type)
355 // from an array-type of type T to IList<T>
356 if (Array_To_IList (expr_type, target_type, false))
362 // from any interface type S to interface-type T.
363 if (expr_type.IsInterface && target_type.IsInterface) {
364 return TypeManager.ImplementsInterface (expr_type, target_type);
367 // from any delegate type to System.Delegate
368 if (target_type == TypeManager.delegate_type &&
369 (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)))
372 // from a generic type definition to a generic instance.
373 if (TypeManager.IsEqual (expr_type, target_type))
379 public static bool ImplicitBoxingConversionExists (Expression expr, Type target_type,
380 out bool use_class_cast)
382 Type expr_type = expr.Type;
383 use_class_cast = false;
386 // From any value-type to the type object.
388 if (target_type == TypeManager.object_type) {
390 // A pointer type cannot be converted to object
392 if (expr_type.IsPointer)
395 return TypeManager.IsValueType (expr_type);
399 // From any value-type to the type System.ValueType.
401 if (target_type == TypeManager.value_type)
402 return TypeManager.IsValueType (expr_type);
404 if (target_type == TypeManager.enum_type) {
406 // From any enum-type to the type System.Enum.
408 if (expr_type.IsEnum)
411 // From any nullable-type with an underlying enum-type to the type System.Enum
413 if (TypeManager.IsNullableType (expr_type))
414 return TypeManager.GetTypeArguments (expr_type) [0].IsEnum;
417 if (TypeManager.IsSubclassOf (expr_type, target_type)) {
419 // Don't box same type arguments
421 if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type)
427 // This code is kind of mirrored inside ImplicitStandardConversionExists
428 // with the small distinction that we only probe there
430 // Always ensure that the code here and there is in sync
432 // from any class-type S to any interface-type T.
433 if (target_type.IsInterface) {
434 if (TypeManager.ImplementsInterface (expr_type, target_type))
435 return TypeManager.IsGenericParameter (expr_type) ||
436 TypeManager.IsValueType (expr_type);
439 if (TypeManager.IsGenericParameter (expr_type))
440 return ImplicitTypeParameterBoxingConversion (
441 expr_type, target_type, out use_class_cast);
446 static Expression ImplicitNulableConversion (EmitContext ec, Expression expr, Type target_type)
448 Type expr_type = expr.Type;
451 // From null to any nullable type
453 if (expr_type == TypeManager.null_type)
454 return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location);
456 Type target = TypeManager.GetTypeArguments (target_type)[0];
460 if (TypeManager.IsNullableType (expr_type)) {
461 Type etype = TypeManager.GetTypeArguments (expr_type)[0];
464 return ImplicitConversionExists (ec, new EmptyExpression (etype), target) ? EmptyExpression.Null : null;
466 Expression unwrap = Nullable.Unwrap.Create (expr);
467 e = ImplicitConversion (ec, unwrap, target, expr.Location);
471 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
476 return ImplicitConversionExists (ec, expr, target) ? EmptyExpression.Null : null;
478 e = ImplicitConversion (ec, expr, target, expr.Location);
480 return Nullable.Wrap.Create (e, target_type);
486 /// Implicit Numeric Conversions.
488 /// expr is the expression to convert, returns a new expression of type
489 /// target_type or null if an implicit conversion is not possible.
491 public static Expression ImplicitNumericConversion (Expression expr, Type target_type)
493 return ImplicitNumericConversion (expr, expr.Type, target_type);
496 static Expression ImplicitNumericConversion (Expression expr, Type expr_type, Type target_type)
498 if (expr_type == TypeManager.sbyte_type){
500 // From sbyte to short, int, long, float, double, decimal
502 if (target_type == TypeManager.int32_type)
503 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
504 if (target_type == TypeManager.int64_type)
505 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
506 if (target_type == TypeManager.double_type)
507 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
508 if (target_type == TypeManager.float_type)
509 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
510 if (target_type == TypeManager.short_type)
511 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
512 if (target_type == TypeManager.decimal_type)
513 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
514 } else if (expr_type == TypeManager.byte_type){
516 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
518 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type ||
519 target_type == TypeManager.short_type || target_type == TypeManager.ushort_type)
520 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
522 if (target_type == TypeManager.uint64_type)
523 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
524 if (target_type == TypeManager.int64_type)
525 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
526 if (target_type == TypeManager.float_type)
527 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
528 if (target_type == TypeManager.double_type)
529 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
530 if (target_type == TypeManager.decimal_type)
531 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
533 } else if (expr_type == TypeManager.short_type){
535 // From short to int, long, float, double, decimal
537 if (target_type == TypeManager.int32_type)
538 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
539 if (target_type == TypeManager.int64_type)
540 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
541 if (target_type == TypeManager.double_type)
542 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
543 if (target_type == TypeManager.float_type)
544 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
545 if (target_type == TypeManager.decimal_type)
546 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
548 } else if (expr_type == TypeManager.ushort_type){
550 // From ushort to int, uint, long, ulong, float, double, decimal
552 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type)
553 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
555 if (target_type == TypeManager.uint64_type)
556 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
557 if (target_type == TypeManager.int64_type)
558 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
559 if (target_type == TypeManager.double_type)
560 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
561 if (target_type == TypeManager.float_type)
562 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
563 if (target_type == TypeManager.decimal_type)
564 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
565 } else if (expr_type == TypeManager.int32_type){
567 // From int to long, float, double, decimal
569 if (target_type == TypeManager.int64_type)
570 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
571 if (target_type == TypeManager.double_type)
572 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
573 if (target_type == TypeManager.float_type)
574 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
575 if (target_type == TypeManager.decimal_type)
576 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
577 } else if (expr_type == TypeManager.uint32_type){
579 // From uint to long, ulong, float, double, decimal
581 if (target_type == TypeManager.int64_type)
582 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
583 if (target_type == TypeManager.uint64_type)
584 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
585 if (target_type == TypeManager.double_type)
586 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
587 if (target_type == TypeManager.float_type)
588 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
589 if (target_type == TypeManager.decimal_type)
590 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
591 } else if (expr_type == TypeManager.int64_type){
593 // From long/ulong to float, double
595 if (target_type == TypeManager.double_type)
596 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
597 if (target_type == TypeManager.float_type)
598 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
599 if (target_type == TypeManager.decimal_type)
600 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
601 } else if (expr_type == TypeManager.uint64_type){
603 // From ulong to float, double
605 if (target_type == TypeManager.double_type)
606 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
607 if (target_type == TypeManager.float_type)
608 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
609 if (target_type == TypeManager.decimal_type)
610 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
611 } else if (expr_type == TypeManager.char_type){
613 // From char to ushort, int, uint, long, ulong, float, double, decimal
615 if ((target_type == TypeManager.ushort_type) ||
616 (target_type == TypeManager.int32_type) ||
617 (target_type == TypeManager.uint32_type))
618 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
619 if (target_type == TypeManager.uint64_type)
620 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
621 if (target_type == TypeManager.int64_type)
622 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
623 if (target_type == TypeManager.float_type)
624 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
625 if (target_type == TypeManager.double_type)
626 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
627 if (target_type == TypeManager.decimal_type)
628 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
629 } else if (expr_type == TypeManager.float_type){
633 if (target_type == TypeManager.double_type)
634 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
641 /// Same as ImplicitStandardConversionExists except that it also looks at
642 /// implicit user defined conversions - needed for overload resolution
644 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
646 if (expr is NullLiteral) {
647 return ((NullLiteral)expr).ConvertImplicitly (target_type) != null;
650 if (ImplicitStandardConversionExists (expr, target_type))
653 if (expr.Type == TypeManager.anonymous_method_type) {
654 if (!TypeManager.IsDelegateType (target_type) &&
655 TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type)
658 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
659 return ame.ImplicitStandardConversionExists (ec, target_type);
662 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
665 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
667 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
671 /// Determines if a standard implicit conversion exists from
672 /// expr_type to target_type
674 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
676 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
678 Type expr_type = expr.Type;
679 if (expr_type == TypeManager.void_type)
682 if (expr.eclass == ExprClass.MethodGroup) {
683 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) {
684 MethodGroupExpr mg = expr as MethodGroupExpr;
686 return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null;
693 //Console.WriteLine ("Expr is {0}", expr);
694 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
695 if (TypeManager.IsEqual (expr_type, target_type))
698 if (TypeManager.IsNullableType (target_type))
699 return ImplicitNulableConversion (null, expr, target_type) != null;
701 // First numeric conversions
702 if (ImplicitNumericConversion (null, expr_type, target_type) != null)
705 if (ImplicitReferenceConversionExists (expr, target_type))
709 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
713 // Implicit Constant Expression Conversions
715 if (expr is IntConstant){
716 int value = ((IntConstant) expr).Value;
718 if (target_type == TypeManager.sbyte_type){
719 if (value >= SByte.MinValue && value <= SByte.MaxValue)
721 } else if (target_type == TypeManager.byte_type){
722 if (value >= 0 && value <= Byte.MaxValue)
724 } else if (target_type == TypeManager.short_type){
725 if (value >= Int16.MinValue && value <= Int16.MaxValue)
727 } else if (target_type == TypeManager.ushort_type){
728 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
730 } else if (target_type == TypeManager.uint32_type){
733 } else if (target_type == TypeManager.uint64_type){
735 // we can optimize this case: a positive int32
736 // always fits on a uint64. But we need an opcode
743 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
747 if (expr is LongConstant && target_type == TypeManager.uint64_type){
749 // Try the implicit constant expression conversion
750 // from long to ulong, instead of a nice routine,
753 long v = ((LongConstant) expr).Value;
759 // If `expr_type' implements `target_type' (which is an iface)
760 // see TryImplicitIntConversion
762 if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
765 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
772 /// Finds "most encompassed type" according to the spec (13.4.2)
773 /// amongst the methods in the MethodGroupExpr
775 static Type FindMostEncompassedType (ArrayList types)
779 if (types.Count == 0)
782 if (types.Count == 1)
783 return (Type) types [0];
785 EmptyExpression expr = EmptyExpression.Grab ();
787 foreach (Type t in types) {
794 if (ImplicitStandardConversionExists (expr, best))
799 foreach (Type t in types) {
802 if (!ImplicitStandardConversionExists (expr, t)) {
808 EmptyExpression.Release (expr);
814 /// Finds "most encompassing type" according to the spec (13.4.2)
815 /// amongst the types in the given set
817 static Type FindMostEncompassingType (ArrayList types)
821 if (types.Count == 0)
824 if (types.Count == 1)
825 return (Type) types [0];
827 EmptyExpression expr = EmptyExpression.Grab ();
829 foreach (Type t in types) {
836 if (ImplicitStandardConversionExists (expr, t))
840 foreach (Type t in types) {
844 if (!ImplicitStandardConversionExists (expr, best)) {
850 EmptyExpression.Release (expr);
856 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
857 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
858 /// for explicit and implicit conversion operators.
860 static public Type FindMostSpecificSource (IList list,
861 Expression source, bool apply_explicit_conv_rules)
863 ArrayList src_types_set = new ArrayList ();
866 // If any operator converts from S then Sx = S
868 Type source_type = source.Type;
869 foreach (MethodBase mb in list){
870 AParametersCollection pd = TypeManager.GetParameterData (mb);
871 Type param_type = pd.Types [0];
873 if (param_type == source_type)
876 src_types_set.Add (param_type);
880 // Explicit Conv rules
882 if (apply_explicit_conv_rules) {
883 ArrayList candidate_set = new ArrayList ();
885 foreach (Type param_type in src_types_set){
886 if (ImplicitStandardConversionExists (source, param_type))
887 candidate_set.Add (param_type);
890 if (candidate_set.Count != 0)
891 return FindMostEncompassedType (candidate_set);
897 if (apply_explicit_conv_rules)
898 return FindMostEncompassingType (src_types_set);
900 return FindMostEncompassedType (src_types_set);
904 /// Finds the most specific target Tx according to section 13.4.4
906 static public Type FindMostSpecificTarget (IList list,
907 Type target, bool apply_explicit_conv_rules)
909 ArrayList tgt_types_set = new ArrayList ();
912 // If any operator converts to T then Tx = T
914 foreach (MethodInfo mi in list){
915 Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType);
916 if (ret_type == target)
919 tgt_types_set.Add (ret_type);
923 // Explicit conv rules
925 if (apply_explicit_conv_rules) {
926 ArrayList candidate_set = new ArrayList ();
928 EmptyExpression expr = EmptyExpression.Grab ();
930 foreach (Type ret_type in tgt_types_set){
931 expr.SetType (ret_type);
933 if (ImplicitStandardConversionExists (expr, target))
934 candidate_set.Add (ret_type);
937 EmptyExpression.Release (expr);
939 if (candidate_set.Count != 0)
940 return FindMostEncompassingType (candidate_set);
944 // Okay, final case !
946 if (apply_explicit_conv_rules)
947 return FindMostEncompassedType (tgt_types_set);
949 return FindMostEncompassingType (tgt_types_set);
953 /// User-defined Implicit conversions
955 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
956 Type target, Location loc)
958 Expression expr = UserDefinedConversion (ec, source, target, loc, false);
959 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
960 expr = ImplicitConversionStandard (ec, expr, target, loc);
966 /// User-defined Explicit conversions
968 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
969 Type target, Location loc)
971 Expression expr = UserDefinedConversion (ec, source, target, loc, true);
972 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
973 expr = ExplicitConversionStandard (ec, expr, target, loc);
978 static void AddConversionOperators (ArrayList list,
979 Expression source, Type target_type,
980 bool look_for_explicit,
986 Type source_type = source.Type;
987 EmptyExpression expr = EmptyExpression.Grab ();
990 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
991 // IntPtr -> uint uses int
992 // UIntPtr -> long uses ulong
994 if (source_type == TypeManager.intptr_type) {
995 if (target_type == TypeManager.uint32_type)
996 target_type = TypeManager.int32_type;
997 } else if (source_type == TypeManager.uintptr_type) {
998 if (target_type == TypeManager.int64_type)
999 target_type = TypeManager.uint64_type;
1002 foreach (MethodInfo m in mg.Methods) {
1003 AParametersCollection pd = TypeManager.GetParameterData (m);
1004 Type return_type = TypeManager.TypeToCoreType (m.ReturnType);
1005 Type arg_type = pd.Types [0];
1007 if (source_type != arg_type) {
1008 if (!ImplicitStandardConversionExists (source, arg_type)) {
1009 if (!look_for_explicit)
1011 expr.SetType (arg_type);
1012 if (!ImplicitStandardConversionExists (expr, source_type))
1017 if (target_type != return_type) {
1018 expr.SetType (return_type);
1019 if (!ImplicitStandardConversionExists (expr, target_type)) {
1020 if (!look_for_explicit)
1022 expr.SetType (target_type);
1023 if (!ImplicitStandardConversionExists (expr, return_type))
1028 // See LAMESPEC: Exclude IntPtr -> int conversion
1029 if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type)
1035 EmptyExpression.Release (expr);
1039 /// Compute the user-defined conversion operator from source_type to target_type.
1040 /// `look_for_explicit' controls whether we should also include the list of explicit operators
1042 static MethodInfo GetConversionOperator (Type container_type, Expression source, Type target_type, bool look_for_explicit)
1044 ArrayList ops = new ArrayList (4);
1046 Type source_type = source.Type;
1048 if (source_type != TypeManager.decimal_type) {
1049 AddConversionOperators (ops, source, target_type, look_for_explicit,
1050 Expression.MethodLookup (container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1051 if (look_for_explicit) {
1052 AddConversionOperators (ops, source, target_type, look_for_explicit,
1053 Expression.MethodLookup (
1054 container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1058 if (target_type != TypeManager.decimal_type) {
1059 AddConversionOperators (ops, source, target_type, look_for_explicit,
1060 Expression.MethodLookup (container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1061 if (look_for_explicit) {
1062 AddConversionOperators (ops, source, target_type, look_for_explicit,
1063 Expression.MethodLookup (
1064 container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1071 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
1072 if (most_specific_source == null)
1075 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
1076 if (most_specific_target == null)
1079 MethodInfo method = null;
1081 foreach (MethodInfo m in ops) {
1082 if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target)
1084 if (TypeManager.GetParameterData (m).Types [0] != most_specific_source)
1086 // Ambiguous: more than one conversion operator satisfies the signature.
1095 static DoubleHash explicit_conv = new DoubleHash (100);
1096 static DoubleHash implicit_conv = new DoubleHash (100);
1099 /// User-defined conversions
1101 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1102 Type target, Location loc,
1103 bool look_for_explicit)
1105 Type source_type = source.Type;
1106 MethodInfo method = null;
1110 if (look_for_explicit) {
1111 hash = explicit_conv;
1113 // Implicit user operators cannot convert to interfaces
1114 if (target.IsInterface)
1117 hash = implicit_conv;
1120 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1121 method = (MethodInfo) o;
1123 method = GetConversionOperator (null, source, target, look_for_explicit);
1124 if (!(source is Constant))
1125 hash.Insert (source_type, target, method);
1131 Type most_specific_source = TypeManager.GetParameterData (method).Types [0];
1134 // This will do the conversion to the best match that we
1135 // found. Now we need to perform an implict standard conversion
1136 // if the best match was not the type that we were requested
1139 if (look_for_explicit)
1140 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1142 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1147 return new UserCast (method, source, loc).DoResolve (ec);
1151 /// Converts implicitly the resolved expression `expr' into the
1152 /// `target_type'. It returns a new expression that can be used
1153 /// in a context that expects a `target_type'.
1155 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1156 Type target_type, Location loc)
1160 if (target_type == null)
1161 throw new Exception ("Target type is null");
1163 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1167 e = ImplicitUserConversion (ec, expr, target_type, loc);
1176 /// Attempts to apply the `Standard Implicit
1177 /// Conversion' rules to the expression `expr' into
1178 /// the `target_type'. It returns a new expression
1179 /// that can be used in a context that expects a
1182 /// This is different from `ImplicitConversion' in that the
1183 /// user defined implicit conversions are excluded.
1185 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1186 Type target_type, Location loc)
1188 return ImplicitConversionStandard (ec, expr, target_type, loc, false);
1191 static Expression ImplicitConversionStandard (EmitContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast)
1193 if (expr.eclass == ExprClass.MethodGroup){
1194 if (!TypeManager.IsDelegateType (target_type)){
1199 // Only allow anonymous method conversions on post ISO_1
1201 if (RootContext.Version != LanguageVersion.ISO_1){
1202 MethodGroupExpr mg = expr as MethodGroupExpr;
1204 return ImplicitDelegateCreation.Create (
1205 ec, mg, target_type, loc);
1209 Type expr_type = expr.Type;
1212 if (expr_type.Equals (target_type)) {
1213 if (expr_type != TypeManager.null_type && expr_type != TypeManager.anonymous_method_type)
1218 if (TypeManager.IsNullableType (target_type))
1219 return ImplicitNulableConversion (ec, expr, target_type);
1222 // Attempt to do the implicit constant expression conversions
1224 Constant c = expr as Constant;
1227 // If `target_type' is an interface and the type of `ic' implements the interface
1228 // e.g. target_type is IComparable, IConvertible, IFormattable
1230 if (c.Type == TypeManager.int32_type && target_type.IsInterface && target_type.IsAssignableFrom (c.Type))
1231 return new BoxedCast (c, target_type);
1234 c = c.ConvertImplicitly (target_type);
1236 Console.WriteLine ("Conversion error happened in line {0}", loc);
1243 e = ImplicitNumericConversion (expr, expr_type, target_type);
1247 e = ImplicitReferenceConversion (expr, target_type, explicit_cast);
1251 if (expr is IntConstant && TypeManager.IsEnumType (target_type)){
1252 Constant i = (Constant) expr;
1254 // LAMESPEC: Conversion from any 0 constant is allowed
1256 // An implicit enumeration conversion permits the decimal-integer-literal 0
1257 // to be converted to any enum-type and to any nullable-type whose underlying
1258 // type is an enum-type
1260 if (i.IsDefaultValue)
1261 return new EnumConstant (i, target_type);
1265 if (expr_type.IsPointer){
1266 if (target_type == TypeManager.void_ptr_type)
1267 return EmptyCast.Create (expr, target_type);
1270 // yep, comparing pointer types cant be done with
1271 // t1 == t2, we have to compare their element types.
1273 if (target_type.IsPointer){
1274 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1281 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1282 return EmptyCast.Create (new NullPointer (loc), target_type);
1285 if (expr_type == TypeManager.anonymous_method_type){
1286 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
1287 Expression am = ame.Compatible (ec, target_type);
1289 return am.DoResolve (ec);
1296 /// Attempts to implicitly convert `source' into `target_type', using
1297 /// ImplicitConversion. If there is no implicit conversion, then
1298 /// an error is signaled
1300 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1301 Type target_type, Location loc)
1303 Expression e = ImplicitConversion (ec, source, target_type, loc);
1307 source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
1312 /// Performs the explicit numeric conversions
1314 /// There are a few conversions that are not part of the C# standard,
1315 /// they were interim hacks in the C# compiler that were supposed to
1316 /// become explicit operators in the UIntPtr class and IntPtr class,
1317 /// but for historical reasons it did not happen, so the C# compiler
1318 /// ended up with these special hacks.
1320 /// See bug 59800 for details.
1322 /// The conversion are:
1332 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1334 Type expr_type = expr.Type;
1335 Type real_target_type = target_type;
1337 if (expr_type == TypeManager.sbyte_type){
1339 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1341 if (real_target_type == TypeManager.byte_type)
1342 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1343 if (real_target_type == TypeManager.ushort_type)
1344 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1345 if (real_target_type == TypeManager.uint32_type)
1346 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1347 if (real_target_type == TypeManager.uint64_type)
1348 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1349 if (real_target_type == TypeManager.char_type)
1350 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1352 // One of the built-in conversions that belonged in the class library
1353 if (real_target_type == TypeManager.uintptr_type){
1354 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I1_U8);
1356 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1358 } else if (expr_type == TypeManager.byte_type){
1360 // From byte to sbyte and char
1362 if (real_target_type == TypeManager.sbyte_type)
1363 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1364 if (real_target_type == TypeManager.char_type)
1365 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1366 } else if (expr_type == TypeManager.short_type){
1368 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1370 if (real_target_type == TypeManager.sbyte_type)
1371 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1372 if (real_target_type == TypeManager.byte_type)
1373 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1374 if (real_target_type == TypeManager.ushort_type)
1375 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1376 if (real_target_type == TypeManager.uint32_type)
1377 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1378 if (real_target_type == TypeManager.uint64_type)
1379 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1380 if (real_target_type == TypeManager.char_type)
1381 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1383 // One of the built-in conversions that belonged in the class library
1384 if (real_target_type == TypeManager.uintptr_type){
1385 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1387 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1389 } else if (expr_type == TypeManager.ushort_type){
1391 // From ushort to sbyte, byte, short, char
1393 if (real_target_type == TypeManager.sbyte_type)
1394 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1395 if (real_target_type == TypeManager.byte_type)
1396 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1397 if (real_target_type == TypeManager.short_type)
1398 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1399 if (real_target_type == TypeManager.char_type)
1400 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1401 } else if (expr_type == TypeManager.int32_type){
1403 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1405 if (real_target_type == TypeManager.sbyte_type)
1406 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1407 if (real_target_type == TypeManager.byte_type)
1408 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1409 if (real_target_type == TypeManager.short_type)
1410 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1411 if (real_target_type == TypeManager.ushort_type)
1412 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1413 if (real_target_type == TypeManager.uint32_type)
1414 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1415 if (real_target_type == TypeManager.uint64_type)
1416 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1417 if (real_target_type == TypeManager.char_type)
1418 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1420 // One of the built-in conversions that belonged in the class library
1421 if (real_target_type == TypeManager.uintptr_type){
1422 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1424 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1426 } else if (expr_type == TypeManager.uint32_type){
1428 // From uint to sbyte, byte, short, ushort, int, char
1430 if (real_target_type == TypeManager.sbyte_type)
1431 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1432 if (real_target_type == TypeManager.byte_type)
1433 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1434 if (real_target_type == TypeManager.short_type)
1435 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1436 if (real_target_type == TypeManager.ushort_type)
1437 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1438 if (real_target_type == TypeManager.int32_type)
1439 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1440 if (real_target_type == TypeManager.char_type)
1441 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1442 } else if (expr_type == TypeManager.int64_type){
1444 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1446 if (real_target_type == TypeManager.sbyte_type)
1447 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1448 if (real_target_type == TypeManager.byte_type)
1449 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1450 if (real_target_type == TypeManager.short_type)
1451 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1452 if (real_target_type == TypeManager.ushort_type)
1453 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1454 if (real_target_type == TypeManager.int32_type)
1455 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1456 if (real_target_type == TypeManager.uint32_type)
1457 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1458 if (real_target_type == TypeManager.uint64_type)
1459 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1460 if (real_target_type == TypeManager.char_type)
1461 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1462 } else if (expr_type == TypeManager.uint64_type){
1464 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1466 if (real_target_type == TypeManager.sbyte_type)
1467 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1468 if (real_target_type == TypeManager.byte_type)
1469 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1470 if (real_target_type == TypeManager.short_type)
1471 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1472 if (real_target_type == TypeManager.ushort_type)
1473 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1474 if (real_target_type == TypeManager.int32_type)
1475 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1476 if (real_target_type == TypeManager.uint32_type)
1477 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1478 if (real_target_type == TypeManager.int64_type)
1479 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1480 if (real_target_type == TypeManager.char_type)
1481 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1483 // One of the built-in conversions that belonged in the class library
1484 if (real_target_type == TypeManager.intptr_type){
1485 return new OperatorCast (EmptyCast.Create (expr, TypeManager.int64_type),
1486 TypeManager.intptr_type, true);
1488 } else if (expr_type == TypeManager.char_type){
1490 // From char to sbyte, byte, short
1492 if (real_target_type == TypeManager.sbyte_type)
1493 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1494 if (real_target_type == TypeManager.byte_type)
1495 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1496 if (real_target_type == TypeManager.short_type)
1497 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1498 } else if (expr_type == TypeManager.float_type){
1500 // From float to sbyte, byte, short,
1501 // ushort, int, uint, long, ulong, char
1504 if (real_target_type == TypeManager.sbyte_type)
1505 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1506 if (real_target_type == TypeManager.byte_type)
1507 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1508 if (real_target_type == TypeManager.short_type)
1509 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1510 if (real_target_type == TypeManager.ushort_type)
1511 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1512 if (real_target_type == TypeManager.int32_type)
1513 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1514 if (real_target_type == TypeManager.uint32_type)
1515 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1516 if (real_target_type == TypeManager.int64_type)
1517 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1518 if (real_target_type == TypeManager.uint64_type)
1519 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1520 if (real_target_type == TypeManager.char_type)
1521 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1522 if (real_target_type == TypeManager.decimal_type)
1523 return new CastToDecimal (expr, true);
1524 } else if (expr_type == TypeManager.double_type){
1526 // From double to sbyte, byte, short,
1527 // ushort, int, uint, long, ulong,
1528 // char, float or decimal
1530 if (real_target_type == TypeManager.sbyte_type)
1531 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1532 if (real_target_type == TypeManager.byte_type)
1533 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1534 if (real_target_type == TypeManager.short_type)
1535 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1536 if (real_target_type == TypeManager.ushort_type)
1537 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1538 if (real_target_type == TypeManager.int32_type)
1539 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1540 if (real_target_type == TypeManager.uint32_type)
1541 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1542 if (real_target_type == TypeManager.int64_type)
1543 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1544 if (real_target_type == TypeManager.uint64_type)
1545 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1546 if (real_target_type == TypeManager.char_type)
1547 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1548 if (real_target_type == TypeManager.float_type)
1549 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1550 if (real_target_type == TypeManager.decimal_type)
1551 return new CastToDecimal (expr, true);
1552 } else if (expr_type == TypeManager.uintptr_type){
1554 // Various built-in conversions that belonged in the class library
1556 // from uintptr to sbyte, short, int32
1558 if (real_target_type == TypeManager.sbyte_type){
1559 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1560 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I1);
1562 if (real_target_type == TypeManager.short_type){
1563 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1564 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I2);
1566 if (real_target_type == TypeManager.int32_type){
1567 return EmptyCast.Create (new OperatorCast (expr, TypeManager.uint32_type, true),
1568 TypeManager.int32_type);
1570 } else if (expr_type == TypeManager.intptr_type){
1571 if (real_target_type == TypeManager.uint64_type){
1572 return EmptyCast.Create (new OperatorCast (expr, TypeManager.int64_type, true),
1573 TypeManager.uint64_type);
1575 } else if (expr_type == TypeManager.decimal_type) {
1576 return new CastFromDecimal (expr, target_type).Resolve ();
1582 /// Returns whether an explicit reference conversion can be performed
1583 /// from source_type to target_type
1585 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1587 Expression e = ExplicitReferenceConversion (null, source_type, target_type);
1591 if (e == EmptyExpression.Null)
1594 throw new InternalErrorException ("Invalid probing conversion result");
1598 /// Implements Explicit Reference conversions
1600 static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type)
1602 bool target_is_value_type = target_type.IsValueType;
1605 // From object to a generic parameter
1607 if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type))
1608 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1611 // Explicit type parameter conversion.
1613 if (TypeManager.IsGenericParameter (source_type))
1614 return ExplicitTypeParameterConversion (source, source_type, target_type);
1617 // From object to any reference type
1619 if (source_type == TypeManager.object_type && !target_is_value_type)
1620 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1623 // Unboxing conversion.
1625 if (((source_type == TypeManager.enum_type &&
1626 !(source is TypeCast)) ||
1627 source_type == TypeManager.value_type) && target_is_value_type)
1628 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1631 // From any class S to any class-type T, provided S is a base class of T
1633 if (TypeManager.IsSubclassOf (target_type, source_type))
1634 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1637 // From any class type S to any interface T, provides S is not sealed
1638 // and provided S does not implement T.
1640 if (target_type.IsInterface && !source_type.IsSealed &&
1641 !TypeManager.ImplementsInterface (source_type, target_type)) {
1642 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1646 // From any interface-type S to to any class type T, provided T is not
1647 // sealed, or provided T implements S.
1649 if (source_type.IsInterface) {
1650 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1651 if (target_type.IsClass)
1652 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1654 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1658 // From System.Collecitons.Generic.IList<T> and its base interfaces to a one-dimensional
1659 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1661 if (IList_To_Array (source_type, target_type))
1662 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1667 if (source_type.IsArray) {
1668 if (target_type.IsArray) {
1670 // From System.Array to any array-type
1672 if (source_type == TypeManager.array_type)
1673 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1676 // From an array type S with an element type Se to an array type T with an
1677 // element type Te provided all the following are true:
1678 // * S and T differe only in element type, in other words, S and T
1679 // have the same number of dimensions.
1680 // * Both Se and Te are reference types
1681 // * An explicit reference conversions exist from Se to Te
1683 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1685 source_type = TypeManager.GetElementType (source_type);
1686 if (!TypeManager.IsReferenceType (source_type))
1689 Type target_type_element = TypeManager.GetElementType (target_type);
1690 if (!TypeManager.IsReferenceType (target_type_element))
1693 if (ExplicitReferenceConversionExists (source_type, target_type_element))
1694 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1701 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1702 // provided that there is an explicit reference conversion from S to T
1704 if (Array_To_IList (source_type, target_type, true))
1705 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1711 // From System delegate to any delegate-type
1713 if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
1714 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1720 /// Performs an explicit conversion of the expression `expr' whose
1721 /// type is expr.Type to `target_type'.
1723 static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
1724 Type target_type, Location loc)
1726 Type expr_type = expr.Type;
1728 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1729 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true);
1734 // Unboxing conversions; only object types can be convertible to enum
1736 if (expr_type == TypeManager.object_type && target_type.IsValueType)
1737 return new UnboxCast (expr, target_type);
1739 if (TypeManager.IsEnumType (expr_type)) {
1740 Expression underlying = EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type));
1741 expr = ExplicitConversionCore (ec, underlying, target_type, loc);
1745 return ExplicitUserConversion (ec, underlying, target_type, loc);
1748 if (TypeManager.IsEnumType (target_type)){
1749 if (expr_type == TypeManager.enum_type)
1750 return new UnboxCast (expr, target_type);
1752 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1754 return EmptyCast.Create (ce, target_type);
1757 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1759 if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
1760 ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1762 return ExplicitConversionCore (ec, ne, target_type, loc);
1768 ne = ExplicitNumericConversion (expr, target_type);
1773 // Skip the ExplicitReferenceConversion because we can not convert
1774 // from Null to a ValueType, and ExplicitReference wont check against
1775 // null literal explicitly
1777 if (expr_type != TypeManager.null_type){
1778 ne = ExplicitReferenceConversion (expr, expr_type, target_type);
1784 ne = ExplicitUnsafe (expr, target_type);
1792 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1794 Type expr_type = expr.Type;
1796 if (target_type.IsPointer){
1797 if (expr_type.IsPointer)
1798 return EmptyCast.Create (expr, target_type);
1800 if (expr_type == TypeManager.sbyte_type ||
1801 expr_type == TypeManager.short_type ||
1802 expr_type == TypeManager.int32_type)
1803 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1805 if (expr_type == TypeManager.ushort_type ||
1806 expr_type == TypeManager.uint32_type ||
1807 expr_type == TypeManager.uint64_type || expr_type == TypeManager.int64_type ||
1808 expr_type == TypeManager.byte_type)
1809 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1812 if (expr_type.IsPointer){
1813 if (target_type == TypeManager.sbyte_type)
1814 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1815 else if (target_type == TypeManager.byte_type)
1816 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1817 else if (target_type == TypeManager.short_type)
1818 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1819 else if (target_type == TypeManager.ushort_type)
1820 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1821 else if (target_type == TypeManager.int32_type)
1822 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1823 else if (target_type == TypeManager.uint32_type)
1824 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1825 else if (target_type == TypeManager.uint64_type || target_type == TypeManager.int64_type)
1826 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1832 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1834 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1835 Type target_type, Location l)
1837 int errors = Report.Errors;
1838 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1839 if (Report.Errors > errors)
1845 ne = ExplicitNumericConversion (expr, target_type);
1849 ne = ExplicitReferenceConversion (expr, expr.Type, target_type);
1853 if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1854 return EmptyCast.Create (expr, target_type);
1856 expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
1861 /// Performs an explicit conversion of the expression `expr' whose
1862 /// type is expr.Type to `target_type'.
1864 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1865 Type target_type, Location loc)
1867 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1872 Type expr_type = expr.Type;
1873 if (TypeManager.IsNullableType (target_type)) {
1874 if (TypeManager.IsNullableType (expr_type)) {
1875 Type target = TypeManager.GetTypeArguments (target_type)[0];
1876 Expression unwrap = Nullable.Unwrap.Create (expr);
1877 e = ExplicitConversion (ec, unwrap, target, expr.Location);
1881 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
1882 } else if (expr_type == TypeManager.object_type) {
1883 return new UnboxCast (expr, target_type);
1885 Type target = TypeManager.GetTypeArguments (target_type) [0];
1887 e = ExplicitConversionCore (ec, expr, target, loc);
1889 return Nullable.Wrap.Create (e, target_type);
1891 } else if (TypeManager.IsNullableType (expr_type)) {
1892 e = Nullable.Unwrap.Create (expr, ec);
1894 bool use_class_cast;
1895 if (ImplicitBoxingConversionExists (e, target_type, out use_class_cast))
1896 return new BoxedCast (expr, target_type);
1898 e = ExplicitConversion (ec, e, target_type, loc);
1900 e = EmptyCast.Create (e, target_type);
1905 e = ExplicitUserConversion (ec, expr, target_type, loc);
1909 expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);