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.
14 using System.Collections.Generic;
17 using IKVM.Reflection.Emit;
19 using System.Reflection.Emit;
22 namespace Mono.CSharp {
25 // A container class for all the conversion operations
27 static class Convert {
29 static EmptyExpression MyEmptyExpr;
36 public static void Reset ()
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 ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit)
48 if (array.Rank != 1 || !list.IsGenericIterateInterface)
51 var arg_type = list.TypeArguments[0];
52 if (array.Element == arg_type)
56 return ExplicitReferenceConversionExists (array.Element, arg_type);
58 if (MyEmptyExpr == null)
59 MyEmptyExpr = new EmptyExpression (array.Element);
61 MyEmptyExpr.SetType (array.Element);
63 return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
66 static bool IList_To_Array(TypeSpec list, ArrayContainer array)
68 if (array.Rank != 1 || !list.IsGenericIterateInterface)
71 var arg_type = list.TypeArguments[0];
72 if (array.Element == arg_type)
75 if (MyEmptyExpr == null)
76 MyEmptyExpr = new EmptyExpression (array.Element);
78 MyEmptyExpr.SetType (array.Element);
80 return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists (array.Element, arg_type);
83 public static Expression ImplicitTypeParameterConversion (Expression expr, TypeSpec target_type)
85 var expr_type = (TypeParameterSpec) expr.Type;
88 // From T to a type parameter U, provided T depends on U
90 var ttype = target_type as TypeParameterSpec;
92 if (expr_type.TypeArguments != null) {
93 foreach (var targ in expr_type.TypeArguments) {
94 if (!TypeSpecComparer.Override.IsEqual (ttype, targ))
97 if (expr_type.IsReferenceType && !ttype.IsReferenceType)
98 return new BoxedCast (expr, target_type);
100 return new ClassCast (expr, target_type);
108 // LAMESPEC: From T to dynamic type because it's like T to object
110 if (target_type.BuildinType == BuildinTypeSpec.Type.Dynamic) {
111 if (expr_type.IsReferenceType)
112 return new ClassCast (expr, target_type);
114 return new BoxedCast (expr, target_type);
118 // From T to its effective base class C
119 // From T to any base class of C (it cannot contain dynamic or be of dynamic type)
120 // From T to any interface implemented by C
122 var base_type = expr_type.GetEffectiveBase ();
123 if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) {
124 if (expr_type.IsReferenceType)
125 return new ClassCast (expr, target_type);
127 return new BoxedCast (expr, target_type);
130 if (target_type.IsInterface && expr_type.IsConvertibleToInterface (target_type)) {
131 if (expr_type.IsReferenceType)
132 return new ClassCast (expr, target_type);
134 return new BoxedCast (expr, target_type);
140 static Expression ExplicitTypeParameterConversion (Expression source, TypeSpec source_type, TypeSpec target_type)
142 var target_tp = target_type as TypeParameterSpec;
143 if (target_tp != null) {
144 if (target_tp.TypeArguments != null) {
145 foreach (var targ in target_tp.TypeArguments) {
146 if (!TypeSpecComparer.Override.IsEqual (source_type, targ))
149 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
153 if (target_tp.Interfaces != null) {
154 foreach (TypeSpec iface in target_tp.Interfaces) {
155 if (!TypeManager.IsGenericParameter (iface))
158 if (TypeManager.IsSubclassOf (source_type, iface))
159 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
166 if (target_type.IsInterface)
167 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
172 public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast)
174 TypeSpec expr_type = expr.Type;
176 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
177 // if we are a method group, emit a warning
182 if (expr_type.Kind == MemberKind.TypeParameter)
183 return ImplicitTypeParameterConversion (expr, target_type);
186 // from the null type to any reference-type.
188 NullLiteral nl = expr as NullLiteral;
190 return nl.ConvertImplicitly (target_type);
193 if (ImplicitReferenceConversionExists (expr, target_type)) {
195 // Avoid wrapping implicitly convertible reference type
200 return EmptyCast.Create (expr, target_type);
203 return ImplicitBoxingConversion (expr, expr_type, target_type);
207 // 6.1.6 Implicit reference conversions
209 public static bool ImplicitReferenceConversionExists (Expression expr, TypeSpec target_type)
211 if (TypeManager.IsStruct (target_type))
214 TypeSpec expr_type = expr.Type;
216 // from the null type to any reference-type.
217 if (expr_type == InternalType.NullLiteral)
218 return target_type != InternalType.AnonymousMethod;
220 if (TypeManager.IsGenericParameter (expr_type))
221 return ImplicitTypeParameterConversion (expr, target_type) != null;
223 // This code is kind of mirrored inside ImplicitStandardConversionExists
224 // with the small distinction that we only probe there
226 // Always ensure that the code here and there is in sync
228 // from any class-type S to any interface-type T.
229 if (target_type.IsInterface) {
230 if (expr_type.ImplementsInterface (target_type, true)){
231 return !TypeManager.IsValueType (expr_type);
236 // Implicit reference conversions (no-boxing) to object or dynamic
238 if (target_type.BuildinType == BuildinTypeSpec.Type.Object || target_type.BuildinType == BuildinTypeSpec.Type.Dynamic) {
239 switch (expr_type.Kind) {
240 case MemberKind.Class:
241 case MemberKind.Interface:
242 case MemberKind.Delegate:
243 case MemberKind.ArrayType:
247 return expr_type.BuildinType == BuildinTypeSpec.Type.Dynamic;
250 if (target_type.BuildinType == BuildinTypeSpec.Type.ValueType)
251 return expr_type.BuildinType == BuildinTypeSpec.Type.Enum;
253 if (expr_type == target_type || TypeSpec.IsBaseClass (expr_type, target_type, true)) {
254 if (TypeManager.IsGenericParameter (expr_type))
257 if (TypeManager.IsValueType (expr_type))
260 // Array type variance conversion
261 //if (target_type.IsArray != expr_type.IsArray)
267 var expr_type_array = expr_type as ArrayContainer;
268 if (expr_type_array != null) {
269 var target_type_array = target_type as ArrayContainer;
270 // from an array-type S to an array-type of type T
271 if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) {
274 // Both SE and TE are reference-types
276 TypeSpec expr_element_type = expr_type_array.Element;
277 if (!TypeManager.IsReferenceType (expr_element_type))
280 TypeSpec target_element_type = target_type_array.Element;
281 if (!TypeManager.IsReferenceType (target_element_type))
284 if (MyEmptyExpr == null)
285 MyEmptyExpr = new EmptyExpression (expr_element_type);
287 MyEmptyExpr.SetType (expr_element_type);
289 return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type);
292 // from an array-type to System.Array
293 if (target_type.BuildinType == BuildinTypeSpec.Type.Array)
296 // from an array-type of type T to IList<T>
297 if (ArrayToIList (expr_type_array, target_type, false))
303 if (TypeSpecComparer.IsEqual (expr_type, target_type))
306 if (TypeSpecComparer.Variant.IsEqual (expr_type, target_type))
309 // from any interface type S to interface-type T.
310 if (expr_type.IsInterface && target_type.IsInterface) {
311 return expr_type.ImplementsInterface (target_type, true);
314 // from any delegate type to System.Delegate
315 if (target_type.BuildinType == BuildinTypeSpec.Type.Delegate &&
316 (expr_type.BuildinType == BuildinTypeSpec.Type.Delegate || expr_type.IsDelegate))
322 public static Expression ImplicitBoxingConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type)
324 switch (target_type.BuildinType) {
326 // From any value-type to the type object.
328 case BuildinTypeSpec.Type.Object:
329 case BuildinTypeSpec.Type.Dynamic:
331 // A pointer type cannot be converted to object
333 if (expr_type.IsPointer)
336 if (!TypeManager.IsValueType (expr_type))
339 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
342 // From any value-type to the type System.ValueType.
344 case BuildinTypeSpec.Type.ValueType:
345 if (!TypeManager.IsValueType (expr_type))
348 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
350 case BuildinTypeSpec.Type.Enum:
352 // From any enum-type to the type System.Enum.
354 if (TypeManager.IsEnumType (expr_type))
355 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
361 // From a nullable-type to a reference type, if a boxing conversion exists from
362 // the underlying type to the reference type
364 if (expr_type.IsNullableType) {
365 if (!TypeManager.IsReferenceType (target_type))
368 var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type);
370 // "cast" underlying type to target type to emit correct InvalidCastException when
371 // underlying hierarchy changes without recompilation
372 if (res != null && expr != null)
373 res = new UnboxCast (res, target_type);
378 if (TypeSpec.IsBaseClass (expr_type, target_type, false)) {
380 // Don't box same type arguments
382 if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type)
383 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
388 // This code is kind of mirrored inside ImplicitStandardConversionExists
389 // with the small distinction that we only probe there
391 // Always ensure that the code here and there is in sync
393 // from any class-type S to any interface-type T.
394 if (target_type.IsInterface) {
395 if (expr_type.ImplementsInterface (target_type, true) &&
396 (TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) {
397 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
404 public static Expression ImplicitNulableConversion (ResolveContext ec, Expression expr, TypeSpec target_type)
406 TypeSpec expr_type = expr.Type;
409 // From null to any nullable type
411 if (expr_type == InternalType.NullLiteral)
412 return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location);
415 TypeSpec t_el = Nullable.NullableInfo.GetUnderlyingType (target_type);
418 if (expr_type.IsNullableType)
419 expr_type = Nullable.NullableInfo.GetUnderlyingType (expr_type);
422 // Predefined implicit identity or implicit numeric conversion
423 // has to exist between underlying type S and underlying type T
426 // conversion exists only mode
428 if (TypeSpecComparer.IsEqual (expr_type, t_el))
429 return EmptyExpression.Null;
431 if (expr is Constant)
432 return ((Constant) expr).ConvertImplicitly (t_el);
434 return ImplicitNumericConversion (null, expr_type, t_el);
438 if (expr_type != expr.Type)
439 unwrap = Nullable.Unwrap.Create (expr);
443 Expression conv = unwrap;
444 if (!TypeSpecComparer.IsEqual (expr_type, t_el)) {
445 if (conv is Constant)
446 conv = ((Constant)conv).ConvertImplicitly (t_el);
448 conv = ImplicitNumericConversion (conv, expr_type, t_el);
454 if (expr_type != expr.Type)
455 return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec);
457 return Nullable.Wrap.Create (conv, target_type);
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 public static Expression ImplicitNumericConversion (Expression expr, TypeSpec target_type)
468 return ImplicitNumericConversion (expr, expr.Type, target_type);
471 static Expression ImplicitNumericConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type)
473 switch (expr_type.BuildinType) {
474 case BuildinTypeSpec.Type.SByte:
476 // From sbyte to short, int, long, float, double, decimal
478 switch (target_type.BuildinType) {
479 case BuildinTypeSpec.Type.Int:
480 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
481 case BuildinTypeSpec.Type.Long:
482 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
483 case BuildinTypeSpec.Type.Double:
484 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
485 case BuildinTypeSpec.Type.Float:
486 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
487 case BuildinTypeSpec.Type.Short:
488 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
489 case BuildinTypeSpec.Type.Decimal:
490 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
495 case BuildinTypeSpec.Type.Byte:
497 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
499 switch (target_type.BuildinType) {
500 case BuildinTypeSpec.Type.Int:
501 case BuildinTypeSpec.Type.UInt:
502 case BuildinTypeSpec.Type.Short:
503 case BuildinTypeSpec.Type.UShort:
504 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
505 case BuildinTypeSpec.Type.ULong:
506 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
507 case BuildinTypeSpec.Type.Long:
508 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
509 case BuildinTypeSpec.Type.Float:
510 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
511 case BuildinTypeSpec.Type.Double:
512 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
513 case BuildinTypeSpec.Type.Decimal:
514 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
517 case BuildinTypeSpec.Type.Short:
519 // From short to int, long, float, double, decimal
521 switch (target_type.BuildinType) {
522 case BuildinTypeSpec.Type.Int:
523 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
524 case BuildinTypeSpec.Type.Long:
525 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
526 case BuildinTypeSpec.Type.Double:
527 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
528 case BuildinTypeSpec.Type.Float:
529 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
530 case BuildinTypeSpec.Type.Decimal:
531 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
534 case BuildinTypeSpec.Type.UShort:
536 // From ushort to int, uint, long, ulong, float, double, decimal
538 switch (target_type.BuildinType) {
539 case BuildinTypeSpec.Type.Int:
540 case BuildinTypeSpec.Type.UInt:
541 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
542 case BuildinTypeSpec.Type.ULong:
543 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
544 case BuildinTypeSpec.Type.Long:
545 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
546 case BuildinTypeSpec.Type.Double:
547 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
548 case BuildinTypeSpec.Type.Float:
549 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
550 case BuildinTypeSpec.Type.Decimal:
551 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
554 case BuildinTypeSpec.Type.Int:
556 // From int to long, float, double, decimal
558 switch (target_type.BuildinType) {
559 case BuildinTypeSpec.Type.Long:
560 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
561 case BuildinTypeSpec.Type.Double:
562 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
563 case BuildinTypeSpec.Type.Float:
564 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
565 case BuildinTypeSpec.Type.Decimal:
566 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
569 case BuildinTypeSpec.Type.UInt:
571 // From uint to long, ulong, float, double, decimal
573 switch (target_type.BuildinType) {
574 case BuildinTypeSpec.Type.Long:
575 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
576 case BuildinTypeSpec.Type.ULong:
577 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
578 case BuildinTypeSpec.Type.Double:
579 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8);
580 case BuildinTypeSpec.Type.Float:
581 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4);
582 case BuildinTypeSpec.Type.Decimal:
583 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
586 case BuildinTypeSpec.Type.Long:
588 // From long to float, double, decimal
590 switch (target_type.BuildinType) {
591 case BuildinTypeSpec.Type.Double:
592 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
593 case BuildinTypeSpec.Type.Float:
594 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
595 case BuildinTypeSpec.Type.Decimal:
596 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
599 case BuildinTypeSpec.Type.ULong:
601 // From ulong to float, double, decimal
603 switch (target_type.BuildinType) {
604 case BuildinTypeSpec.Type.Double:
605 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8);
606 case BuildinTypeSpec.Type.Float:
607 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4);
608 case BuildinTypeSpec.Type.Decimal:
609 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
612 case BuildinTypeSpec.Type.Char:
614 // From char to ushort, int, uint, long, ulong, float, double, decimal
616 switch (target_type.BuildinType) {
617 case BuildinTypeSpec.Type.UShort:
618 case BuildinTypeSpec.Type.Int:
619 case BuildinTypeSpec.Type.UInt:
620 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
621 case BuildinTypeSpec.Type.ULong:
622 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
623 case BuildinTypeSpec.Type.Long:
624 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
625 case BuildinTypeSpec.Type.Float:
626 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
627 case BuildinTypeSpec.Type.Double:
628 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
629 case BuildinTypeSpec.Type.Decimal:
630 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type);
633 case BuildinTypeSpec.Type.Float:
637 if (target_type.BuildinType == BuildinTypeSpec.Type.Double)
638 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
646 /// Same as ImplicitStandardConversionExists except that it also looks at
647 /// implicit user defined conversions - needed for overload resolution
649 public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, TypeSpec target_type)
651 if (ImplicitStandardConversionExists (expr, target_type))
654 if (expr.Type == InternalType.AnonymousMethod) {
655 if (!target_type.IsDelegate && !target_type.IsExpressionTreeType)
658 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
659 return ame.ImplicitStandardConversionExists (ec, target_type);
662 if (expr.eclass == ExprClass.MethodGroup) {
663 if (target_type.IsDelegate && ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) {
664 MethodGroupExpr mg = expr as MethodGroupExpr;
666 return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type);
672 // Conversion from __arglist to System.ArgIterator
673 if (expr.Type == InternalType.Arglist)
674 return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec;
676 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
680 /// Determines if a standard implicit conversion exists from
681 /// expr_type to target_type
684 public static bool ImplicitStandardConversionExists (Expression expr, TypeSpec target_type)
686 TypeSpec expr_type = expr.Type;
688 NullLiteral nl = expr as NullLiteral;
690 return nl.ConvertImplicitly (target_type) != null;
692 if (expr_type == target_type)
695 // Implicit dynamic conversion
696 if (expr_type.BuildinType == BuildinTypeSpec.Type.Dynamic) {
697 switch (target_type.Kind) {
698 case MemberKind.ArrayType:
699 case MemberKind.Class:
700 case MemberKind.Struct:
701 case MemberKind.Delegate:
702 case MemberKind.Enum:
703 case MemberKind.Interface:
704 case MemberKind.TypeParameter:
708 // dynamic to __arglist
709 if (target_type == InternalType.Arglist)
715 if (target_type.IsNullableType) {
716 return ImplicitNulableConversion (null, expr, target_type) != null;
719 // First numeric conversions
720 if (ImplicitNumericConversion (null, expr_type, target_type) != null)
723 if (ImplicitReferenceConversionExists (expr, target_type))
726 if (ImplicitBoxingConversion (null, expr_type, target_type) != null)
730 // Implicit Constant Expression Conversions
732 if (expr is IntConstant){
733 int value = ((IntConstant) expr).Value;
734 switch (target_type.BuildinType) {
735 case BuildinTypeSpec.Type.SByte:
736 if (value >= SByte.MinValue && value <= SByte.MaxValue)
739 case BuildinTypeSpec.Type.Byte:
740 if (value >= 0 && value <= Byte.MaxValue)
743 case BuildinTypeSpec.Type.Short:
744 if (value >= Int16.MinValue && value <= Int16.MaxValue)
747 case BuildinTypeSpec.Type.UShort:
748 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
751 case BuildinTypeSpec.Type.UInt:
755 case BuildinTypeSpec.Type.ULong:
757 // we can optimize this case: a positive int32
758 // always fits on a uint64. But we need an opcode
768 if (expr is LongConstant && target_type.BuildinType == BuildinTypeSpec.Type.ULong){
770 // Try the implicit constant expression conversion
771 // from long to ulong, instead of a nice routine,
774 long v = ((LongConstant) expr).Value;
779 if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)) {
780 var i = (IntegralConstant) expr;
782 // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0
784 // An implicit enumeration conversion permits the decimal-integer-literal 0
785 // to be converted to any enum-type and to any nullable-type whose underlying
786 // type is an enum-type
788 return i.IsZeroInteger;
792 // If `expr_type' implements `target_type' (which is an iface)
793 // see TryImplicitIntConversion
795 if (target_type.IsInterface && expr_type.ImplementsInterface (target_type, true))
798 if (target_type.IsPointer && expr_type.IsPointer && ((PointerContainer) target_type).Element.Kind == MemberKind.Void)
801 if (TypeSpecComparer.IsEqual (expr_type, target_type))
808 /// Finds "most encompassed type" according to the spec (13.4.2)
809 /// amongst the methods in the MethodGroupExpr
811 public static TypeSpec FindMostEncompassedType (IEnumerable<TypeSpec> types)
813 TypeSpec best = null;
814 EmptyExpression expr = EmptyExpression.Grab ();
816 foreach (TypeSpec t in types) {
823 if (ImplicitStandardConversionExists (expr, best))
828 foreach (TypeSpec t in types) {
831 if (!ImplicitStandardConversionExists (expr, t)) {
837 EmptyExpression.Release (expr);
843 /// Finds "most encompassing type" according to the spec (13.4.2)
844 /// amongst the types in the given set
846 static TypeSpec FindMostEncompassingType (IList<TypeSpec> types)
848 TypeSpec best = null;
850 if (types.Count == 0)
853 if (types.Count == 1)
856 EmptyExpression expr = EmptyExpression.Grab ();
858 foreach (TypeSpec t in types) {
865 if (ImplicitStandardConversionExists (expr, t))
869 foreach (TypeSpec t in types) {
873 if (!ImplicitStandardConversionExists (expr, best)) {
879 EmptyExpression.Release (expr);
885 // Finds the most specific source Sx according to the rules of the spec (13.4.4)
886 // by making use of FindMostEncomp* methods. Applies the correct rules separately
887 // for explicit and implicit conversion operators.
889 static TypeSpec FindMostSpecificSource (List<MethodSpec> list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules)
891 var src_types_set = new TypeSpec [list.Count];
894 // Try exact match first, if any operator converts from S then Sx = S
896 for (int i = 0; i < src_types_set.Length; ++i) {
897 TypeSpec param_type = list [i].Parameters.Types [0];
899 if (param_type == sourceType)
902 src_types_set [i] = param_type;
906 // Explicit Conv rules
908 if (apply_explicit_conv_rules) {
909 var candidate_set = new List<TypeSpec> ();
911 foreach (TypeSpec param_type in src_types_set){
912 if (ImplicitStandardConversionExists (source, param_type))
913 candidate_set.Add (param_type);
916 if (candidate_set.Count != 0)
917 return FindMostEncompassedType (candidate_set);
923 if (apply_explicit_conv_rules)
924 return FindMostEncompassingType (src_types_set);
926 return FindMostEncompassedType (src_types_set);
930 /// Finds the most specific target Tx according to section 13.4.4
932 static public TypeSpec FindMostSpecificTarget (IList<MethodSpec> list,
933 TypeSpec target, bool apply_explicit_conv_rules)
935 var tgt_types_set = new List<TypeSpec> ();
938 // If any operator converts to T then Tx = T
940 foreach (var mi in list){
941 TypeSpec ret_type = mi.ReturnType;
942 if (ret_type == target)
945 tgt_types_set.Add (ret_type);
949 // Explicit conv rules
951 if (apply_explicit_conv_rules) {
952 var candidate_set = new List<TypeSpec> ();
954 EmptyExpression expr = EmptyExpression.Grab ();
956 foreach (TypeSpec ret_type in tgt_types_set){
957 expr.SetType (ret_type);
959 if (ImplicitStandardConversionExists (expr, target))
960 candidate_set.Add (ret_type);
963 EmptyExpression.Release (expr);
965 if (candidate_set.Count != 0)
966 return FindMostEncompassingType (candidate_set);
970 // Okay, final case !
972 if (apply_explicit_conv_rules)
973 return FindMostEncompassedType (tgt_types_set);
975 return FindMostEncompassingType (tgt_types_set);
979 /// User-defined Implicit conversions
981 static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc)
983 return UserDefinedConversion (ec, source, target, true, loc);
987 /// User-defined Explicit conversions
989 static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc)
991 return UserDefinedConversion (ec, source, target, false, loc);
994 static void FindApplicableUserDefinedConversionOperators (IList<MemberSpec> operators, Expression source, TypeSpec target, bool implicitOnly, ref List<MethodSpec> candidates)
996 if (source.Type.IsInterface) {
997 // Neither A nor B are interface-types
1001 // For a conversion operator to be applicable, it must be possible
1002 // to perform a standard conversion from the source type to
1003 // the operand type of the operator, and it must be possible
1004 // to perform a standard conversion from the result type of
1005 // the operator to the target type.
1007 Expression texpr = null;
1009 foreach (MethodSpec op in operators) {
1011 // Can be null because MemberCache.GetUserOperator does not resize the array
1015 var t = op.Parameters.Types[0];
1016 if (source.Type != t && !ImplicitStandardConversionExists (source, t)) {
1020 if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type))
1030 if (t.IsNullableType)
1031 t = Nullable.NullableInfo.GetUnderlyingType (t);
1033 if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) {
1038 texpr = new EmptyExpression (target);
1040 if (!ImplicitStandardConversionExists (texpr, t))
1045 if (candidates == null)
1046 candidates = new List<MethodSpec> ();
1048 candidates.Add (op);
1053 // User-defined conversions
1055 static Expression UserDefinedConversion (ResolveContext ec, Expression source, TypeSpec target, bool implicitOnly, Location loc)
1057 List<MethodSpec> candidates = null;
1060 // If S or T are nullable types, source_type and target_type are their underlying types
1061 // otherwise source_type and target_type are equal to S and T respectively.
1063 TypeSpec source_type = source.Type;
1064 TypeSpec target_type = target;
1065 Expression source_type_expr;
1067 if (source_type.IsNullableType) {
1068 // No implicit conversion S? -> T for non-reference types
1069 if (implicitOnly && !TypeManager.IsReferenceType (target_type) && !target_type.IsNullableType)
1072 source_type_expr = Nullable.Unwrap.Create (source);
1073 source_type = source_type_expr.Type;
1075 source_type_expr = source;
1078 if (target_type.IsNullableType)
1079 target_type = Nullable.NullableInfo.GetUnderlyingType (target_type);
1081 // Only these containers can contain a user defined implicit or explicit operators
1082 const MemberKind user_conversion_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.TypeParameter;
1084 if ((source_type.Kind & user_conversion_kinds) != 0 && source_type.BuildinType != BuildinTypeSpec.Type.Decimal) {
1085 bool declared_only = source_type.IsStruct;
1087 var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only);
1088 if (operators != null) {
1089 FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
1092 if (!implicitOnly) {
1093 operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only);
1094 if (operators != null) {
1095 FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
1100 if ((target.Kind & user_conversion_kinds) != 0 && target_type.BuildinType != BuildinTypeSpec.Type.Decimal) {
1101 bool declared_only = target.IsStruct || implicitOnly;
1103 var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only);
1104 if (operators != null) {
1105 FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, implicitOnly, ref candidates);
1108 if (!implicitOnly) {
1109 operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only);
1110 if (operators != null) {
1111 FindApplicableUserDefinedConversionOperators (operators, source_type_expr, target_type, false, ref candidates);
1116 if (candidates == null)
1120 // Find the most specific conversion operator
1122 MethodSpec most_specific_operator;
1124 if (candidates.Count == 1) {
1125 most_specific_operator = candidates[0];
1126 s_x = most_specific_operator.Parameters.Types[0];
1127 t_x = most_specific_operator.ReturnType;
1130 // Pass original source type to find the best match against input type and
1131 // not the unwrapped expression
1133 s_x = FindMostSpecificSource (candidates, source.Type, source_type_expr, !implicitOnly);
1137 t_x = FindMostSpecificTarget (candidates, target, !implicitOnly);
1141 most_specific_operator = null;
1142 for (int i = 0; i < candidates.Count; ++i) {
1143 if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) {
1144 most_specific_operator = candidates[i];
1149 if (most_specific_operator == null) {
1150 MethodSpec ambig_arg = null;
1151 foreach (var candidate in candidates) {
1152 if (candidate.ReturnType == t_x)
1153 most_specific_operator = candidate;
1154 else if (candidate.Parameters.Types[0] == s_x)
1155 ambig_arg = candidate;
1158 ec.Report.Error (457, loc,
1159 "Ambiguous user defined operators `{0}' and `{1}' when converting from `{2}' to `{3}'",
1160 ambig_arg.GetSignatureForError (), most_specific_operator.GetSignatureForError (),
1161 source.Type.GetSignatureForError (), target.GetSignatureForError ());
1166 // Convert input type when it's different to best operator argument
1168 if (s_x != source_type) {
1169 var c = source as Constant;
1171 source = c.TryReduce (ec, s_x, loc);
1173 source = implicitOnly ?
1174 ImplicitConversionStandard (ec, source_type_expr, s_x, loc) :
1175 ExplicitConversionStandard (ec, source_type_expr, s_x, loc);
1178 source = source_type_expr;
1181 source = new UserCast (most_specific_operator, source, loc).Resolve (ec);
1184 // Convert result type when it's different to best operator return type
1186 if (t_x != target_type) {
1188 // User operator is of T?, no need to lift it
1190 if (t_x == target && t_x.IsNullableType)
1193 source = implicitOnly ?
1194 ImplicitConversionStandard (ec, source, target_type, loc) :
1195 ExplicitConversionStandard (ec, source, target_type, loc);
1202 // Source expression is of nullable type, lift the result in the case it's null and
1203 // not nullable/lifted user operator is used
1205 if (source_type_expr is Nullable.Unwrap && !s_x.IsNullableType && (TypeManager.IsReferenceType (target) || target_type != target))
1206 source = new Nullable.Lifted (source, source_type_expr, target).Resolve (ec);
1207 else if (target_type != target)
1208 source = Nullable.Wrap.Create (source, target);
1214 /// Converts implicitly the resolved expression `expr' into the
1215 /// `target_type'. It returns a new expression that can be used
1216 /// in a context that expects a `target_type'.
1218 static public Expression ImplicitConversion (ResolveContext ec, Expression expr,
1219 TypeSpec target_type, Location loc)
1223 if (target_type == null)
1224 throw new Exception ("Target type is null");
1226 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1230 e = ImplicitUserConversion (ec, expr, target_type, loc);
1239 /// Attempts to apply the `Standard Implicit
1240 /// Conversion' rules to the expression `expr' into
1241 /// the `target_type'. It returns a new expression
1242 /// that can be used in a context that expects a
1245 /// This is different from `ImplicitConversion' in that the
1246 /// user defined implicit conversions are excluded.
1248 static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr,
1249 TypeSpec target_type, Location loc)
1251 return ImplicitConversionStandard (ec, expr, target_type, loc, false);
1254 static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, TypeSpec target_type, Location loc, bool explicit_cast)
1256 if (expr.eclass == ExprClass.MethodGroup){
1257 if (!TypeManager.IsDelegateType (target_type)){
1262 // Only allow anonymous method conversions on post ISO_1
1264 if (ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1){
1265 MethodGroupExpr mg = expr as MethodGroupExpr;
1267 return ImplicitDelegateCreation.Create (
1268 ec, mg, target_type, loc);
1272 TypeSpec expr_type = expr.Type;
1275 if (expr_type == target_type) {
1276 if (expr_type != InternalType.NullLiteral && expr_type != InternalType.AnonymousMethod)
1281 if (expr_type.BuildinType == BuildinTypeSpec.Type.Dynamic) {
1282 switch (target_type.Kind) {
1283 case MemberKind.ArrayType:
1284 case MemberKind.Class:
1285 if (target_type.BuildinType == BuildinTypeSpec.Type.Object)
1286 return EmptyCast.Create (expr, target_type);
1288 goto case MemberKind.Struct;
1289 case MemberKind.Struct:
1290 case MemberKind.Delegate:
1291 case MemberKind.Enum:
1292 case MemberKind.Interface:
1293 case MemberKind.TypeParameter:
1294 Arguments args = new Arguments (1);
1295 args.Add (new Argument (expr));
1296 return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec);
1302 if (target_type.IsNullableType)
1303 return ImplicitNulableConversion (ec, expr, target_type);
1306 // Attempt to do the implicit constant expression conversions
1308 Constant c = expr as Constant;
1311 c = c.ConvertImplicitly (target_type);
1313 Console.WriteLine ("Conversion error happened in line {0}", loc);
1320 e = ImplicitNumericConversion (expr, expr_type, target_type);
1324 e = ImplicitReferenceConversion (expr, target_type, explicit_cast);
1328 if (expr is IntegralConstant && TypeManager.IsEnumType (target_type)){
1329 var i = (IntegralConstant) expr;
1331 // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0
1333 // An implicit enumeration conversion permits the decimal-integer-literal 0
1334 // to be converted to any enum-type and to any nullable-type whose underlying
1335 // type is an enum-type
1337 if (i.IsZeroInteger) {
1338 // Recreate 0 literal to remove any collected conversions
1339 return new EnumConstant (new IntLiteral (ec.BuildinTypes, 0, i.Location), target_type);
1344 var target_pc = target_type as PointerContainer;
1345 if (target_pc != null) {
1346 if (expr_type.IsPointer) {
1348 // Pointer types are same when they have same element types
1350 if (expr_type == target_pc)
1353 if (target_pc.Element.Kind == MemberKind.Void)
1354 return EmptyCast.Create (expr, target_type);
1359 if (expr_type == InternalType.NullLiteral)
1360 return new NullPointer (target_type, loc);
1364 if (expr_type == InternalType.AnonymousMethod){
1365 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
1366 Expression am = ame.Compatible (ec, target_type);
1368 return am.Resolve (ec);
1371 if (expr_type == InternalType.Arglist && target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec)
1374 if (TypeSpecComparer.IsEqual (expr_type, target_type)) {
1375 if (expr_type == target_type)
1378 return EmptyCast.Create (expr, target_type);
1385 /// Attempts to implicitly convert `source' into `target_type', using
1386 /// ImplicitConversion. If there is no implicit conversion, then
1387 /// an error is signaled
1389 static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source,
1390 TypeSpec target_type, Location loc)
1392 Expression e = ImplicitConversion (ec, source, target_type, loc);
1396 source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
1401 /// Performs the explicit numeric conversions
1403 /// There are a few conversions that are not part of the C# standard,
1404 /// they were interim hacks in the C# compiler that were supposed to
1405 /// become explicit operators in the UIntPtr class and IntPtr class,
1406 /// but for historical reasons it did not happen, so the C# compiler
1407 /// ended up with these special hacks.
1409 /// See bug 59800 for details.
1411 /// The conversion are:
1421 public static Expression ExplicitNumericConversion (ResolveContext rc, Expression expr, TypeSpec target_type)
1423 // Not all predefined explicit numeric conversion are
1424 // defined here, for some of them (mostly IntPtr/UIntPtr) we
1425 // defer to user-operator handling which is now perfect but
1428 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
1429 // IntPtr -> uint uses int
1430 // UIntPtr -> long uses ulong
1433 switch (expr.Type.BuildinType) {
1434 case BuildinTypeSpec.Type.SByte:
1436 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1438 switch (target_type.BuildinType) {
1439 case BuildinTypeSpec.Type.Byte:
1440 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1441 case BuildinTypeSpec.Type.UShort:
1442 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1443 case BuildinTypeSpec.Type.UInt:
1444 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1445 case BuildinTypeSpec.Type.ULong:
1446 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1447 case BuildinTypeSpec.Type.Char:
1448 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1450 // One of the built-in conversions that belonged in the class library
1451 case BuildinTypeSpec.Type.UIntPtr:
1452 return new OperatorCast (new ConvCast (expr, rc.BuildinTypes.ULong, ConvCast.Mode.I1_U8), target_type, target_type, true);
1455 case BuildinTypeSpec.Type.Byte:
1457 // From byte to sbyte and char
1459 switch (target_type.BuildinType) {
1460 case BuildinTypeSpec.Type.SByte:
1461 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1462 case BuildinTypeSpec.Type.Char:
1463 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1466 case BuildinTypeSpec.Type.Short:
1468 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1470 switch (target_type.BuildinType) {
1471 case BuildinTypeSpec.Type.SByte:
1472 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1473 case BuildinTypeSpec.Type.Byte:
1474 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1475 case BuildinTypeSpec.Type.UShort:
1476 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1477 case BuildinTypeSpec.Type.UInt:
1478 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1479 case BuildinTypeSpec.Type.ULong:
1480 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1481 case BuildinTypeSpec.Type.Char:
1482 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1484 // One of the built-in conversions that belonged in the class library
1485 case BuildinTypeSpec.Type.UIntPtr:
1486 return new OperatorCast (new ConvCast (expr, rc.BuildinTypes.ULong, ConvCast.Mode.I2_U8), target_type, target_type, true);
1489 case BuildinTypeSpec.Type.UShort:
1491 // From ushort to sbyte, byte, short, char
1493 switch (target_type.BuildinType) {
1494 case BuildinTypeSpec.Type.SByte:
1495 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1496 case BuildinTypeSpec.Type.Byte:
1497 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1498 case BuildinTypeSpec.Type.Short:
1499 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1500 case BuildinTypeSpec.Type.Char:
1501 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1504 case BuildinTypeSpec.Type.Int:
1506 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1508 switch (target_type.BuildinType) {
1509 case BuildinTypeSpec.Type.SByte:
1510 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1511 case BuildinTypeSpec.Type.Byte:
1512 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1513 case BuildinTypeSpec.Type.Short:
1514 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1515 case BuildinTypeSpec.Type.UShort:
1516 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1517 case BuildinTypeSpec.Type.UInt:
1518 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1519 case BuildinTypeSpec.Type.ULong:
1520 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1521 case BuildinTypeSpec.Type.Char:
1522 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1524 // One of the built-in conversions that belonged in the class library
1525 case BuildinTypeSpec.Type.UIntPtr:
1526 return new OperatorCast (new ConvCast (expr, rc.BuildinTypes.ULong, ConvCast.Mode.I2_U8), target_type, target_type, true);
1529 case BuildinTypeSpec.Type.UInt:
1531 // From uint to sbyte, byte, short, ushort, int, char
1533 switch (target_type.BuildinType) {
1534 case BuildinTypeSpec.Type.SByte:
1535 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1536 case BuildinTypeSpec.Type.Byte:
1537 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1538 case BuildinTypeSpec.Type.Short:
1539 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1540 case BuildinTypeSpec.Type.UShort:
1541 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1542 case BuildinTypeSpec.Type.Int:
1543 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1544 case BuildinTypeSpec.Type.Char:
1545 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1548 case BuildinTypeSpec.Type.Long:
1550 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1552 switch (target_type.BuildinType) {
1553 case BuildinTypeSpec.Type.SByte:
1554 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1555 case BuildinTypeSpec.Type.Byte:
1556 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1557 case BuildinTypeSpec.Type.Short:
1558 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1559 case BuildinTypeSpec.Type.UShort:
1560 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1561 case BuildinTypeSpec.Type.Int:
1562 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1563 case BuildinTypeSpec.Type.UInt:
1564 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1565 case BuildinTypeSpec.Type.ULong:
1566 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1567 case BuildinTypeSpec.Type.Char:
1568 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1571 case BuildinTypeSpec.Type.ULong:
1573 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1575 switch (target_type.BuildinType) {
1576 case BuildinTypeSpec.Type.SByte:
1577 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1578 case BuildinTypeSpec.Type.Byte:
1579 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1580 case BuildinTypeSpec.Type.Short:
1581 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1582 case BuildinTypeSpec.Type.UShort:
1583 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1584 case BuildinTypeSpec.Type.Int:
1585 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1586 case BuildinTypeSpec.Type.UInt:
1587 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1588 case BuildinTypeSpec.Type.Long:
1589 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1590 case BuildinTypeSpec.Type.Char:
1591 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1593 // One of the built-in conversions that belonged in the class library
1594 case BuildinTypeSpec.Type.IntPtr:
1595 return new OperatorCast (EmptyCast.Create (expr, rc.BuildinTypes.Long), target_type, true);
1598 case BuildinTypeSpec.Type.Char:
1600 // From char to sbyte, byte, short
1602 switch (target_type.BuildinType) {
1603 case BuildinTypeSpec.Type.SByte:
1604 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1605 case BuildinTypeSpec.Type.Byte:
1606 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1607 case BuildinTypeSpec.Type.Short:
1608 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1611 case BuildinTypeSpec.Type.Float:
1613 // From float to sbyte, byte, short,
1614 // ushort, int, uint, long, ulong, char
1617 switch (target_type.BuildinType) {
1618 case BuildinTypeSpec.Type.SByte:
1619 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1620 case BuildinTypeSpec.Type.Byte:
1621 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1622 case BuildinTypeSpec.Type.Short:
1623 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1624 case BuildinTypeSpec.Type.UShort:
1625 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1626 case BuildinTypeSpec.Type.Int:
1627 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1628 case BuildinTypeSpec.Type.UInt:
1629 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1630 case BuildinTypeSpec.Type.Long:
1631 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1632 case BuildinTypeSpec.Type.ULong:
1633 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1634 case BuildinTypeSpec.Type.Char:
1635 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1636 case BuildinTypeSpec.Type.Decimal:
1637 return new OperatorCast (expr, target_type, true);
1640 case BuildinTypeSpec.Type.Double:
1642 // From double to sbyte, byte, short,
1643 // ushort, int, uint, long, ulong,
1644 // char, float or decimal
1646 switch (target_type.BuildinType) {
1647 case BuildinTypeSpec.Type.SByte:
1648 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1649 case BuildinTypeSpec.Type.Byte:
1650 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1651 case BuildinTypeSpec.Type.Short:
1652 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1653 case BuildinTypeSpec.Type.UShort:
1654 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1655 case BuildinTypeSpec.Type.Int:
1656 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1657 case BuildinTypeSpec.Type.UInt:
1658 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1659 case BuildinTypeSpec.Type.Long:
1660 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1661 case BuildinTypeSpec.Type.ULong:
1662 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1663 case BuildinTypeSpec.Type.Char:
1664 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1665 case BuildinTypeSpec.Type.Float:
1666 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1667 case BuildinTypeSpec.Type.Decimal:
1668 return new OperatorCast (expr, target_type, true);
1671 case BuildinTypeSpec.Type.UIntPtr:
1673 // Various built-in conversions that belonged in the class library
1675 // from uintptr to sbyte, short, int32
1677 switch (target_type.BuildinType) {
1678 case BuildinTypeSpec.Type.SByte:
1679 return new ConvCast (new OperatorCast (expr, expr.Type, rc.BuildinTypes.UInt, true), target_type, ConvCast.Mode.U4_I1);
1680 case BuildinTypeSpec.Type.Short:
1681 return new ConvCast (new OperatorCast (expr, expr.Type, rc.BuildinTypes.UInt, true), target_type, ConvCast.Mode.U4_I2);
1682 case BuildinTypeSpec.Type.Int:
1683 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuildinTypes.UInt, true), target_type);
1684 case BuildinTypeSpec.Type.UInt:
1685 return new OperatorCast (expr, expr.Type, target_type, true);
1686 case BuildinTypeSpec.Type.Long:
1687 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuildinTypes.ULong, true), target_type);
1690 case BuildinTypeSpec.Type.IntPtr:
1691 if (target_type.BuildinType == BuildinTypeSpec.Type.UInt)
1692 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuildinTypes.Int, true), target_type);
1693 if (target_type.BuildinType == BuildinTypeSpec.Type.ULong)
1694 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuildinTypes.Long, true), target_type);
1697 case BuildinTypeSpec.Type.Decimal:
1698 // From decimal to sbyte, byte, short,
1699 // ushort, int, uint, long, ulong, char,
1701 switch (target_type.BuildinType) {
1702 case BuildinTypeSpec.Type.SByte:
1703 case BuildinTypeSpec.Type.Byte:
1704 case BuildinTypeSpec.Type.Short:
1705 case BuildinTypeSpec.Type.UShort:
1706 case BuildinTypeSpec.Type.Int:
1707 case BuildinTypeSpec.Type.UInt:
1708 case BuildinTypeSpec.Type.Long:
1709 case BuildinTypeSpec.Type.ULong:
1710 case BuildinTypeSpec.Type.Char:
1711 case BuildinTypeSpec.Type.Float:
1712 case BuildinTypeSpec.Type.Double:
1713 return new OperatorCast (expr, expr.Type, target_type, true);
1723 /// Returns whether an explicit reference conversion can be performed
1724 /// from source_type to target_type
1726 public static bool ExplicitReferenceConversionExists (TypeSpec source_type, TypeSpec target_type)
1728 Expression e = ExplicitReferenceConversion (null, source_type, target_type);
1732 if (e == EmptyExpression.Null)
1735 throw new InternalErrorException ("Invalid probing conversion result");
1739 /// Implements Explicit Reference conversions
1741 static Expression ExplicitReferenceConversion (Expression source, TypeSpec source_type, TypeSpec target_type)
1744 // From object to a generic parameter
1746 if (source_type.BuildinType == BuildinTypeSpec.Type.Object && TypeManager.IsGenericParameter (target_type))
1747 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1750 // Explicit type parameter conversion.
1752 if (source_type.Kind == MemberKind.TypeParameter)
1753 return ExplicitTypeParameterConversion (source, source_type, target_type);
1755 bool target_is_value_type = TypeManager.IsStruct (target_type) || TypeManager.IsEnumType (target_type);
1758 // Unboxing conversion from System.ValueType to any non-nullable-value-type
1760 if (source_type.BuildinType == BuildinTypeSpec.Type.ValueType && target_is_value_type)
1761 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1764 // From object or dynamic to any reference type or value type (unboxing)
1766 if (source_type.BuildinType == BuildinTypeSpec.Type.Object || source_type.BuildinType == BuildinTypeSpec.Type.Dynamic) {
1767 if (target_type.IsPointer)
1771 source == null ? EmptyExpression.Null :
1772 target_is_value_type ? new UnboxCast (source, target_type) :
1773 source is Constant ? (Expression) new EmptyConstantCast ((Constant) source, target_type) :
1774 new ClassCast (source, target_type);
1778 // From any class S to any class-type T, provided S is a base class of T
1780 if (source_type.Kind == MemberKind.Class && TypeSpec.IsBaseClass (target_type, source_type, true))
1781 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1784 // From any interface-type S to to any class type T, provided T is not
1785 // sealed, or provided T implements S.
1787 if (source_type.Kind == MemberKind.Interface) {
1788 if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) {
1790 return EmptyExpression.Null;
1793 // Unboxing conversion from any interface-type to any non-nullable-value-type that
1794 // implements the interface-type
1796 return target_is_value_type ? new UnboxCast (source, target_type) : (Expression) new ClassCast (source, target_type);
1800 // From System.Collections.Generic.IList<T> and its base interfaces to a one-dimensional
1801 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1803 var target_array = target_type as ArrayContainer;
1804 if (target_array != null && IList_To_Array (source_type, target_array))
1805 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1810 var source_array = source_type as ArrayContainer;
1811 if (source_array != null) {
1812 var target_array = target_type as ArrayContainer;
1813 if (target_array != null) {
1815 // From System.Array to any array-type
1817 if (source_type.BuildinType == BuildinTypeSpec.Type.Array)
1818 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1821 // From an array type S with an element type Se to an array type T with an
1822 // element type Te provided all the following are true:
1823 // * S and T differe only in element type, in other words, S and T
1824 // have the same number of dimensions.
1825 // * Both Se and Te are reference types
1826 // * An explicit reference conversions exist from Se to Te
1828 if (source_array.Rank == target_array.Rank) {
1830 source_type = source_array.Element;
1831 if (!TypeManager.IsReferenceType (source_type))
1834 var target_element = target_array.Element;
1835 if (!TypeManager.IsReferenceType (target_element))
1838 if (ExplicitReferenceConversionExists (source_type, target_element))
1839 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1846 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1847 // provided that there is an explicit reference conversion from S to T
1849 if (ArrayToIList (source_array, target_type, true))
1850 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1856 // From any class type S to any interface T, provides S is not sealed
1857 // and provided S does not implement T.
1859 if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type, true)) {
1860 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1864 // From System delegate to any delegate-type
1866 if (source_type.BuildinType == BuildinTypeSpec.Type.Delegate && TypeManager.IsDelegateType (target_type))
1867 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1870 // From variant generic delegate to same variant generic delegate type
1872 if (source_type.IsDelegate && target_type.IsDelegate && source_type.MemberDefinition == target_type.MemberDefinition) {
1873 var tparams = source_type.MemberDefinition.TypeParameters;
1874 var targs_src = source_type.TypeArguments;
1875 var targs_dst = target_type.TypeArguments;
1877 for (i = 0; i < tparams.Length; ++i) {
1879 // If TP is invariant, types have to be identical
1881 if (TypeSpecComparer.IsEqual (targs_src[i], targs_dst[i]))
1884 if (tparams[i].Variance == Variance.Covariant) {
1886 //If TP is covariant, an implicit or explicit identity or reference conversion is required
1888 if (ImplicitReferenceConversionExists (new EmptyExpression (targs_src[i]), targs_dst[i]))
1891 if (ExplicitReferenceConversionExists (targs_src[i], targs_dst[i]))
1894 } else if (tparams[i].Variance == Variance.Contravariant) {
1896 //If TP is contravariant, both are either identical or reference types
1898 if (TypeManager.IsReferenceType (targs_src[i]) && TypeManager.IsReferenceType (targs_dst[i]))
1905 if (i == tparams.Length)
1906 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1913 /// Performs an explicit conversion of the expression `expr' whose
1914 /// type is expr.Type to `target_type'.
1916 static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr,
1917 TypeSpec target_type, Location loc)
1919 TypeSpec expr_type = expr.Type;
1921 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1922 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true);
1926 if (TypeManager.IsEnumType (expr_type)) {
1927 TypeSpec real_target = TypeManager.IsEnumType (target_type) ? EnumSpec.GetUnderlyingType (target_type) : target_type;
1928 Expression underlying = EmptyCast.Create (expr, EnumSpec.GetUnderlyingType (expr_type));
1929 if (underlying.Type == real_target)
1933 ne = ImplicitNumericConversion (underlying, real_target);
1936 ne = ExplicitNumericConversion (ec, underlying, real_target);
1939 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1941 if (ne == null && (real_target.BuildinType == BuildinTypeSpec.Type.IntPtr || real_target.BuildinType == BuildinTypeSpec.Type.UIntPtr))
1942 ne = ExplicitUserConversion (ec, underlying, real_target, loc);
1944 return ne != null ? EmptyCast.Create (ne, target_type) : null;
1947 if (TypeManager.IsEnumType (target_type)) {
1949 // System.Enum can be unboxed to any enum-type
1951 if (expr_type.BuildinType == BuildinTypeSpec.Type.Enum)
1952 return new UnboxCast (expr, target_type);
1954 TypeSpec real_target = TypeManager.IsEnumType (target_type) ? EnumSpec.GetUnderlyingType (target_type) : target_type;
1956 if (expr_type == real_target)
1957 return EmptyCast.Create (expr, target_type);
1959 ne = ImplicitNumericConversion (expr, real_target);
1961 return EmptyCast.Create (ne, target_type);
1963 ne = ExplicitNumericConversion (ec, expr, real_target);
1965 return EmptyCast.Create (ne, target_type);
1968 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1970 if (expr_type.BuildinType == BuildinTypeSpec.Type.IntPtr || expr_type.BuildinType == BuildinTypeSpec.Type.UIntPtr) {
1971 ne = ExplicitUserConversion (ec, expr, real_target, loc);
1973 return ExplicitConversionCore (ec, ne, target_type, loc);
1976 ne = ExplicitNumericConversion (ec, expr, target_type);
1982 // Skip the ExplicitReferenceConversion because we can not convert
1983 // from Null to a ValueType, and ExplicitReference wont check against
1984 // null literal explicitly
1986 if (expr_type != InternalType.NullLiteral) {
1987 ne = ExplicitReferenceConversion (expr, expr_type, target_type);
1993 ne = ExplicitUnsafe (expr, target_type);
2001 public static Expression ExplicitUnsafe (Expression expr, TypeSpec target_type)
2003 TypeSpec expr_type = expr.Type;
2005 if (target_type.IsPointer){
2006 if (expr_type.IsPointer)
2007 return EmptyCast.Create (expr, target_type);
2009 switch (expr_type.BuildinType) {
2010 case BuildinTypeSpec.Type.SByte:
2011 case BuildinTypeSpec.Type.Short:
2012 case BuildinTypeSpec.Type.Int:
2013 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
2015 case BuildinTypeSpec.Type.UShort:
2016 case BuildinTypeSpec.Type.UInt:
2017 case BuildinTypeSpec.Type.Byte:
2018 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
2020 case BuildinTypeSpec.Type.Long:
2021 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I);
2023 case BuildinTypeSpec.Type.ULong:
2024 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I);
2028 if (expr_type.IsPointer){
2029 switch (target_type.BuildinType) {
2030 case BuildinTypeSpec.Type.SByte:
2031 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
2032 case BuildinTypeSpec.Type.Byte:
2033 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
2034 case BuildinTypeSpec.Type.Short:
2035 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
2036 case BuildinTypeSpec.Type.UShort:
2037 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
2038 case BuildinTypeSpec.Type.Int:
2039 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
2040 case BuildinTypeSpec.Type.UInt:
2041 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
2042 case BuildinTypeSpec.Type.Long:
2043 return new ConvCast (expr, target_type, ConvCast.Mode.I_I8);
2044 case BuildinTypeSpec.Type.ULong:
2045 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
2052 /// Same as ExplicitConversion, only it doesn't include user defined conversions
2054 static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr,
2055 TypeSpec target_type, Location l)
2057 int errors = ec.Report.Errors;
2058 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
2059 if (ec.Report.Errors > errors)
2065 ne = ExplicitNumericConversion (ec, expr, target_type);
2069 ne = ExplicitReferenceConversion (expr, expr.Type, target_type);
2073 if (ec.IsUnsafe && expr.Type.IsPointer && target_type.IsPointer && ((PointerContainer)expr.Type).Element.Kind == MemberKind.Void)
2074 return EmptyCast.Create (expr, target_type);
2076 expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
2081 /// Performs an explicit conversion of the expression `expr' whose
2082 /// type is expr.Type to `target_type'.
2084 static public Expression ExplicitConversion (ResolveContext ec, Expression expr,
2085 TypeSpec target_type, Location loc)
2087 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
2090 // Don't eliminate explicit precission casts
2093 if (target_type.BuildinType == BuildinTypeSpec.Type.Float)
2094 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
2096 if (target_type.BuildinType == BuildinTypeSpec.Type.Double)
2097 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
2103 TypeSpec expr_type = expr.Type;
2104 if (target_type.IsNullableType) {
2107 if (expr_type.IsNullableType) {
2108 target = Nullable.NullableInfo.GetUnderlyingType (target_type);
2109 Expression unwrap = Nullable.Unwrap.Create (expr);
2110 e = ExplicitConversion (ec, unwrap, target, expr.Location);
2114 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
2116 if (expr_type.BuildinType == BuildinTypeSpec.Type.Object) {
2117 return new UnboxCast (expr, target_type);
2120 target = TypeManager.GetTypeArguments (target_type) [0];
2121 e = ExplicitConversionCore (ec, expr, target, loc);
2123 return Nullable.Wrap.Create (e, target_type);
2124 } else if (expr_type.IsNullableType) {
2125 e = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type);
2129 e = Nullable.Unwrap.Create (expr, false);
2130 e = ExplicitConversionCore (ec, e, target_type, loc);
2132 return EmptyCast.Create (e, target_type);
2135 e = ExplicitUserConversion (ec, expr, target_type, loc);
2139 expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);