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
;
15 using System
.Diagnostics
;
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
19 namespace Mono
.CSharp
{
22 // A container class for all the conversion operations
24 static class Convert
{
26 static EmptyExpression MyEmptyExpr
;
27 static DoubleHash explicit_conv
;
28 static DoubleHash implicit_conv
;
35 public static void Reset ()
38 explicit_conv
= new DoubleHash (100);
39 implicit_conv
= new DoubleHash (100);
43 // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
44 // interfaces of this interface, provided there is an implicit reference conversion
47 static bool ArrayToIList (ArrayContainer array
, TypeSpec list
, bool isExplicit
)
49 if (array
.Rank
!= 1 || !list
.IsGeneric
)
52 var open_version
= list
.GetDefinition ();
53 if ((open_version
!= TypeManager
.generic_ilist_type
) &&
54 (open_version
!= TypeManager
.generic_icollection_type
) &&
55 (open_version
!= TypeManager
.generic_ienumerable_type
))
58 var arg_type
= list
.TypeArguments
[0];
59 if (array
.Element
== arg_type
)
63 return ExplicitReferenceConversionExists (array
.Element
, arg_type
);
65 if (MyEmptyExpr
== null)
66 MyEmptyExpr
= new EmptyExpression (array
.Element
);
68 MyEmptyExpr
.SetType (array
.Element
);
70 return ImplicitReferenceConversionExists (MyEmptyExpr
, arg_type
);
73 static bool IList_To_Array(TypeSpec list
, ArrayContainer array
)
75 if (array
.Rank
!= 1 || !list
.IsGeneric
)
78 var open_version
= list
.GetDefinition ();
79 if ((open_version
!= TypeManager
.generic_ilist_type
) &&
80 (open_version
!= TypeManager
.generic_icollection_type
) &&
81 (open_version
!= TypeManager
.generic_ienumerable_type
))
84 var arg_type
= list
.TypeArguments
[0];
85 if (array
.Element
== arg_type
)
88 if (MyEmptyExpr
== null)
89 MyEmptyExpr
= new EmptyExpression (array
.Element
);
91 MyEmptyExpr
.SetType (array
.Element
);
93 return ImplicitReferenceConversionExists (MyEmptyExpr
, arg_type
) || ExplicitReferenceConversionExists (array
.Element
, arg_type
);
96 static Expression
ImplicitTypeParameterConversion (Expression expr
, TypeSpec target_type
)
98 var expr_type
= (TypeParameterSpec
) expr
.Type
;
100 // From T to a type parameter U
102 var ttype
= target_type
as TypeParameterSpec
;
104 if (expr_type
.IsReferenceType
&& !ttype
.IsReferenceType
)
105 return new BoxedCast (expr
, target_type
);
107 return new ClassCast (expr
, target_type
);
111 // From T to its effective base class C
112 // From T to any base class of C
113 // From T to any interface implemented by C
115 var base_type
= expr_type
.GetEffectiveBase ();
116 if (base_type
== target_type
|| TypeManager
.IsSubclassOf (base_type
, target_type
) || base_type
.ImplementsInterface (target_type
)) {
117 if (expr_type
.IsReferenceType
)
118 return new ClassCast (expr
, target_type
);
120 return new BoxedCast (expr
, target_type
);
123 if (target_type
.IsInterface
&& expr_type
.IsConvertibleToInterface (target_type
)) {
124 if (expr_type
.IsReferenceType
)
125 return new ClassCast (expr
, target_type
);
127 return new BoxedCast (expr
, target_type
);
133 static Expression
ExplicitTypeParameterConversion (Expression source
, TypeSpec source_type
, TypeSpec target_type
)
135 var target_tp
= target_type
as TypeParameterSpec
;
136 if (target_tp
!= null) {
137 if (target_tp
.Interfaces
!= null) {
138 foreach (TypeSpec iface
in target_tp
.Interfaces
) {
139 if (!TypeManager
.IsGenericParameter (iface
))
142 if (TypeManager
.IsSubclassOf (source_type
, iface
))
143 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
, true);
150 if (target_type
.IsInterface
)
151 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
, true);
156 static Expression
ImplicitReferenceConversion (Expression expr
, TypeSpec target_type
, bool explicit_cast
)
158 TypeSpec expr_type
= expr
.Type
;
160 if (expr_type
== null && expr
.eclass
== ExprClass
.MethodGroup
){
161 // if we are a method group, emit a warning
166 if (expr_type
== TypeManager
.void_type
)
169 if (expr_type
.Kind
== MemberKind
.TypeParameter
)
170 return ImplicitTypeParameterConversion (expr
, target_type
);
173 // from the null type to any reference-type.
175 NullLiteral nl
= expr
as NullLiteral
;
177 return nl
.ConvertImplicitly (null, target_type
);
180 if (ImplicitReferenceConversionExists (expr
, target_type
)) {
182 // Avoid wrapping implicitly convertible reference type
187 return EmptyCast
.Create (expr
, target_type
);
190 return ImplicitBoxingConversion (expr
, expr_type
, target_type
);
194 // 6.1.6 Implicit reference conversions
196 public static bool ImplicitReferenceConversionExists (Expression expr
, TypeSpec target_type
)
198 if (TypeManager
.IsStruct (target_type
))
201 TypeSpec expr_type
= expr
.Type
;
203 // from the null type to any reference-type.
204 if (expr_type
== TypeManager
.null_type
)
205 return target_type
!= InternalType
.AnonymousMethod
;
207 if (TypeManager
.IsGenericParameter (expr_type
))
208 return ImplicitTypeParameterConversion (expr
, target_type
) != null;
210 // This code is kind of mirrored inside ImplicitStandardConversionExists
211 // with the small distinction that we only probe there
213 // Always ensure that the code here and there is in sync
215 // from any class-type S to any interface-type T.
216 if (target_type
.IsInterface
) {
217 if (expr_type
.ImplementsInterface (target_type
)){
218 return !TypeManager
.IsValueType (expr_type
);
223 // notice that it is possible to write "ValueType v = 1", the ValueType here
224 // is an abstract class, and not really a value type, so we apply the same rules.
226 if (target_type
== TypeManager
.object_type
|| target_type
== InternalType
.Dynamic
) {
228 // A pointer type cannot be converted to object
230 if (expr_type
.IsPointer
)
233 if (TypeManager
.IsValueType (expr_type
))
236 if (expr_type
.IsClass
|| expr_type
.IsInterface
|| expr_type
== TypeManager
.enum_type
|| expr_type
.IsDelegate
) {
237 // No mcs internal types are convertible
238 return true; // expr_type.MetaInfo.Module != typeof (Convert).Module;
241 // From anything to dynamic
242 if (target_type
== InternalType
.Dynamic
)
245 // From dynamic to object
246 if (expr_type
== InternalType
.Dynamic
)
250 } else if (target_type
== TypeManager
.value_type
) {
251 return expr_type
== TypeManager
.enum_type
;
252 } else if (TypeManager
.IsSubclassOf (expr_type
, target_type
)) {
254 // Special case: enumeration to System.Enum.
255 // System.Enum is not a value type, it is a class, so we need
256 // a boxing conversion
258 if (target_type
== TypeManager
.enum_type
|| TypeManager
.IsGenericParameter (expr_type
))
261 if (TypeManager
.IsValueType (expr_type
))
264 // Array type variance conversion
265 //if (target_type.IsArray != expr_type.IsArray)
271 var expr_type_array
= expr_type
as ArrayContainer
;
272 if (expr_type_array
!= null) {
273 var target_type_array
= target_type
as ArrayContainer
;
274 // from an array-type S to an array-type of type T
275 if (target_type_array
!= null && expr_type_array
.Rank
== target_type_array
.Rank
) {
278 // Both SE and TE are reference-types
280 TypeSpec expr_element_type
= expr_type_array
.Element
;
281 if (!TypeManager
.IsReferenceType (expr_element_type
))
284 TypeSpec target_element_type
= target_type_array
.Element
;
285 if (!TypeManager
.IsReferenceType (target_element_type
))
288 if (MyEmptyExpr
== null)
289 MyEmptyExpr
= new EmptyExpression (expr_element_type
);
291 MyEmptyExpr
.SetType (expr_element_type
);
293 return ImplicitStandardConversionExists (MyEmptyExpr
, target_element_type
);
296 // from an array-type to System.Array
297 if (target_type
== TypeManager
.array_type
)
300 // from an array-type of type T to IList<T>
301 if (ArrayToIList (expr_type_array
, target_type
, false))
307 if (TypeSpecComparer
.Variant
.IsEqual (expr_type
, target_type
))
310 // from any interface type S to interface-type T.
311 if (expr_type
.IsInterface
&& target_type
.IsInterface
) {
312 return expr_type
.ImplementsInterface (target_type
);
315 // from any delegate type to System.Delegate
316 if (target_type
== TypeManager
.delegate_type
&&
317 (expr_type
== TypeManager
.delegate_type
|| expr_type
.IsDelegate
))
320 if (TypeManager
.IsEqual (expr_type
, target_type
))
326 public static Expression
ImplicitBoxingConversion (Expression expr
, TypeSpec expr_type
, TypeSpec target_type
)
329 // From any value-type to the type object.
331 if (target_type
== TypeManager
.object_type
|| target_type
== InternalType
.Dynamic
) {
333 // A pointer type cannot be converted to object
335 if (expr_type
.IsPointer
)
338 if (!TypeManager
.IsValueType (expr_type
))
341 return expr
== null ? EmptyExpression
.Null
: new BoxedCast (expr
, target_type
);
345 // From any value-type to the type System.ValueType.
347 if (target_type
== TypeManager
.value_type
) {
348 if (!TypeManager
.IsValueType (expr_type
))
351 return expr
== null ? EmptyExpression
.Null
: new BoxedCast (expr
, target_type
);
354 if (target_type
== TypeManager
.enum_type
) {
356 // From any enum-type to the type System.Enum.
358 if (TypeManager
.IsEnumType (expr_type
))
359 return expr
== null ? EmptyExpression
.Null
: new BoxedCast (expr
, target_type
);
363 // From a nullable-type to a reference type, if a boxing conversion exists from
364 // the underlying type to the reference type
366 if (TypeManager
.IsNullableType (expr_type
)) {
367 if (!TypeManager
.IsReferenceType (target_type
))
370 var res
= ImplicitBoxingConversion (expr
, Nullable
.NullableInfo
.GetUnderlyingType (expr_type
), target_type
);
372 // "cast" underlying type to target type to emit correct InvalidCastException when
373 // underlying hierarchy changes without recompilation
374 if (res
!= null && expr
!= null)
375 res
= new UnboxCast (res
, target_type
);
380 if (TypeManager
.IsSubclassOf (expr_type
, target_type
)) {
382 // Don't box same type arguments
384 if (TypeManager
.IsGenericParameter (expr_type
) && expr_type
!= target_type
)
385 return expr
== null ? EmptyExpression
.Null
: new BoxedCast (expr
, target_type
);
390 // This code is kind of mirrored inside ImplicitStandardConversionExists
391 // with the small distinction that we only probe there
393 // Always ensure that the code here and there is in sync
395 // from any class-type S to any interface-type T.
396 if (target_type
.IsInterface
) {
397 if (expr_type
.ImplementsInterface (target_type
) &&
398 (TypeManager
.IsGenericParameter (expr_type
) || TypeManager
.IsValueType (expr_type
))) {
399 return expr
== null ? EmptyExpression
.Null
: new BoxedCast (expr
, target_type
);
406 public static Expression
ImplicitNulableConversion (ResolveContext ec
, Expression expr
, TypeSpec target_type
)
408 TypeSpec expr_type
= expr
.Type
;
411 // From null to any nullable type
413 if (expr_type
== TypeManager
.null_type
)
414 return ec
== null ? EmptyExpression
.Null
: Nullable
.LiftedNull
.Create (target_type
, expr
.Location
);
417 TypeSpec t_el
= TypeManager
.GetTypeArguments (target_type
)[0];
420 if (TypeManager
.IsNullableType (expr_type
))
421 expr_type
= TypeManager
.GetTypeArguments (expr_type
)[0];
424 // Predefined implicit identity or implicit numeric conversion
425 // has to exist between underlying type S and underlying type T
430 if (expr_type
== t_el
)
431 return EmptyExpression
.Null
;
433 return ImplicitNumericConversion (null, expr_type
, t_el
);
437 if (expr_type
!= expr
.Type
)
438 unwrap
= Nullable
.Unwrap
.Create (expr
);
442 Expression conv
= expr_type
== t_el
? unwrap
: ImplicitNumericConversion (unwrap
, expr_type
, t_el
);
446 if (expr_type
!= expr
.Type
)
447 return new Nullable
.Lifted (conv
, unwrap
, target_type
).Resolve (ec
);
449 // Do constant optimization for S -> T?
450 if (unwrap
is Constant
)
451 conv
= ((Constant
) unwrap
).ConvertImplicitly (ec
, t_el
);
453 return Nullable
.Wrap
.Create (conv
, target_type
);
457 /// Implicit Numeric Conversions.
459 /// expr is the expression to convert, returns a new expression of type
460 /// target_type or null if an implicit conversion is not possible.
462 public static Expression
ImplicitNumericConversion (Expression expr
, TypeSpec target_type
)
464 return ImplicitNumericConversion (expr
, expr
.Type
, target_type
);
467 static Expression
ImplicitNumericConversion (Expression expr
, TypeSpec expr_type
, TypeSpec target_type
)
469 if (expr_type
== TypeManager
.sbyte_type
){
471 // From sbyte to short, int, long, float, double, decimal
473 if (target_type
== TypeManager
.int32_type
)
474 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I4
);
475 if (target_type
== TypeManager
.int64_type
)
476 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
477 if (target_type
== TypeManager
.double_type
)
478 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
479 if (target_type
== TypeManager
.float_type
)
480 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
481 if (target_type
== TypeManager
.short_type
)
482 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I2
);
483 if (target_type
== TypeManager
.decimal_type
)
484 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
485 } else if (expr_type
== TypeManager
.byte_type
){
487 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
489 if (target_type
== TypeManager
.int32_type
|| target_type
== TypeManager
.uint32_type
||
490 target_type
== TypeManager
.short_type
|| target_type
== TypeManager
.ushort_type
)
491 return expr
== null ? EmptyExpression
.Null
: EmptyCast
.Create (expr
, target_type
);
493 if (target_type
== TypeManager
.uint64_type
)
494 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
495 if (target_type
== TypeManager
.int64_type
)
496 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
497 if (target_type
== TypeManager
.float_type
)
498 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
499 if (target_type
== TypeManager
.double_type
)
500 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
501 if (target_type
== TypeManager
.decimal_type
)
502 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
504 } else if (expr_type
== TypeManager
.short_type
){
506 // From short to int, long, float, double, decimal
508 if (target_type
== TypeManager
.int32_type
)
509 return expr
== null ? EmptyExpression
.Null
: EmptyCast
.Create (expr
, target_type
);
510 if (target_type
== TypeManager
.int64_type
)
511 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
512 if (target_type
== TypeManager
.double_type
)
513 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
514 if (target_type
== TypeManager
.float_type
)
515 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
516 if (target_type
== TypeManager
.decimal_type
)
517 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
519 } else if (expr_type
== TypeManager
.ushort_type
){
521 // From ushort to int, uint, long, ulong, float, double, decimal
523 if (target_type
== TypeManager
.int32_type
|| target_type
== TypeManager
.uint32_type
)
524 return expr
== null ? EmptyExpression
.Null
: EmptyCast
.Create (expr
, target_type
);
526 if (target_type
== TypeManager
.uint64_type
)
527 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
528 if (target_type
== TypeManager
.int64_type
)
529 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
530 if (target_type
== TypeManager
.double_type
)
531 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
532 if (target_type
== TypeManager
.float_type
)
533 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
534 if (target_type
== TypeManager
.decimal_type
)
535 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
536 } else if (expr_type
== TypeManager
.int32_type
){
538 // From int to long, float, double, decimal
540 if (target_type
== TypeManager
.int64_type
)
541 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
542 if (target_type
== TypeManager
.double_type
)
543 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
544 if (target_type
== TypeManager
.float_type
)
545 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
546 if (target_type
== TypeManager
.decimal_type
)
547 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
548 } else if (expr_type
== TypeManager
.uint32_type
){
550 // From uint to long, ulong, float, double, decimal
552 if (target_type
== TypeManager
.int64_type
)
553 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
554 if (target_type
== TypeManager
.uint64_type
)
555 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
556 if (target_type
== TypeManager
.double_type
)
557 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
), target_type
, OpCodes
.Conv_R8
);
558 if (target_type
== TypeManager
.float_type
)
559 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
), target_type
, OpCodes
.Conv_R4
);
560 if (target_type
== TypeManager
.decimal_type
)
561 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
562 } else if (expr_type
== TypeManager
.int64_type
){
564 // From long/ulong to float, double
566 if (target_type
== TypeManager
.double_type
)
567 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
568 if (target_type
== TypeManager
.float_type
)
569 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
570 if (target_type
== TypeManager
.decimal_type
)
571 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
572 } else if (expr_type
== TypeManager
.uint64_type
){
574 // From ulong to float, double
576 if (target_type
== TypeManager
.double_type
)
577 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
), target_type
, OpCodes
.Conv_R8
);
578 if (target_type
== TypeManager
.float_type
)
579 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R_Un
), target_type
, OpCodes
.Conv_R4
);
580 if (target_type
== TypeManager
.decimal_type
)
581 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
582 } else if (expr_type
== TypeManager
.char_type
){
584 // From char to ushort, int, uint, long, ulong, float, double, decimal
586 if ((target_type
== TypeManager
.ushort_type
) ||
587 (target_type
== TypeManager
.int32_type
) ||
588 (target_type
== TypeManager
.uint32_type
))
589 return expr
== null ? EmptyExpression
.Null
: EmptyCast
.Create (expr
, target_type
);
590 if (target_type
== TypeManager
.uint64_type
)
591 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
592 if (target_type
== TypeManager
.int64_type
)
593 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I8
);
594 if (target_type
== TypeManager
.float_type
)
595 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
596 if (target_type
== TypeManager
.double_type
)
597 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
598 if (target_type
== TypeManager
.decimal_type
)
599 return expr
== null ? EmptyExpression
.Null
: new CastToDecimal (expr
);
600 } else if (expr_type
== TypeManager
.float_type
){
604 if (target_type
== TypeManager
.double_type
)
605 return expr
== null ? EmptyExpression
.Null
: new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
612 /// Same as ImplicitStandardConversionExists except that it also looks at
613 /// implicit user defined conversions - needed for overload resolution
615 public static bool ImplicitConversionExists (ResolveContext ec
, Expression expr
, TypeSpec target_type
)
617 if (ImplicitStandardConversionExists (expr
, target_type
))
620 if (expr
.Type
== InternalType
.AnonymousMethod
) {
621 if (!TypeManager
.IsDelegateType (target_type
) && target_type
.GetDefinition () != TypeManager
.expression_type
)
624 AnonymousMethodExpression ame
= (AnonymousMethodExpression
) expr
;
625 return ame
.ImplicitStandardConversionExists (ec
, target_type
);
628 if (expr
.eclass
== ExprClass
.MethodGroup
) {
629 if (target_type
.IsDelegate
&& RootContext
.Version
!= LanguageVersion
.ISO_1
) {
630 MethodGroupExpr mg
= expr
as MethodGroupExpr
;
632 return DelegateCreation
.ImplicitStandardConversionExists (ec
, mg
, target_type
);
638 return ImplicitUserConversion (ec
, expr
, target_type
, Location
.Null
) != null;
642 /// Determines if a standard implicit conversion exists from
643 /// expr_type to target_type
645 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
647 public static bool ImplicitStandardConversionExists (Expression expr
, TypeSpec target_type
)
649 TypeSpec expr_type
= expr
.Type
;
651 if (expr_type
== TypeManager
.null_type
) {
652 NullLiteral nl
= expr
as NullLiteral
;
654 return nl
.ConvertImplicitly (null, target_type
) != null;
657 if (expr_type
== TypeManager
.void_type
)
660 if (TypeManager
.IsEqual (expr_type
, target_type
))
663 if (TypeManager
.IsNullableType (target_type
)) {
664 return ImplicitNulableConversion (null, expr
, target_type
) != null;
667 // First numeric conversions
668 if (ImplicitNumericConversion (null, expr_type
, target_type
) != null)
671 if (ImplicitReferenceConversionExists (expr
, target_type
))
674 if (ImplicitBoxingConversion (null, expr_type
, target_type
) != null)
678 // Implicit Constant Expression Conversions
680 if (expr
is IntConstant
){
681 int value = ((IntConstant
) expr
).Value
;
683 if (target_type
== TypeManager
.sbyte_type
){
684 if (value >= SByte
.MinValue
&& value <= SByte
.MaxValue
)
686 } else if (target_type
== TypeManager
.byte_type
){
687 if (value >= 0 && value <= Byte
.MaxValue
)
689 } else if (target_type
== TypeManager
.short_type
){
690 if (value >= Int16
.MinValue
&& value <= Int16
.MaxValue
)
692 } else if (target_type
== TypeManager
.ushort_type
){
693 if (value >= UInt16
.MinValue
&& value <= UInt16
.MaxValue
)
695 } else if (target_type
== TypeManager
.uint32_type
){
698 } else if (target_type
== TypeManager
.uint64_type
){
700 // we can optimize this case: a positive int32
701 // always fits on a uint64. But we need an opcode
708 if (value == 0 && target_type
.IsEnum
)
712 if (expr
is LongConstant
&& target_type
== TypeManager
.uint64_type
){
714 // Try the implicit constant expression conversion
715 // from long to ulong, instead of a nice routine,
718 long v
= ((LongConstant
) expr
).Value
;
724 // If `expr_type' implements `target_type' (which is an iface)
725 // see TryImplicitIntConversion
727 if (target_type
.IsInterface
&& expr_type
.ImplementsInterface (target_type
))
730 if (target_type
== TypeManager
.void_ptr_type
&& expr_type
.IsPointer
)
733 // Conversion from __arglist to System.ArgIterator
734 if (expr_type
== InternalType
.Arglist
)
735 return target_type
== TypeManager
.arg_iterator_type
;
741 /// Finds "most encompassed type" according to the spec (13.4.2)
742 /// amongst the methods in the MethodGroupExpr
744 public static TypeSpec
FindMostEncompassedType (IEnumerable
<TypeSpec
> types
)
746 TypeSpec best
= null;
747 EmptyExpression expr
= EmptyExpression
.Grab ();
749 foreach (TypeSpec t
in types
) {
756 if (ImplicitStandardConversionExists (expr
, best
))
761 foreach (TypeSpec t
in types
) {
764 if (!ImplicitStandardConversionExists (expr
, t
)) {
770 EmptyExpression
.Release (expr
);
776 /// Finds "most encompassing type" according to the spec (13.4.2)
777 /// amongst the types in the given set
779 static TypeSpec
FindMostEncompassingType (IList
<TypeSpec
> types
)
781 TypeSpec best
= null;
783 if (types
.Count
== 0)
786 if (types
.Count
== 1)
789 EmptyExpression expr
= EmptyExpression
.Grab ();
791 foreach (TypeSpec t
in types
) {
798 if (ImplicitStandardConversionExists (expr
, t
))
802 foreach (TypeSpec t
in types
) {
806 if (!ImplicitStandardConversionExists (expr
, best
)) {
812 EmptyExpression
.Release (expr
);
818 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
819 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
820 /// for explicit and implicit conversion operators.
822 static public TypeSpec
FindMostSpecificSource (IList
<MethodSpec
> list
,
823 Expression source
, bool apply_explicit_conv_rules
)
825 var src_types_set
= new List
<TypeSpec
> ();
828 // If any operator converts from S then Sx = S
830 TypeSpec source_type
= source
.Type
;
831 foreach (var mb
in list
){
832 TypeSpec param_type
= mb
.Parameters
.Types
[0];
834 if (param_type
== source_type
)
837 src_types_set
.Add (param_type
);
841 // Explicit Conv rules
843 if (apply_explicit_conv_rules
) {
844 var candidate_set
= new List
<TypeSpec
> ();
846 foreach (TypeSpec param_type
in src_types_set
){
847 if (ImplicitStandardConversionExists (source
, param_type
))
848 candidate_set
.Add (param_type
);
851 if (candidate_set
.Count
!= 0)
852 return FindMostEncompassedType (candidate_set
);
858 if (apply_explicit_conv_rules
)
859 return FindMostEncompassingType (src_types_set
);
861 return FindMostEncompassedType (src_types_set
);
865 /// Finds the most specific target Tx according to section 13.4.4
867 static public TypeSpec
FindMostSpecificTarget (IList
<MethodSpec
> list
,
868 TypeSpec target
, bool apply_explicit_conv_rules
)
870 var tgt_types_set
= new List
<TypeSpec
> ();
873 // If any operator converts to T then Tx = T
875 foreach (var mi
in list
){
876 TypeSpec ret_type
= mi
.ReturnType
;
877 if (ret_type
== target
)
880 tgt_types_set
.Add (ret_type
);
884 // Explicit conv rules
886 if (apply_explicit_conv_rules
) {
887 var candidate_set
= new List
<TypeSpec
> ();
889 EmptyExpression expr
= EmptyExpression
.Grab ();
891 foreach (TypeSpec ret_type
in tgt_types_set
){
892 expr
.SetType (ret_type
);
894 if (ImplicitStandardConversionExists (expr
, target
))
895 candidate_set
.Add (ret_type
);
898 EmptyExpression
.Release (expr
);
900 if (candidate_set
.Count
!= 0)
901 return FindMostEncompassingType (candidate_set
);
905 // Okay, final case !
907 if (apply_explicit_conv_rules
)
908 return FindMostEncompassedType (tgt_types_set
);
910 return FindMostEncompassingType (tgt_types_set
);
914 /// User-defined Implicit conversions
916 static public Expression
ImplicitUserConversion (ResolveContext ec
, Expression source
,
917 TypeSpec target
, Location loc
)
919 return UserDefinedConversion (ec
, source
, target
, loc
, false, true);
923 /// User-defined Explicit conversions
925 static Expression
ExplicitUserConversion (ResolveContext ec
, Expression source
,
926 TypeSpec target
, Location loc
)
928 return UserDefinedConversion (ec
, source
, target
, loc
, true, true);
931 static void AddConversionOperators (List
<MethodSpec
> list
,
932 Expression source
, TypeSpec target_type
,
933 bool look_for_explicit
,
939 TypeSpec source_type
= source
.Type
;
940 EmptyExpression expr
= EmptyExpression
.Grab ();
943 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
944 // IntPtr -> uint uses int
945 // UIntPtr -> long uses ulong
947 if (source_type
== TypeManager
.intptr_type
) {
948 if (target_type
== TypeManager
.uint32_type
)
949 target_type
= TypeManager
.int32_type
;
950 } else if (source_type
== TypeManager
.uintptr_type
) {
951 if (target_type
== TypeManager
.int64_type
)
952 target_type
= TypeManager
.uint64_type
;
955 foreach (MethodSpec m
in mg
.Methods
) {
956 AParametersCollection pd
= m
.Parameters
;
957 TypeSpec return_type
= m
.ReturnType
;
958 TypeSpec arg_type
= pd
.Types
[0];
960 if (source_type
!= arg_type
) {
961 if (!ImplicitStandardConversionExists (source
, arg_type
)) {
962 if (!look_for_explicit
)
964 expr
.SetType (arg_type
);
965 if (!ImplicitStandardConversionExists (expr
, source_type
))
970 if (target_type
!= return_type
) {
971 expr
.SetType (return_type
);
972 if (!ImplicitStandardConversionExists (expr
, target_type
)) {
973 if (!look_for_explicit
)
975 expr
.SetType (target_type
);
976 if (!ImplicitStandardConversionExists (expr
, return_type
))
981 // See LAMESPEC: Exclude IntPtr -> int conversion
982 if (source_type
== TypeManager
.uintptr_type
&& return_type
== TypeManager
.uint32_type
)
988 EmptyExpression
.Release (expr
);
992 /// Compute the user-defined conversion operator from source_type to target_type.
993 /// `look_for_explicit' controls whether we should also include the list of explicit operators
995 static MethodSpec
GetConversionOperator (CompilerContext ctx
, TypeSpec container_type
, Expression source
, TypeSpec target_type
, bool look_for_explicit
)
997 var ops
= new List
<MethodSpec
> (4);
999 TypeSpec source_type
= source
.Type
;
1001 if (source_type
!= TypeManager
.decimal_type
) {
1002 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
1003 Expression
.MethodLookup (ctx
, container_type
, source_type
, MemberKind
.Operator
, "op_Implicit", 0, Location
.Null
));
1004 if (look_for_explicit
) {
1005 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
1006 Expression
.MethodLookup (ctx
,
1007 container_type
, source_type
, MemberKind
.Operator
, "op_Explicit", 0, Location
.Null
));
1011 if (target_type
!= TypeManager
.decimal_type
) {
1012 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
1013 Expression
.MethodLookup (ctx
, container_type
, target_type
, MemberKind
.Operator
, "op_Implicit", 0, Location
.Null
));
1014 if (look_for_explicit
) {
1015 AddConversionOperators (ops
, source
, target_type
, look_for_explicit
,
1016 Expression
.MethodLookup (ctx
,
1017 container_type
, target_type
, MemberKind
.Operator
, "op_Explicit", 0, Location
.Null
));
1024 TypeSpec most_specific_source
= FindMostSpecificSource (ops
, source
, look_for_explicit
);
1025 if (most_specific_source
== null)
1028 TypeSpec most_specific_target
= FindMostSpecificTarget (ops
, target_type
, look_for_explicit
);
1029 if (most_specific_target
== null)
1032 MethodSpec method
= null;
1034 foreach (var m
in ops
) {
1035 if (m
.ReturnType
!= most_specific_target
)
1037 if (m
.Parameters
.Types
[0] != most_specific_source
)
1039 // Ambiguous: more than one conversion operator satisfies the signature.
1049 /// User-defined conversions
1051 public static Expression
UserDefinedConversion (ResolveContext ec
, Expression source
,
1052 TypeSpec target
, Location loc
,
1053 bool look_for_explicit
, bool return_convert
)
1055 TypeSpec source_type
= source
.Type
;
1056 MethodSpec method
= null;
1057 Expression expr
= null;
1061 if (look_for_explicit
) {
1062 hash
= explicit_conv
;
1064 // Implicit user operators cannot convert to interfaces
1065 if (target
.IsInterface
)
1068 hash
= implicit_conv
;
1071 if (!(source
is Constant
) && hash
.Lookup (source_type
, target
, out o
)) {
1072 method
= (MethodSpec
) o
;
1074 if (source_type
== InternalType
.Dynamic
)
1077 method
= GetConversionOperator (ec
.Compiler
, null, source
, target
, look_for_explicit
);
1080 if (method
!= null) {
1081 TypeSpec most_specific_source
= method
.Parameters
.Types
[0];
1084 // This will do the conversion to the best match that we
1085 // found. Now we need to perform an implict standard conversion
1086 // if the best match was not the type that we were requested
1089 if (look_for_explicit
) {
1090 ReportPrinter temp
= new SessionReportPrinter ();
1091 ReportPrinter prev
= ec
.Report
.SetPrinter (temp
);
1093 expr
= ExplicitConversionStandard (ec
, source
, most_specific_source
, loc
);
1095 ec
.Report
.SetPrinter (prev
);
1096 if (temp
.ErrorsCount
!= 0)
1099 if (ImplicitStandardConversionExists (source
, most_specific_source
))
1100 expr
= ImplicitConversionStandard (ec
, source
, most_specific_source
, loc
);
1107 bool nullable
= false;
1109 if (TypeManager
.IsNullableType (source_type
)) {
1110 source
= Nullable
.Unwrap
.Create (source
);
1114 TypeSpec target_underlying
;
1115 if (TypeManager
.IsNullableType (target
)) {
1116 target_underlying
= TypeManager
.GetTypeArguments (target
)[0];
1119 // No implicit conversion S? -> T for non-reference type T
1120 if (!look_for_explicit
&& !TypeManager
.IsReferenceType (target
))
1123 target_underlying
= target
;
1127 expr
= UserDefinedConversion (ec
, source
, target_underlying
, loc
, look_for_explicit
, return_convert
);
1129 // Do result expression lifting only when it's needed
1130 if (expr
!= null && (!look_for_explicit
|| TypeManager
.IsReferenceType (target
)))
1131 expr
= new Nullable
.Lifted (expr
, source
, target
).Resolve (ec
);
1136 expr
= new UserCast (method
, expr
, loc
).Resolve (ec
);
1138 if (return_convert
&& !TypeManager
.IsEqual (expr
.Type
, target
)) {
1139 if (look_for_explicit
) {
1140 expr
= ExplicitConversionStandard (ec
, expr
, target
, loc
);
1142 expr
= ImplicitConversionStandard (ec
, expr
, target
, loc
);
1147 if (!(source
is Constant
))
1148 hash
.Insert (source_type
, target
, method
);
1154 /// Converts implicitly the resolved expression `expr' into the
1155 /// `target_type'. It returns a new expression that can be used
1156 /// in a context that expects a `target_type'.
1158 static public Expression
ImplicitConversion (ResolveContext ec
, Expression expr
,
1159 TypeSpec target_type
, Location loc
)
1163 if (target_type
== null)
1164 throw new Exception ("Target type is null");
1166 e
= ImplicitConversionStandard (ec
, expr
, target_type
, loc
);
1170 e
= ImplicitUserConversion (ec
, expr
, target_type
, loc
);
1179 /// Attempts to apply the `Standard Implicit
1180 /// Conversion' rules to the expression `expr' into
1181 /// the `target_type'. It returns a new expression
1182 /// that can be used in a context that expects a
1185 /// This is different from `ImplicitConversion' in that the
1186 /// user defined implicit conversions are excluded.
1188 static public Expression
ImplicitConversionStandard (ResolveContext ec
, Expression expr
,
1189 TypeSpec target_type
, Location loc
)
1191 return ImplicitConversionStandard (ec
, expr
, target_type
, loc
, false);
1194 static Expression
ImplicitConversionStandard (ResolveContext ec
, Expression expr
, TypeSpec target_type
, Location loc
, bool explicit_cast
)
1196 if (expr
.eclass
== ExprClass
.MethodGroup
){
1197 if (!TypeManager
.IsDelegateType (target_type
)){
1202 // Only allow anonymous method conversions on post ISO_1
1204 if (RootContext
.Version
!= LanguageVersion
.ISO_1
){
1205 MethodGroupExpr mg
= expr
as MethodGroupExpr
;
1207 return ImplicitDelegateCreation
.Create (
1208 ec
, mg
, target_type
, loc
);
1212 TypeSpec expr_type
= expr
.Type
;
1215 if (expr_type
.Equals (target_type
)) {
1216 if (expr_type
!= TypeManager
.null_type
&& expr_type
!= InternalType
.AnonymousMethod
)
1221 if (TypeSpecComparer
.Variant
.IsEqual (expr_type
, target_type
)) {
1225 if (TypeManager
.IsNullableType (target_type
))
1226 return ImplicitNulableConversion (ec
, expr
, target_type
);
1229 // Attempt to do the implicit constant expression conversions
1231 Constant c
= expr
as Constant
;
1234 c
= c
.ConvertImplicitly (ec
, 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
).Resolve (ec
);
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
== InternalType
.AnonymousMethod
){
1286 AnonymousMethodExpression ame
= (AnonymousMethodExpression
) expr
;
1287 Expression am
= ame
.Compatible (ec
, target_type
);
1289 return am
.Resolve (ec
);
1292 if (expr_type
== InternalType
.Arglist
&& target_type
== TypeManager
.arg_iterator_type
)
1299 /// Attempts to implicitly convert `source' into `target_type', using
1300 /// ImplicitConversion. If there is no implicit conversion, then
1301 /// an error is signaled
1303 static public Expression
ImplicitConversionRequired (ResolveContext ec
, Expression source
,
1304 TypeSpec target_type
, Location loc
)
1306 Expression e
= ImplicitConversion (ec
, source
, target_type
, loc
);
1310 if (source
.Type
== InternalType
.Dynamic
) {
1311 Arguments args
= new Arguments (1);
1312 args
.Add (new Argument (source
));
1313 return new DynamicConversion (target_type
, 0, args
, loc
).Resolve (ec
);
1316 source
.Error_ValueCannotBeConverted (ec
, loc
, target_type
, false);
1321 /// Performs the explicit numeric conversions
1323 /// There are a few conversions that are not part of the C# standard,
1324 /// they were interim hacks in the C# compiler that were supposed to
1325 /// become explicit operators in the UIntPtr class and IntPtr class,
1326 /// but for historical reasons it did not happen, so the C# compiler
1327 /// ended up with these special hacks.
1329 /// See bug 59800 for details.
1331 /// The conversion are:
1341 public static Expression
ExplicitNumericConversion (Expression expr
, TypeSpec target_type
)
1343 TypeSpec expr_type
= expr
.Type
;
1344 TypeSpec real_target_type
= target_type
;
1346 if (expr_type
== TypeManager
.sbyte_type
){
1348 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1350 if (real_target_type
== TypeManager
.byte_type
)
1351 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U1
);
1352 if (real_target_type
== TypeManager
.ushort_type
)
1353 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U2
);
1354 if (real_target_type
== TypeManager
.uint32_type
)
1355 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U4
);
1356 if (real_target_type
== TypeManager
.uint64_type
)
1357 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_U8
);
1358 if (real_target_type
== TypeManager
.char_type
)
1359 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I1_CH
);
1361 // One of the built-in conversions that belonged in the class library
1362 if (real_target_type
== TypeManager
.uintptr_type
){
1363 Expression u8e
= new ConvCast (expr
, TypeManager
.uint64_type
, ConvCast
.Mode
.I1_U8
);
1365 return new OperatorCast (u8e
, TypeManager
.uintptr_type
, true);
1367 } else if (expr_type
== TypeManager
.byte_type
){
1369 // From byte to sbyte and char
1371 if (real_target_type
== TypeManager
.sbyte_type
)
1372 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U1_I1
);
1373 if (real_target_type
== TypeManager
.char_type
)
1374 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U1_CH
);
1375 } else if (expr_type
== TypeManager
.short_type
){
1377 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1379 if (real_target_type
== TypeManager
.sbyte_type
)
1380 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_I1
);
1381 if (real_target_type
== TypeManager
.byte_type
)
1382 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U1
);
1383 if (real_target_type
== TypeManager
.ushort_type
)
1384 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U2
);
1385 if (real_target_type
== TypeManager
.uint32_type
)
1386 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U4
);
1387 if (real_target_type
== TypeManager
.uint64_type
)
1388 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_U8
);
1389 if (real_target_type
== TypeManager
.char_type
)
1390 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I2_CH
);
1392 // One of the built-in conversions that belonged in the class library
1393 if (real_target_type
== TypeManager
.uintptr_type
){
1394 Expression u8e
= new ConvCast (expr
, TypeManager
.uint64_type
, ConvCast
.Mode
.I2_U8
);
1396 return new OperatorCast (u8e
, TypeManager
.uintptr_type
, true);
1398 } else if (expr_type
== TypeManager
.ushort_type
){
1400 // From ushort to sbyte, byte, short, char
1402 if (real_target_type
== TypeManager
.sbyte_type
)
1403 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_I1
);
1404 if (real_target_type
== TypeManager
.byte_type
)
1405 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_U1
);
1406 if (real_target_type
== TypeManager
.short_type
)
1407 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_I2
);
1408 if (real_target_type
== TypeManager
.char_type
)
1409 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U2_CH
);
1410 } else if (expr_type
== TypeManager
.int32_type
){
1412 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1414 if (real_target_type
== TypeManager
.sbyte_type
)
1415 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_I1
);
1416 if (real_target_type
== TypeManager
.byte_type
)
1417 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U1
);
1418 if (real_target_type
== TypeManager
.short_type
)
1419 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_I2
);
1420 if (real_target_type
== TypeManager
.ushort_type
)
1421 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U2
);
1422 if (real_target_type
== TypeManager
.uint32_type
)
1423 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U4
);
1424 if (real_target_type
== TypeManager
.uint64_type
)
1425 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_U8
);
1426 if (real_target_type
== TypeManager
.char_type
)
1427 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I4_CH
);
1429 // One of the built-in conversions that belonged in the class library
1430 if (real_target_type
== TypeManager
.uintptr_type
){
1431 Expression u8e
= new ConvCast (expr
, TypeManager
.uint64_type
, ConvCast
.Mode
.I2_U8
);
1433 return new OperatorCast (u8e
, TypeManager
.uintptr_type
, true);
1435 } else if (expr_type
== TypeManager
.uint32_type
){
1437 // From uint to sbyte, byte, short, ushort, int, char
1439 if (real_target_type
== TypeManager
.sbyte_type
)
1440 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I1
);
1441 if (real_target_type
== TypeManager
.byte_type
)
1442 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_U1
);
1443 if (real_target_type
== TypeManager
.short_type
)
1444 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I2
);
1445 if (real_target_type
== TypeManager
.ushort_type
)
1446 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_U2
);
1447 if (real_target_type
== TypeManager
.int32_type
)
1448 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_I4
);
1449 if (real_target_type
== TypeManager
.char_type
)
1450 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U4_CH
);
1451 } else if (expr_type
== TypeManager
.int64_type
){
1453 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1455 if (real_target_type
== TypeManager
.sbyte_type
)
1456 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I1
);
1457 if (real_target_type
== TypeManager
.byte_type
)
1458 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U1
);
1459 if (real_target_type
== TypeManager
.short_type
)
1460 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I2
);
1461 if (real_target_type
== TypeManager
.ushort_type
)
1462 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U2
);
1463 if (real_target_type
== TypeManager
.int32_type
)
1464 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I4
);
1465 if (real_target_type
== TypeManager
.uint32_type
)
1466 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U4
);
1467 if (real_target_type
== TypeManager
.uint64_type
)
1468 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_U8
);
1469 if (real_target_type
== TypeManager
.char_type
)
1470 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_CH
);
1471 } else if (expr_type
== TypeManager
.uint64_type
){
1473 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1475 if (real_target_type
== TypeManager
.sbyte_type
)
1476 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I1
);
1477 if (real_target_type
== TypeManager
.byte_type
)
1478 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U1
);
1479 if (real_target_type
== TypeManager
.short_type
)
1480 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I2
);
1481 if (real_target_type
== TypeManager
.ushort_type
)
1482 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U2
);
1483 if (real_target_type
== TypeManager
.int32_type
)
1484 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I4
);
1485 if (real_target_type
== TypeManager
.uint32_type
)
1486 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_U4
);
1487 if (real_target_type
== TypeManager
.int64_type
)
1488 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I8
);
1489 if (real_target_type
== TypeManager
.char_type
)
1490 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_CH
);
1492 // One of the built-in conversions that belonged in the class library
1493 if (real_target_type
== TypeManager
.intptr_type
){
1494 return new OperatorCast (EmptyCast
.Create (expr
, TypeManager
.int64_type
),
1495 TypeManager
.intptr_type
, true);
1497 } else if (expr_type
== TypeManager
.char_type
){
1499 // From char to sbyte, byte, short
1501 if (real_target_type
== TypeManager
.sbyte_type
)
1502 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_I1
);
1503 if (real_target_type
== TypeManager
.byte_type
)
1504 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_U1
);
1505 if (real_target_type
== TypeManager
.short_type
)
1506 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.CH_I2
);
1507 } else if (expr_type
== TypeManager
.float_type
){
1509 // From float to sbyte, byte, short,
1510 // ushort, int, uint, long, ulong, char
1513 if (real_target_type
== TypeManager
.sbyte_type
)
1514 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I1
);
1515 if (real_target_type
== TypeManager
.byte_type
)
1516 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U1
);
1517 if (real_target_type
== TypeManager
.short_type
)
1518 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I2
);
1519 if (real_target_type
== TypeManager
.ushort_type
)
1520 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U2
);
1521 if (real_target_type
== TypeManager
.int32_type
)
1522 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I4
);
1523 if (real_target_type
== TypeManager
.uint32_type
)
1524 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U4
);
1525 if (real_target_type
== TypeManager
.int64_type
)
1526 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_I8
);
1527 if (real_target_type
== TypeManager
.uint64_type
)
1528 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_U8
);
1529 if (real_target_type
== TypeManager
.char_type
)
1530 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R4_CH
);
1531 if (real_target_type
== TypeManager
.decimal_type
)
1532 return new CastToDecimal (expr
, true);
1533 } else if (expr_type
== TypeManager
.double_type
){
1535 // From double to sbyte, byte, short,
1536 // ushort, int, uint, long, ulong,
1537 // char, float or decimal
1539 if (real_target_type
== TypeManager
.sbyte_type
)
1540 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I1
);
1541 if (real_target_type
== TypeManager
.byte_type
)
1542 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U1
);
1543 if (real_target_type
== TypeManager
.short_type
)
1544 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I2
);
1545 if (real_target_type
== TypeManager
.ushort_type
)
1546 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U2
);
1547 if (real_target_type
== TypeManager
.int32_type
)
1548 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I4
);
1549 if (real_target_type
== TypeManager
.uint32_type
)
1550 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U4
);
1551 if (real_target_type
== TypeManager
.int64_type
)
1552 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_I8
);
1553 if (real_target_type
== TypeManager
.uint64_type
)
1554 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_U8
);
1555 if (real_target_type
== TypeManager
.char_type
)
1556 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_CH
);
1557 if (real_target_type
== TypeManager
.float_type
)
1558 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.R8_R4
);
1559 if (real_target_type
== TypeManager
.decimal_type
)
1560 return new CastToDecimal (expr
, true);
1561 } else if (expr_type
== TypeManager
.uintptr_type
){
1563 // Various built-in conversions that belonged in the class library
1565 // from uintptr to sbyte, short, int32
1567 if (real_target_type
== TypeManager
.sbyte_type
){
1568 Expression uint32e
= new OperatorCast (expr
, TypeManager
.uint32_type
, true);
1569 return new ConvCast (uint32e
, TypeManager
.sbyte_type
, ConvCast
.Mode
.U4_I1
);
1571 if (real_target_type
== TypeManager
.short_type
){
1572 Expression uint32e
= new OperatorCast (expr
, TypeManager
.uint32_type
, true);
1573 return new ConvCast (uint32e
, TypeManager
.sbyte_type
, ConvCast
.Mode
.U4_I2
);
1575 if (real_target_type
== TypeManager
.int32_type
){
1576 return EmptyCast
.Create (new OperatorCast (expr
, TypeManager
.uint32_type
, true),
1577 TypeManager
.int32_type
);
1579 } else if (expr_type
== TypeManager
.intptr_type
){
1580 if (real_target_type
== TypeManager
.uint64_type
){
1581 return EmptyCast
.Create (new OperatorCast (expr
, TypeManager
.int64_type
, true),
1582 TypeManager
.uint64_type
);
1584 } else if (expr_type
== TypeManager
.decimal_type
) {
1585 return new CastFromDecimal (expr
, target_type
).Resolve ();
1591 /// Returns whether an explicit reference conversion can be performed
1592 /// from source_type to target_type
1594 public static bool ExplicitReferenceConversionExists (TypeSpec source_type
, TypeSpec target_type
)
1596 Expression e
= ExplicitReferenceConversion (null, source_type
, target_type
);
1600 if (e
== EmptyExpression
.Null
)
1603 throw new InternalErrorException ("Invalid probing conversion result");
1607 /// Implements Explicit Reference conversions
1609 static Expression
ExplicitReferenceConversion (Expression source
, TypeSpec source_type
, TypeSpec target_type
)
1612 // From object to a generic parameter
1614 if (source_type
== TypeManager
.object_type
&& TypeManager
.IsGenericParameter (target_type
))
1615 return source
== null ? EmptyExpression
.Null
: new UnboxCast (source
, target_type
);
1618 // Explicit type parameter conversion.
1620 if (TypeManager
.IsGenericParameter (source_type
))
1621 return ExplicitTypeParameterConversion (source
, source_type
, target_type
);
1623 bool target_is_value_type
= TypeManager
.IsStruct (target_type
) || TypeManager
.IsEnumType (target_type
);
1626 // Unboxing conversion from System.ValueType to any non-nullable-value-type
1628 if (source_type
== TypeManager
.value_type
&& target_is_value_type
)
1629 return source
== null ? EmptyExpression
.Null
: new UnboxCast (source
, target_type
);
1632 // From object to any reference type or value type (unboxing)
1634 if (source_type
== TypeManager
.object_type
)
1636 source
== null ? EmptyExpression
.Null
:
1637 target_is_value_type
? new UnboxCast (source
, target_type
) :
1638 source
is Constant
? (Expression
) new EmptyConstantCast ((Constant
) source
, target_type
) :
1639 new ClassCast (source
, target_type
);
1642 // From any class S to any class-type T, provided S is a base class of T
1644 if (TypeManager
.IsSubclassOf (target_type
, source_type
))
1645 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1648 // From any interface-type S to to any class type T, provided T is not
1649 // sealed, or provided T implements S.
1651 if (source_type
.IsInterface
) {
1652 if (!target_type
.IsSealed
|| target_type
.ImplementsInterface (source_type
)) {
1653 if (target_type
.IsClass
)
1654 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1657 // Unboxing conversion from any interface-type to any non-nullable-value-type that
1658 // implements the interface-type
1660 return source
== null ? EmptyExpression
.Null
: new UnboxCast (source
, target_type
);
1664 // From System.Collections.Generic.IList<T> and its base interfaces to a one-dimensional
1665 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1667 var target_array
= target_type
as ArrayContainer
;
1668 if (target_array
!= null && IList_To_Array (source_type
, target_array
))
1669 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1674 var source_array
= source_type
as ArrayContainer
;
1675 if (source_array
!= null) {
1676 var target_array
= target_type
as ArrayContainer
;
1677 if (target_array
!= null) {
1679 // From System.Array to any array-type
1681 if (source_type
== TypeManager
.array_type
)
1682 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1685 // From an array type S with an element type Se to an array type T with an
1686 // element type Te provided all the following are true:
1687 // * S and T differe only in element type, in other words, S and T
1688 // have the same number of dimensions.
1689 // * Both Se and Te are reference types
1690 // * An explicit reference conversions exist from Se to Te
1692 if (source_array
.Rank
== target_array
.Rank
) {
1694 source_type
= source_array
.Element
;
1695 if (!TypeManager
.IsReferenceType (source_type
))
1698 var target_element
= target_array
.Element
;
1699 if (!TypeManager
.IsReferenceType (target_element
))
1702 if (ExplicitReferenceConversionExists (source_type
, target_element
))
1703 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1710 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1711 // provided that there is an explicit reference conversion from S to T
1713 if (ArrayToIList (source_array
, target_type
, true))
1714 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1720 // From any class type S to any interface T, provides S is not sealed
1721 // and provided S does not implement T.
1723 if (target_type
.IsInterface
&& !source_type
.IsSealed
&& !source_type
.ImplementsInterface (target_type
)) {
1724 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1728 // From System delegate to any delegate-type
1730 if (source_type
== TypeManager
.delegate_type
&& TypeManager
.IsDelegateType (target_type
))
1731 return source
== null ? EmptyExpression
.Null
: new ClassCast (source
, target_type
);
1737 /// Performs an explicit conversion of the expression `expr' whose
1738 /// type is expr.Type to `target_type'.
1740 static public Expression
ExplicitConversionCore (ResolveContext ec
, Expression expr
,
1741 TypeSpec target_type
, Location loc
)
1743 TypeSpec expr_type
= expr
.Type
;
1745 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1746 Expression ne
= ImplicitConversionStandard (ec
, expr
, target_type
, loc
, true);
1750 if (TypeManager
.IsEnumType (expr_type
)) {
1751 TypeSpec real_target
= TypeManager
.IsEnumType (target_type
) ? EnumSpec
.GetUnderlyingType (target_type
) : target_type
;
1752 Expression underlying
= EmptyCast
.Create (expr
, EnumSpec
.GetUnderlyingType (expr_type
));
1753 if (underlying
.Type
== real_target
)
1757 ne
= ImplicitNumericConversion (underlying
, real_target
);
1760 ne
= ExplicitNumericConversion (underlying
, real_target
);
1763 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1765 if (ne
== null && (real_target
== TypeManager
.intptr_type
|| real_target
== TypeManager
.uintptr_type
))
1766 ne
= ExplicitUserConversion (ec
, underlying
, real_target
, loc
);
1768 return ne
!= null ? EmptyCast
.Create (ne
, target_type
) : null;
1771 if (TypeManager
.IsEnumType (target_type
)) {
1773 // System.Enum can be unboxed to any enum-type
1775 if (expr_type
== TypeManager
.enum_type
)
1776 return new UnboxCast (expr
, target_type
);
1778 TypeSpec real_target
= TypeManager
.IsEnumType (target_type
) ? EnumSpec
.GetUnderlyingType (target_type
) : target_type
;
1780 if (expr_type
== real_target
)
1781 return EmptyCast
.Create (expr
, target_type
);
1783 ne
= ImplicitNumericConversion (expr
, real_target
);
1785 return EmptyCast
.Create (ne
, target_type
);
1787 ne
= ExplicitNumericConversion (expr
, real_target
);
1789 return EmptyCast
.Create (ne
, target_type
);
1792 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1794 if (expr_type
== TypeManager
.intptr_type
|| expr_type
== TypeManager
.uintptr_type
) {
1795 ne
= ExplicitUserConversion (ec
, expr
, real_target
, loc
);
1797 return ExplicitConversionCore (ec
, ne
, target_type
, loc
);
1800 ne
= ExplicitNumericConversion (expr
, target_type
);
1806 // Skip the ExplicitReferenceConversion because we can not convert
1807 // from Null to a ValueType, and ExplicitReference wont check against
1808 // null literal explicitly
1810 if (expr_type
!= TypeManager
.null_type
){
1811 ne
= ExplicitReferenceConversion (expr
, expr_type
, target_type
);
1817 ne
= ExplicitUnsafe (expr
, target_type
);
1825 public static Expression
ExplicitUnsafe (Expression expr
, TypeSpec target_type
)
1827 TypeSpec expr_type
= expr
.Type
;
1829 if (target_type
.IsPointer
){
1830 if (expr_type
.IsPointer
)
1831 return EmptyCast
.Create (expr
, target_type
);
1833 if (expr_type
== TypeManager
.sbyte_type
||
1834 expr_type
== TypeManager
.short_type
||
1835 expr_type
== TypeManager
.int32_type
)
1836 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I
);
1838 if (expr_type
== TypeManager
.ushort_type
||
1839 expr_type
== TypeManager
.uint32_type
||
1840 expr_type
== TypeManager
.byte_type
)
1841 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U
);
1843 if (expr_type
== TypeManager
.int64_type
)
1844 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I8_I
);
1846 if (expr_type
== TypeManager
.uint64_type
)
1847 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.U8_I
);
1850 if (expr_type
.IsPointer
){
1851 if (target_type
== TypeManager
.sbyte_type
)
1852 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I1
);
1853 if (target_type
== TypeManager
.byte_type
)
1854 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U1
);
1855 if (target_type
== TypeManager
.short_type
)
1856 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I2
);
1857 if (target_type
== TypeManager
.ushort_type
)
1858 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U2
);
1859 if (target_type
== TypeManager
.int32_type
)
1860 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_I4
);
1861 if (target_type
== TypeManager
.uint32_type
)
1862 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U4
);
1863 if (target_type
== TypeManager
.int64_type
)
1864 return new ConvCast (expr
, target_type
, ConvCast
.Mode
.I_I8
);
1865 if (target_type
== TypeManager
.uint64_type
)
1866 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_U8
);
1872 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1874 static public Expression
ExplicitConversionStandard (ResolveContext ec
, Expression expr
,
1875 TypeSpec target_type
, Location l
)
1877 int errors
= ec
.Report
.Errors
;
1878 Expression ne
= ImplicitConversionStandard (ec
, expr
, target_type
, l
);
1879 if (ec
.Report
.Errors
> errors
)
1885 ne
= ExplicitNumericConversion (expr
, target_type
);
1889 ne
= ExplicitReferenceConversion (expr
, expr
.Type
, target_type
);
1893 if (ec
.IsUnsafe
&& expr
.Type
== TypeManager
.void_ptr_type
&& target_type
.IsPointer
)
1894 return EmptyCast
.Create (expr
, target_type
);
1896 expr
.Error_ValueCannotBeConverted (ec
, l
, target_type
, true);
1901 /// Performs an explicit conversion of the expression `expr' whose
1902 /// type is expr.Type to `target_type'.
1904 static public Expression
ExplicitConversion (ResolveContext ec
, Expression expr
,
1905 TypeSpec target_type
, Location loc
)
1907 Expression e
= ExplicitConversionCore (ec
, expr
, target_type
, loc
);
1910 // Don't eliminate explicit precission casts
1913 if (target_type
== TypeManager
.float_type
)
1914 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R4
);
1916 if (target_type
== TypeManager
.double_type
)
1917 return new OpcodeCast (expr
, target_type
, OpCodes
.Conv_R8
);
1923 TypeSpec expr_type
= expr
.Type
;
1924 if (TypeManager
.IsNullableType (target_type
)) {
1925 if (TypeManager
.IsNullableType (expr_type
)) {
1926 TypeSpec target
= Nullable
.NullableInfo
.GetUnderlyingType (target_type
);
1927 Expression unwrap
= Nullable
.Unwrap
.Create (expr
);
1928 e
= ExplicitConversion (ec
, unwrap
, target
, expr
.Location
);
1932 return new Nullable
.Lifted (e
, unwrap
, target_type
).Resolve (ec
);
1933 } else if (expr_type
== TypeManager
.object_type
) {
1934 return new UnboxCast (expr
, target_type
);
1936 TypeSpec target
= TypeManager
.GetTypeArguments (target_type
) [0];
1938 e
= ExplicitConversionCore (ec
, expr
, target
, loc
);
1940 return Nullable
.Wrap
.Create (e
, target_type
);
1942 } else if (TypeManager
.IsNullableType (expr_type
)) {
1943 e
= ImplicitBoxingConversion (expr
, Nullable
.NullableInfo
.GetUnderlyingType (expr_type
), target_type
);
1947 e
= Nullable
.Unwrap
.Create (expr
, false);
1948 e
= ExplicitConversionCore (ec
, e
, target_type
, loc
);
1950 return EmptyCast
.Create (e
, target_type
);
1953 e
= ExplicitUserConversion (ec
, expr
, target_type
, loc
);
1957 expr
.Error_ValueCannotBeConverted (ec
, loc
, target_type
, true);