2009-09-04 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / convert.cs
blobd9c903690fdbb60222d469c0cb56f1d603834df4
1 //
2 // conversion.cs: various routines for implementing conversions.
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Ravi Pratap (ravi@ximian.com)
7 // Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
21 // A container class for all the conversion operations
23 static class Convert {
25 static EmptyExpression MyEmptyExpr;
26 static DoubleHash explicit_conv;
27 static DoubleHash implicit_conv;
29 static Convert ()
31 Reset ();
34 public static void Reset ()
36 MyEmptyExpr = null;
37 explicit_conv = new DoubleHash (100);
38 implicit_conv = new DoubleHash (100);
41 static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
43 ArrayList list = new ArrayList ();
44 list.Add (gc.EffectiveBaseClass);
45 foreach (Type t in gc.InterfaceConstraints) {
46 if (!TypeManager.IsGenericParameter (t))
47 continue;
49 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
50 if (new_gc != null)
51 list.Add (TypeParam_EffectiveBaseType (new_gc));
53 return FindMostEncompassedType (list);
57 // From a one-dimensional array-type S[] to System.Collections.IList<T> and base
58 // interfaces of this interface, provided there is an implicit reference conversion
59 // from S to T.
61 static bool Array_To_IList (Type array, Type list, bool isExplicit)
63 if ((array.GetArrayRank () != 1) || !TypeManager.IsGenericType (list))
64 return false;
66 Type gt = TypeManager.DropGenericTypeArguments (list);
67 if ((gt != TypeManager.generic_ilist_type) &&
68 (gt != TypeManager.generic_icollection_type) &&
69 (gt != TypeManager.generic_ienumerable_type))
70 return false;
72 Type element_type = TypeManager.GetElementType (array);
73 Type arg_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (list) [0]);
75 if (element_type == arg_type)
76 return true;
78 if (isExplicit)
79 return ExplicitReferenceConversionExists (element_type, arg_type);
81 Type t = TypeManager.GetElementType (array);
82 if (MyEmptyExpr == null)
83 MyEmptyExpr = new EmptyExpression (t);
84 else
85 MyEmptyExpr.SetType (t);
87 return ImplicitReferenceConversionExists (MyEmptyExpr, arg_type);
90 static bool IList_To_Array(Type list, Type array)
92 if (!TypeManager.IsGenericType (list) || !array.IsArray || array.GetArrayRank() != 1)
93 return false;
95 Type gt = TypeManager.DropGenericTypeArguments (list);
96 if (gt != TypeManager.generic_ilist_type &&
97 gt != TypeManager.generic_icollection_type &&
98 gt != TypeManager.generic_ienumerable_type)
99 return false;
101 Type arg_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments(list)[0]);
102 Type element_type = TypeManager.GetElementType(array);
104 if (element_type == arg_type)
105 return true;
107 if (MyEmptyExpr == null)
108 MyEmptyExpr = new EmptyExpression(element_type);
109 else
110 MyEmptyExpr.SetType(element_type);
112 return ImplicitReferenceConversionExists(MyEmptyExpr, arg_type) || ExplicitReferenceConversionExists(element_type, arg_type);
115 static Expression ImplicitTypeParameterConversion (Expression expr,
116 Type target_type)
118 Type expr_type = expr.Type;
120 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
122 if (gc == null) {
123 if (target_type == TypeManager.object_type)
124 return new BoxedCast (expr, target_type);
126 return null;
129 // We're converting from a type parameter which is known to be a reference type.
130 Type base_type = TypeParam_EffectiveBaseType (gc);
132 if (TypeManager.IsSubclassOf (base_type, target_type))
133 return new ClassCast (expr, target_type);
135 if (target_type.IsInterface) {
136 if (TypeManager.ImplementsInterface (base_type, target_type))
137 return new ClassCast (expr, target_type);
139 foreach (Type t in gc.InterfaceConstraints) {
140 if (TypeManager.IsSubclassOf (t, target_type))
141 return new ClassCast (expr, target_type);
142 if (TypeManager.ImplementsInterface (t, target_type))
143 return new ClassCast (expr, target_type);
147 foreach (Type t in gc.InterfaceConstraints) {
148 if (!TypeManager.IsGenericParameter (t))
149 continue;
150 if (TypeManager.IsSubclassOf (t, target_type))
151 return new ClassCast (expr, target_type);
152 if (TypeManager.ImplementsInterface (t, target_type))
153 return new ClassCast (expr, target_type);
156 return null;
159 static bool ImplicitTypeParameterBoxingConversion (Type expr_type, Type target_type,
160 out bool use_class_cast)
162 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
164 if (gc == null) {
165 use_class_cast = false;
166 return target_type == TypeManager.object_type;
169 use_class_cast = true;
171 if (!gc.HasReferenceTypeConstraint)
172 return false;
174 // We're converting from a type parameter which is known to be a reference type.
175 Type base_type = TypeParam_EffectiveBaseType (gc);
177 if (TypeManager.IsSubclassOf (base_type, target_type))
178 return true;
180 if (target_type.IsInterface) {
181 if (TypeManager.ImplementsInterface (base_type, target_type))
182 return true;
184 foreach (Type t in gc.InterfaceConstraints) {
185 if (TypeManager.IsSubclassOf (t, target_type))
186 return true;
187 if (TypeManager.ImplementsInterface (t, target_type))
188 return true;
192 foreach (Type t in gc.InterfaceConstraints) {
193 if (!TypeManager.IsGenericParameter (t))
194 continue;
195 if (TypeManager.IsSubclassOf (t, target_type))
196 return true;
197 if (TypeManager.ImplementsInterface (t, target_type))
198 return true;
201 use_class_cast = false;
202 return false;
205 static Expression ExplicitTypeParameterConversion (Expression source, Type source_type, Type target_type)
207 if (TypeManager.IsGenericParameter (target_type)) {
208 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
209 if (gc == null)
210 return null;
212 foreach (Type iface in gc.InterfaceConstraints) {
213 if (!TypeManager.IsGenericParameter (iface))
214 continue;
216 if (TypeManager.IsSubclassOf (source_type, iface))
217 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
221 if (target_type.IsInterface)
222 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true);
224 return null;
227 static Expression ImplicitReferenceConversion (Expression expr, Type target_type, bool explicit_cast)
229 Type expr_type = expr.Type;
231 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
232 // if we are a method group, emit a warning
234 expr.Emit (null);
237 if (expr_type == TypeManager.void_type)
238 return null;
240 if (TypeManager.IsGenericParameter (expr_type))
241 return ImplicitTypeParameterConversion (expr, target_type);
244 // from the null type to any reference-type.
246 NullLiteral nl = expr as NullLiteral;
247 if (nl != null) {
248 return nl.ConvertImplicitly(target_type);
251 if (ImplicitReferenceConversionExists (expr, target_type)) {
253 // Avoid wrapping implicitly convertible reference type
255 if (!explicit_cast)
256 return expr;
258 return EmptyCast.Create (expr, target_type);
261 bool use_class_cast;
262 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast)) {
263 if (use_class_cast)
264 return new ClassCast (expr, target_type);
265 else
266 return new BoxedCast (expr, target_type);
269 return null;
273 // 6.1.6 Implicit reference conversions
275 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
277 if (TypeManager.IsStruct (target_type))
278 return false;
280 Type expr_type = expr.Type;
282 // from the null type to any reference-type.
283 if (expr_type == TypeManager.null_type)
284 return target_type != InternalType.AnonymousMethod;
286 if (TypeManager.IsGenericParameter (expr_type))
287 return ImplicitTypeParameterConversion (expr, target_type) != null;
290 // notice that it is possible to write "ValueType v = 1", the ValueType here
291 // is an abstract class, and not really a value type, so we apply the same rules.
293 if (target_type == TypeManager.object_type || TypeManager.IsDynamicType (target_type)) {
295 // A pointer type cannot be converted to object
297 if (expr_type.IsPointer)
298 return false;
300 if (TypeManager.IsValueType (expr_type))
301 return false;
303 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
304 // No mcs internal types are convertible
305 return expr_type.Module != typeof (Convert).Module;
308 return false;
309 } else if (target_type == TypeManager.value_type) {
310 return expr_type == TypeManager.enum_type;
311 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
313 // Special case: enumeration to System.Enum.
314 // System.Enum is not a value type, it is a class, so we need
315 // a boxing conversion
317 if (target_type == TypeManager.enum_type || TypeManager.IsGenericParameter (expr_type))
318 return false;
320 return true;
323 // This code is kind of mirrored inside ImplicitStandardConversionExists
324 // with the small distinction that we only probe there
326 // Always ensure that the code here and there is in sync
328 // from any class-type S to any interface-type T.
329 if (target_type.IsInterface) {
330 if (TypeManager.ImplementsInterface (expr_type, target_type)){
331 return !TypeManager.IsGenericParameter (expr_type) &&
332 !TypeManager.IsValueType (expr_type);
336 if (expr_type.IsArray) {
337 // from an array-type S to an array-type of type T
338 if (target_type.IsArray && expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
341 // Both SE and TE are reference-types
343 Type expr_element_type = TypeManager.GetElementType (expr_type);
344 if (!TypeManager.IsReferenceType (expr_element_type))
345 return false;
347 Type target_element_type = TypeManager.GetElementType (target_type);
348 if (!TypeManager.IsReferenceType (target_element_type))
349 return false;
351 if (MyEmptyExpr == null)
352 MyEmptyExpr = new EmptyExpression (expr_element_type);
353 else
354 MyEmptyExpr.SetType (expr_element_type);
356 return ImplicitStandardConversionExists (MyEmptyExpr, target_element_type);
359 // from an array-type to System.Array
360 if (target_type == TypeManager.array_type)
361 return true;
363 // from an array-type of type T to IList<T>
364 if (Array_To_IList (expr_type, target_type, false))
365 return true;
367 return false;
370 if (TypeManager.IsVariantOf (expr_type, target_type))
371 return true;
373 // from any interface type S to interface-type T.
374 if (expr_type.IsInterface && target_type.IsInterface) {
375 return TypeManager.ImplementsInterface (expr_type, target_type);
378 // from any delegate type to System.Delegate
379 if (target_type == TypeManager.delegate_type &&
380 (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)))
381 return true;
383 if (TypeManager.IsEqual (expr_type, target_type))
384 return true;
386 return false;
389 public static bool ImplicitBoxingConversionExists (Expression expr, Type target_type,
390 out bool use_class_cast)
392 Type expr_type = expr.Type;
393 use_class_cast = false;
396 // From any value-type to the type object.
398 if (target_type == TypeManager.object_type || TypeManager.IsDynamicType (target_type)) {
400 // A pointer type cannot be converted to object
402 if (expr_type.IsPointer)
403 return false;
405 return TypeManager.IsValueType (expr_type);
409 // From any value-type to the type System.ValueType.
411 if (target_type == TypeManager.value_type)
412 return TypeManager.IsValueType (expr_type);
414 if (target_type == TypeManager.enum_type) {
416 // From any enum-type to the type System.Enum.
418 if (TypeManager.IsEnumType (expr_type))
419 return true;
421 // From any nullable-type with an underlying enum-type to the type System.Enum
423 if (TypeManager.IsNullableType (expr_type))
424 return TypeManager.IsEnumType (TypeManager.GetTypeArguments (expr_type) [0]);
427 if (TypeManager.IsSubclassOf (expr_type, target_type)) {
429 // Don't box same type arguments
431 if (TypeManager.IsGenericParameter (expr_type) && expr_type != target_type)
432 return true;
434 return false;
437 // This code is kind of mirrored inside ImplicitStandardConversionExists
438 // with the small distinction that we only probe there
440 // Always ensure that the code here and there is in sync
442 // from any class-type S to any interface-type T.
443 if (target_type.IsInterface) {
444 if (TypeManager.ImplementsInterface (expr_type, target_type))
445 return TypeManager.IsGenericParameter (expr_type) ||
446 TypeManager.IsValueType (expr_type);
449 if (TypeManager.IsGenericParameter (expr_type))
450 return ImplicitTypeParameterBoxingConversion (
451 expr_type, target_type, out use_class_cast);
453 return false;
456 public static Expression ImplicitNulableConversion (ResolveContext ec, Expression expr, Type target_type)
458 Type expr_type = expr.Type;
461 // From null to any nullable type
463 if (expr_type == TypeManager.null_type)
464 return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location);
466 Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]);
467 Expression e;
469 // S? -> T?
470 if (TypeManager.IsNullableType (expr_type)) {
471 Type etype = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (expr_type)[0]);
473 if (ec == null)
474 return ImplicitConversionExists (ec, new EmptyExpression (etype), target) ? EmptyExpression.Null : null;
476 Expression unwrap = Nullable.Unwrap.Create (expr);
477 e = ImplicitConversion (ec, unwrap, target, expr.Location);
478 if (e == null)
479 return null;
481 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
484 // S -> T?
485 if (ec == null)
486 return ImplicitConversionExists (ec, expr, target) ? EmptyExpression.Null : null;
488 e = ImplicitConversion (ec, expr, target, expr.Location);
489 if (e != null)
490 return Nullable.Wrap.Create (e, target_type);
492 return null;
495 /// <summary>
496 /// Implicit Numeric Conversions.
498 /// expr is the expression to convert, returns a new expression of type
499 /// target_type or null if an implicit conversion is not possible.
500 /// </summary>
501 public static Expression ImplicitNumericConversion (Expression expr, Type target_type)
503 return ImplicitNumericConversion (expr, expr.Type, target_type);
506 static Expression ImplicitNumericConversion (Expression expr, Type expr_type, Type target_type)
508 if (expr_type == TypeManager.sbyte_type){
510 // From sbyte to short, int, long, float, double, decimal
512 if (target_type == TypeManager.int32_type)
513 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
514 if (target_type == TypeManager.int64_type)
515 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
516 if (target_type == TypeManager.double_type)
517 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
518 if (target_type == TypeManager.float_type)
519 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
520 if (target_type == TypeManager.short_type)
521 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
522 if (target_type == TypeManager.decimal_type)
523 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
524 } else if (expr_type == TypeManager.byte_type){
526 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
528 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type ||
529 target_type == TypeManager.short_type || target_type == TypeManager.ushort_type)
530 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
532 if (target_type == TypeManager.uint64_type)
533 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
534 if (target_type == TypeManager.int64_type)
535 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
536 if (target_type == TypeManager.float_type)
537 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
538 if (target_type == TypeManager.double_type)
539 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
540 if (target_type == TypeManager.decimal_type)
541 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
543 } else if (expr_type == TypeManager.short_type){
545 // From short to int, long, float, double, decimal
547 if (target_type == TypeManager.int32_type)
548 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
549 if (target_type == TypeManager.int64_type)
550 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
551 if (target_type == TypeManager.double_type)
552 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
553 if (target_type == TypeManager.float_type)
554 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
555 if (target_type == TypeManager.decimal_type)
556 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
558 } else if (expr_type == TypeManager.ushort_type){
560 // From ushort to int, uint, long, ulong, float, double, decimal
562 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type)
563 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
565 if (target_type == TypeManager.uint64_type)
566 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
567 if (target_type == TypeManager.int64_type)
568 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
569 if (target_type == TypeManager.double_type)
570 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
571 if (target_type == TypeManager.float_type)
572 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
573 if (target_type == TypeManager.decimal_type)
574 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
575 } else if (expr_type == TypeManager.int32_type){
577 // From int to long, float, double, decimal
579 if (target_type == TypeManager.int64_type)
580 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
581 if (target_type == TypeManager.double_type)
582 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
583 if (target_type == TypeManager.float_type)
584 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
585 if (target_type == TypeManager.decimal_type)
586 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
587 } else if (expr_type == TypeManager.uint32_type){
589 // From uint to long, ulong, float, double, decimal
591 if (target_type == TypeManager.int64_type)
592 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
593 if (target_type == TypeManager.uint64_type)
594 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
595 if (target_type == TypeManager.double_type)
596 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
597 if (target_type == TypeManager.float_type)
598 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
599 if (target_type == TypeManager.decimal_type)
600 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
601 } else if (expr_type == TypeManager.int64_type){
603 // From long/ulong to float, double
605 if (target_type == TypeManager.double_type)
606 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
607 if (target_type == TypeManager.float_type)
608 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
609 if (target_type == TypeManager.decimal_type)
610 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
611 } else if (expr_type == TypeManager.uint64_type){
613 // From ulong to float, double
615 if (target_type == TypeManager.double_type)
616 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
617 if (target_type == TypeManager.float_type)
618 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
619 if (target_type == TypeManager.decimal_type)
620 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
621 } else if (expr_type == TypeManager.char_type){
623 // From char to ushort, int, uint, long, ulong, float, double, decimal
625 if ((target_type == TypeManager.ushort_type) ||
626 (target_type == TypeManager.int32_type) ||
627 (target_type == TypeManager.uint32_type))
628 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
629 if (target_type == TypeManager.uint64_type)
630 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
631 if (target_type == TypeManager.int64_type)
632 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
633 if (target_type == TypeManager.float_type)
634 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
635 if (target_type == TypeManager.double_type)
636 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
637 if (target_type == TypeManager.decimal_type)
638 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
639 } else if (expr_type == TypeManager.float_type){
641 // float to double
643 if (target_type == TypeManager.double_type)
644 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
647 return null;
650 /// <summary>
651 /// Same as ImplicitStandardConversionExists except that it also looks at
652 /// implicit user defined conversions - needed for overload resolution
653 /// </summary>
654 public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, Type target_type)
656 if (ImplicitStandardConversionExists (expr, target_type))
657 return true;
659 if (expr.Type == InternalType.AnonymousMethod) {
660 if (!TypeManager.IsDelegateType (target_type) &&
661 TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type)
662 return false;
664 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
665 return ame.ImplicitStandardConversionExists (ec, target_type);
668 if (expr.eclass == ExprClass.MethodGroup) {
669 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) {
670 MethodGroupExpr mg = expr as MethodGroupExpr;
671 if (mg != null)
672 return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type);
675 return false;
678 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
681 public static bool ImplicitUserConversionExists (ResolveContext ec, Type source, Type target)
683 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
686 /// <summary>
687 /// Determines if a standard implicit conversion exists from
688 /// expr_type to target_type
690 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
691 /// </summary>
692 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
694 Type expr_type = expr.Type;
696 if (expr_type == TypeManager.null_type) {
697 NullLiteral nl = expr as NullLiteral;
698 if (nl != null)
699 return nl.ConvertImplicitly (target_type) != null;
702 if (expr_type == TypeManager.void_type)
703 return false;
705 if (TypeManager.IsEqual (expr_type, target_type))
706 return true;
708 if (TypeManager.IsNullableType (target_type))
709 return ImplicitNulableConversion (null, expr, target_type) != null;
711 // First numeric conversions
712 if (ImplicitNumericConversion (null, expr_type, target_type) != null)
713 return true;
715 if (ImplicitReferenceConversionExists (expr, target_type))
716 return true;
718 bool use_class_cast;
719 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
720 return true;
723 // Implicit Constant Expression Conversions
725 if (expr is IntConstant){
726 int value = ((IntConstant) expr).Value;
728 if (target_type == TypeManager.sbyte_type){
729 if (value >= SByte.MinValue && value <= SByte.MaxValue)
730 return true;
731 } else if (target_type == TypeManager.byte_type){
732 if (value >= 0 && value <= Byte.MaxValue)
733 return true;
734 } else if (target_type == TypeManager.short_type){
735 if (value >= Int16.MinValue && value <= Int16.MaxValue)
736 return true;
737 } else if (target_type == TypeManager.ushort_type){
738 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
739 return true;
740 } else if (target_type == TypeManager.uint32_type){
741 if (value >= 0)
742 return true;
743 } else if (target_type == TypeManager.uint64_type){
745 // we can optimize this case: a positive int32
746 // always fits on a uint64. But we need an opcode
747 // to do it.
749 if (value >= 0)
750 return true;
753 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
754 return true;
757 if (expr is LongConstant && target_type == TypeManager.uint64_type){
759 // Try the implicit constant expression conversion
760 // from long to ulong, instead of a nice routine,
761 // we just inline it
763 long v = ((LongConstant) expr).Value;
764 if (v >= 0)
765 return true;
769 // If `expr_type' implements `target_type' (which is an iface)
770 // see TryImplicitIntConversion
772 if (target_type.IsInterface && TypeManager.ImplementsInterface (expr_type, target_type))
773 return true;
775 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
776 return true;
778 // Conversion from __arglist to System.ArgIterator
779 if (expr_type == InternalType.Arglist)
780 return target_type == TypeManager.arg_iterator_type;
782 return false;
785 /// <summary>
786 /// Finds "most encompassed type" according to the spec (13.4.2)
787 /// amongst the methods in the MethodGroupExpr
788 /// </summary>
789 static Type FindMostEncompassedType (ArrayList types)
791 Type best = null;
793 if (types.Count == 0)
794 return null;
796 if (types.Count == 1)
797 return (Type) types [0];
799 EmptyExpression expr = EmptyExpression.Grab ();
801 foreach (Type t in types) {
802 if (best == null) {
803 best = t;
804 continue;
807 expr.SetType (t);
808 if (ImplicitStandardConversionExists (expr, best))
809 best = t;
812 expr.SetType (best);
813 foreach (Type t in types) {
814 if (best == t)
815 continue;
816 if (!ImplicitStandardConversionExists (expr, t)) {
817 best = null;
818 break;
822 EmptyExpression.Release (expr);
824 return best;
827 /// <summary>
828 /// Finds "most encompassing type" according to the spec (13.4.2)
829 /// amongst the types in the given set
830 /// </summary>
831 static Type FindMostEncompassingType (ArrayList types)
833 Type best = null;
835 if (types.Count == 0)
836 return null;
838 if (types.Count == 1)
839 return (Type) types [0];
841 EmptyExpression expr = EmptyExpression.Grab ();
843 foreach (Type t in types) {
844 if (best == null) {
845 best = t;
846 continue;
849 expr.SetType (best);
850 if (ImplicitStandardConversionExists (expr, t))
851 best = t;
854 foreach (Type t in types) {
855 if (best == t)
856 continue;
857 expr.SetType (t);
858 if (!ImplicitStandardConversionExists (expr, best)) {
859 best = null;
860 break;
864 EmptyExpression.Release (expr);
866 return best;
869 /// <summary>
870 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
871 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
872 /// for explicit and implicit conversion operators.
873 /// </summary>
874 static public Type FindMostSpecificSource (IList list,
875 Expression source, bool apply_explicit_conv_rules)
877 ArrayList src_types_set = new ArrayList ();
880 // If any operator converts from S then Sx = S
882 Type source_type = source.Type;
883 foreach (MethodBase mb in list){
884 AParametersCollection pd = TypeManager.GetParameterData (mb);
885 Type param_type = pd.Types [0];
887 if (param_type == source_type)
888 return param_type;
890 src_types_set.Add (param_type);
894 // Explicit Conv rules
896 if (apply_explicit_conv_rules) {
897 ArrayList candidate_set = new ArrayList ();
899 foreach (Type param_type in src_types_set){
900 if (ImplicitStandardConversionExists (source, param_type))
901 candidate_set.Add (param_type);
904 if (candidate_set.Count != 0)
905 return FindMostEncompassedType (candidate_set);
909 // Final case
911 if (apply_explicit_conv_rules)
912 return FindMostEncompassingType (src_types_set);
913 else
914 return FindMostEncompassedType (src_types_set);
917 /// <summary>
918 /// Finds the most specific target Tx according to section 13.4.4
919 /// </summary>
920 static public Type FindMostSpecificTarget (IList list,
921 Type target, bool apply_explicit_conv_rules)
923 ArrayList tgt_types_set = new ArrayList ();
926 // If any operator converts to T then Tx = T
928 foreach (MethodInfo mi in list){
929 Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType);
930 if (ret_type == target)
931 return ret_type;
933 tgt_types_set.Add (ret_type);
937 // Explicit conv rules
939 if (apply_explicit_conv_rules) {
940 ArrayList candidate_set = new ArrayList ();
942 EmptyExpression expr = EmptyExpression.Grab ();
944 foreach (Type ret_type in tgt_types_set){
945 expr.SetType (ret_type);
947 if (ImplicitStandardConversionExists (expr, target))
948 candidate_set.Add (ret_type);
951 EmptyExpression.Release (expr);
953 if (candidate_set.Count != 0)
954 return FindMostEncompassingType (candidate_set);
958 // Okay, final case !
960 if (apply_explicit_conv_rules)
961 return FindMostEncompassedType (tgt_types_set);
962 else
963 return FindMostEncompassingType (tgt_types_set);
966 /// <summary>
967 /// User-defined Implicit conversions
968 /// </summary>
969 static public Expression ImplicitUserConversion (ResolveContext ec, Expression source,
970 Type target, Location loc)
972 Expression expr = UserDefinedConversion (ec, source, target, loc, false);
973 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
974 expr = ImplicitConversionStandard (ec, expr, target, loc);
976 return expr;
979 /// <summary>
980 /// User-defined Explicit conversions
981 /// </summary>
982 static public Expression ExplicitUserConversion (ResolveContext ec, Expression source,
983 Type target, Location loc)
985 Expression expr = UserDefinedConversion (ec, source, target, loc, true);
986 if (expr != null && !TypeManager.IsEqual (expr.Type, target))
987 expr = ExplicitConversionStandard (ec, expr, target, loc);
989 return expr;
992 static void AddConversionOperators (ArrayList list,
993 Expression source, Type target_type,
994 bool look_for_explicit,
995 MethodGroupExpr mg)
997 if (mg == null)
998 return;
1000 Type source_type = source.Type;
1001 EmptyExpression expr = EmptyExpression.Grab ();
1004 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
1005 // IntPtr -> uint uses int
1006 // UIntPtr -> long uses ulong
1008 if (source_type == TypeManager.intptr_type) {
1009 if (target_type == TypeManager.uint32_type)
1010 target_type = TypeManager.int32_type;
1011 } else if (source_type == TypeManager.uintptr_type) {
1012 if (target_type == TypeManager.int64_type)
1013 target_type = TypeManager.uint64_type;
1016 foreach (MethodInfo m in mg.Methods) {
1017 AParametersCollection pd = TypeManager.GetParameterData (m);
1018 Type return_type = TypeManager.TypeToCoreType (m.ReturnType);
1019 Type arg_type = pd.Types [0];
1021 if (source_type != arg_type) {
1022 if (!ImplicitStandardConversionExists (source, arg_type)) {
1023 if (!look_for_explicit)
1024 continue;
1025 expr.SetType (arg_type);
1026 if (!ImplicitStandardConversionExists (expr, source_type))
1027 continue;
1031 if (target_type != return_type) {
1032 expr.SetType (return_type);
1033 if (!ImplicitStandardConversionExists (expr, target_type)) {
1034 if (!look_for_explicit)
1035 continue;
1036 expr.SetType (target_type);
1037 if (!ImplicitStandardConversionExists (expr, return_type))
1038 continue;
1042 // See LAMESPEC: Exclude IntPtr -> int conversion
1043 if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type)
1044 continue;
1046 list.Add (m);
1049 EmptyExpression.Release (expr);
1052 /// <summary>
1053 /// Compute the user-defined conversion operator from source_type to target_type.
1054 /// `look_for_explicit' controls whether we should also include the list of explicit operators
1055 /// </summary>
1056 static MethodInfo GetConversionOperator (Type container_type, Expression source, Type target_type, bool look_for_explicit)
1058 ArrayList ops = new ArrayList (4);
1060 Type source_type = source.Type;
1062 if (source_type != TypeManager.decimal_type) {
1063 AddConversionOperators (ops, source, target_type, look_for_explicit,
1064 Expression.MethodLookup (container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1065 if (look_for_explicit) {
1066 AddConversionOperators (ops, source, target_type, look_for_explicit,
1067 Expression.MethodLookup (
1068 container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1072 if (target_type != TypeManager.decimal_type) {
1073 AddConversionOperators (ops, source, target_type, look_for_explicit,
1074 Expression.MethodLookup (container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1075 if (look_for_explicit) {
1076 AddConversionOperators (ops, source, target_type, look_for_explicit,
1077 Expression.MethodLookup (
1078 container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1082 if (ops.Count == 0)
1083 return null;
1085 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
1086 if (most_specific_source == null)
1087 return null;
1089 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
1090 if (most_specific_target == null)
1091 return null;
1093 MethodInfo method = null;
1095 foreach (MethodInfo m in ops) {
1096 if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target)
1097 continue;
1098 if (TypeManager.GetParameterData (m).Types [0] != most_specific_source)
1099 continue;
1100 // Ambiguous: more than one conversion operator satisfies the signature.
1101 if (method != null)
1102 return null;
1103 method = m;
1106 return method;
1109 /// <summary>
1110 /// User-defined conversions
1111 /// </summary>
1112 static public Expression UserDefinedConversion (ResolveContext ec, Expression source,
1113 Type target, Location loc,
1114 bool look_for_explicit)
1116 Type source_type = source.Type;
1117 MethodInfo method = null;
1119 object o;
1120 DoubleHash hash;
1121 if (look_for_explicit) {
1122 hash = explicit_conv;
1123 } else {
1124 // Implicit user operators cannot convert to interfaces
1125 if (target.IsInterface)
1126 return null;
1128 hash = implicit_conv;
1131 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1132 method = (MethodInfo) o;
1133 } else {
1134 method = GetConversionOperator (null, source, target, look_for_explicit);
1135 if (!(source is Constant))
1136 hash.Insert (source_type, target, method);
1139 if (method == null)
1140 return null;
1142 Type most_specific_source = TypeManager.GetParameterData (method).Types [0];
1145 // This will do the conversion to the best match that we
1146 // found. Now we need to perform an implict standard conversion
1147 // if the best match was not the type that we were requested
1148 // by target.
1150 if (look_for_explicit)
1151 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1152 else
1153 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1155 if (source == null)
1156 return null;
1158 return new UserCast (method, source, loc).DoResolve (ec);
1161 /// <summary>
1162 /// Converts implicitly the resolved expression `expr' into the
1163 /// `target_type'. It returns a new expression that can be used
1164 /// in a context that expects a `target_type'.
1165 /// </summary>
1166 static public Expression ImplicitConversion (ResolveContext ec, Expression expr,
1167 Type target_type, Location loc)
1169 Expression e;
1171 if (target_type == null)
1172 throw new Exception ("Target type is null");
1174 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1175 if (e != null)
1176 return e;
1178 e = ImplicitUserConversion (ec, expr, target_type, loc);
1179 if (e != null)
1180 return e;
1182 return null;
1186 /// <summary>
1187 /// Attempts to apply the `Standard Implicit
1188 /// Conversion' rules to the expression `expr' into
1189 /// the `target_type'. It returns a new expression
1190 /// that can be used in a context that expects a
1191 /// `target_type'.
1193 /// This is different from `ImplicitConversion' in that the
1194 /// user defined implicit conversions are excluded.
1195 /// </summary>
1196 static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr,
1197 Type target_type, Location loc)
1199 return ImplicitConversionStandard (ec, expr, target_type, loc, false);
1202 static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast)
1204 if (expr.eclass == ExprClass.MethodGroup){
1205 if (!TypeManager.IsDelegateType (target_type)){
1206 return null;
1210 // Only allow anonymous method conversions on post ISO_1
1212 if (RootContext.Version != LanguageVersion.ISO_1){
1213 MethodGroupExpr mg = expr as MethodGroupExpr;
1214 if (mg != null)
1215 return ImplicitDelegateCreation.Create (
1216 ec, mg, target_type, loc);
1220 Type expr_type = expr.Type;
1221 Expression e;
1223 if (expr_type.Equals (target_type)) {
1224 if (expr_type != TypeManager.null_type && expr_type != InternalType.AnonymousMethod)
1225 return expr;
1226 return null;
1229 if (TypeManager.IsVariantOf (expr_type, target_type)) {
1230 return expr;
1233 if (TypeManager.IsNullableType (target_type))
1234 return ImplicitNulableConversion (ec, expr, target_type);
1237 // Attempt to do the implicit constant expression conversions
1239 Constant c = expr as Constant;
1240 if (c != null) {
1241 try {
1242 c = c.ConvertImplicitly (target_type);
1243 } catch {
1244 Console.WriteLine ("Conversion error happened in line {0}", loc);
1245 throw;
1247 if (c != null)
1248 return c;
1251 e = ImplicitNumericConversion (expr, expr_type, target_type);
1252 if (e != null)
1253 return e;
1255 e = ImplicitReferenceConversion (expr, target_type, explicit_cast);
1256 if (e != null)
1257 return e;
1259 if (expr is IntConstant && TypeManager.IsEnumType (target_type)){
1260 Constant i = (Constant) expr;
1262 // LAMESPEC: Conversion from any 0 constant is allowed
1264 // An implicit enumeration conversion permits the decimal-integer-literal 0
1265 // to be converted to any enum-type and to any nullable-type whose underlying
1266 // type is an enum-type
1268 if (i.IsDefaultValue)
1269 return new EnumConstant (i, target_type);
1272 if (ec.IsUnsafe) {
1273 if (expr_type.IsPointer){
1274 if (target_type == TypeManager.void_ptr_type)
1275 return EmptyCast.Create (expr, target_type);
1278 // yep, comparing pointer types cant be done with
1279 // t1 == t2, we have to compare their element types.
1281 if (target_type.IsPointer){
1282 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1283 return expr;
1285 //return null;
1289 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1290 return EmptyCast.Create (new NullPointer (loc), target_type);
1293 if (expr_type == InternalType.AnonymousMethod){
1294 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
1295 Expression am = ame.Compatible (ec, target_type);
1296 if (am != null)
1297 return am.DoResolve (ec);
1300 if (expr_type == InternalType.Arglist && target_type == TypeManager.arg_iterator_type)
1301 return expr;
1303 return null;
1306 /// <summary>
1307 /// Attempts to implicitly convert `source' into `target_type', using
1308 /// ImplicitConversion. If there is no implicit conversion, then
1309 /// an error is signaled
1310 /// </summary>
1311 static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source,
1312 Type target_type, Location loc)
1314 Expression e = ImplicitConversion (ec, source, target_type, loc);
1315 if (e != null)
1316 return e;
1318 source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
1319 return null;
1322 /// <summary>
1323 /// Performs the explicit numeric conversions
1325 /// There are a few conversions that are not part of the C# standard,
1326 /// they were interim hacks in the C# compiler that were supposed to
1327 /// become explicit operators in the UIntPtr class and IntPtr class,
1328 /// but for historical reasons it did not happen, so the C# compiler
1329 /// ended up with these special hacks.
1331 /// See bug 59800 for details.
1333 /// The conversion are:
1334 /// UIntPtr->SByte
1335 /// UIntPtr->Int16
1336 /// UIntPtr->Int32
1337 /// IntPtr->UInt64
1338 /// UInt64->IntPtr
1339 /// SByte->UIntPtr
1340 /// Int16->UIntPtr
1342 /// </summary>
1343 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1345 Type expr_type = expr.Type;
1346 Type real_target_type = target_type;
1348 if (expr_type == TypeManager.sbyte_type){
1350 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1352 if (real_target_type == TypeManager.byte_type)
1353 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1354 if (real_target_type == TypeManager.ushort_type)
1355 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1356 if (real_target_type == TypeManager.uint32_type)
1357 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1358 if (real_target_type == TypeManager.uint64_type)
1359 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1360 if (real_target_type == TypeManager.char_type)
1361 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1363 // One of the built-in conversions that belonged in the class library
1364 if (real_target_type == TypeManager.uintptr_type){
1365 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I1_U8);
1367 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1369 } else if (expr_type == TypeManager.byte_type){
1371 // From byte to sbyte and char
1373 if (real_target_type == TypeManager.sbyte_type)
1374 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1375 if (real_target_type == TypeManager.char_type)
1376 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1377 } else if (expr_type == TypeManager.short_type){
1379 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1381 if (real_target_type == TypeManager.sbyte_type)
1382 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1383 if (real_target_type == TypeManager.byte_type)
1384 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1385 if (real_target_type == TypeManager.ushort_type)
1386 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1387 if (real_target_type == TypeManager.uint32_type)
1388 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1389 if (real_target_type == TypeManager.uint64_type)
1390 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1391 if (real_target_type == TypeManager.char_type)
1392 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1394 // One of the built-in conversions that belonged in the class library
1395 if (real_target_type == TypeManager.uintptr_type){
1396 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1398 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1400 } else if (expr_type == TypeManager.ushort_type){
1402 // From ushort to sbyte, byte, short, char
1404 if (real_target_type == TypeManager.sbyte_type)
1405 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1406 if (real_target_type == TypeManager.byte_type)
1407 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1408 if (real_target_type == TypeManager.short_type)
1409 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1410 if (real_target_type == TypeManager.char_type)
1411 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1412 } else if (expr_type == TypeManager.int32_type){
1414 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1416 if (real_target_type == TypeManager.sbyte_type)
1417 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1418 if (real_target_type == TypeManager.byte_type)
1419 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1420 if (real_target_type == TypeManager.short_type)
1421 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1422 if (real_target_type == TypeManager.ushort_type)
1423 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1424 if (real_target_type == TypeManager.uint32_type)
1425 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1426 if (real_target_type == TypeManager.uint64_type)
1427 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1428 if (real_target_type == TypeManager.char_type)
1429 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1431 // One of the built-in conversions that belonged in the class library
1432 if (real_target_type == TypeManager.uintptr_type){
1433 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1435 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1437 } else if (expr_type == TypeManager.uint32_type){
1439 // From uint to sbyte, byte, short, ushort, int, char
1441 if (real_target_type == TypeManager.sbyte_type)
1442 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1443 if (real_target_type == TypeManager.byte_type)
1444 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1445 if (real_target_type == TypeManager.short_type)
1446 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1447 if (real_target_type == TypeManager.ushort_type)
1448 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1449 if (real_target_type == TypeManager.int32_type)
1450 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1451 if (real_target_type == TypeManager.char_type)
1452 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1453 } else if (expr_type == TypeManager.int64_type){
1455 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1457 if (real_target_type == TypeManager.sbyte_type)
1458 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1459 if (real_target_type == TypeManager.byte_type)
1460 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1461 if (real_target_type == TypeManager.short_type)
1462 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1463 if (real_target_type == TypeManager.ushort_type)
1464 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1465 if (real_target_type == TypeManager.int32_type)
1466 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1467 if (real_target_type == TypeManager.uint32_type)
1468 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1469 if (real_target_type == TypeManager.uint64_type)
1470 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1471 if (real_target_type == TypeManager.char_type)
1472 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1473 } else if (expr_type == TypeManager.uint64_type){
1475 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1477 if (real_target_type == TypeManager.sbyte_type)
1478 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1479 if (real_target_type == TypeManager.byte_type)
1480 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1481 if (real_target_type == TypeManager.short_type)
1482 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1483 if (real_target_type == TypeManager.ushort_type)
1484 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1485 if (real_target_type == TypeManager.int32_type)
1486 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1487 if (real_target_type == TypeManager.uint32_type)
1488 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1489 if (real_target_type == TypeManager.int64_type)
1490 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1491 if (real_target_type == TypeManager.char_type)
1492 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1494 // One of the built-in conversions that belonged in the class library
1495 if (real_target_type == TypeManager.intptr_type){
1496 return new OperatorCast (EmptyCast.Create (expr, TypeManager.int64_type),
1497 TypeManager.intptr_type, true);
1499 } else if (expr_type == TypeManager.char_type){
1501 // From char to sbyte, byte, short
1503 if (real_target_type == TypeManager.sbyte_type)
1504 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1505 if (real_target_type == TypeManager.byte_type)
1506 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1507 if (real_target_type == TypeManager.short_type)
1508 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1509 } else if (expr_type == TypeManager.float_type){
1511 // From float to sbyte, byte, short,
1512 // ushort, int, uint, long, ulong, char
1513 // or decimal
1515 if (real_target_type == TypeManager.sbyte_type)
1516 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1517 if (real_target_type == TypeManager.byte_type)
1518 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1519 if (real_target_type == TypeManager.short_type)
1520 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1521 if (real_target_type == TypeManager.ushort_type)
1522 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1523 if (real_target_type == TypeManager.int32_type)
1524 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1525 if (real_target_type == TypeManager.uint32_type)
1526 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1527 if (real_target_type == TypeManager.int64_type)
1528 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1529 if (real_target_type == TypeManager.uint64_type)
1530 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1531 if (real_target_type == TypeManager.char_type)
1532 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1533 if (real_target_type == TypeManager.decimal_type)
1534 return new CastToDecimal (expr, true);
1535 } else if (expr_type == TypeManager.double_type){
1537 // From double to sbyte, byte, short,
1538 // ushort, int, uint, long, ulong,
1539 // char, float or decimal
1541 if (real_target_type == TypeManager.sbyte_type)
1542 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1543 if (real_target_type == TypeManager.byte_type)
1544 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1545 if (real_target_type == TypeManager.short_type)
1546 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1547 if (real_target_type == TypeManager.ushort_type)
1548 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1549 if (real_target_type == TypeManager.int32_type)
1550 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1551 if (real_target_type == TypeManager.uint32_type)
1552 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1553 if (real_target_type == TypeManager.int64_type)
1554 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1555 if (real_target_type == TypeManager.uint64_type)
1556 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1557 if (real_target_type == TypeManager.char_type)
1558 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1559 if (real_target_type == TypeManager.float_type)
1560 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1561 if (real_target_type == TypeManager.decimal_type)
1562 return new CastToDecimal (expr, true);
1563 } else if (expr_type == TypeManager.uintptr_type){
1565 // Various built-in conversions that belonged in the class library
1567 // from uintptr to sbyte, short, int32
1569 if (real_target_type == TypeManager.sbyte_type){
1570 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1571 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I1);
1573 if (real_target_type == TypeManager.short_type){
1574 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1575 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I2);
1577 if (real_target_type == TypeManager.int32_type){
1578 return EmptyCast.Create (new OperatorCast (expr, TypeManager.uint32_type, true),
1579 TypeManager.int32_type);
1581 } else if (expr_type == TypeManager.intptr_type){
1582 if (real_target_type == TypeManager.uint64_type){
1583 return EmptyCast.Create (new OperatorCast (expr, TypeManager.int64_type, true),
1584 TypeManager.uint64_type);
1586 } else if (expr_type == TypeManager.decimal_type) {
1587 return new CastFromDecimal (expr, target_type).Resolve ();
1589 return null;
1592 /// <summary>
1593 /// Returns whether an explicit reference conversion can be performed
1594 /// from source_type to target_type
1595 /// </summary>
1596 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1598 Expression e = ExplicitReferenceConversion (null, source_type, target_type);
1599 if (e == null)
1600 return false;
1602 if (e == EmptyExpression.Null)
1603 return true;
1605 throw new InternalErrorException ("Invalid probing conversion result");
1608 /// <summary>
1609 /// Implements Explicit Reference conversions
1610 /// </summary>
1611 static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type)
1613 bool target_is_value_type = TypeManager.IsStruct (target_type);
1616 // From object to a generic parameter
1618 if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type))
1619 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1622 // Explicit type parameter conversion.
1624 if (TypeManager.IsGenericParameter (source_type))
1625 return ExplicitTypeParameterConversion (source, source_type, target_type);
1628 // From object to any reference type or value type (unboxing)
1630 if (source_type == TypeManager.object_type)
1631 return source == null ? EmptyExpression.Null :
1632 target_is_value_type ? (Expression) new UnboxCast (source, target_type) : new ClassCast (source, target_type);
1635 // Unboxing conversion from the types object and System.ValueType to any non-nullable-value-type
1637 if (source_type == TypeManager.value_type && target_is_value_type)
1638 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1641 // From any class S to any class-type T, provided S is a base class of T
1643 if (TypeManager.IsSubclassOf (target_type, source_type))
1644 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1647 // From any class type S to any interface T, provides S is not sealed
1648 // and provided S does not implement T.
1650 if (target_type.IsInterface && !source_type.IsSealed &&
1651 !TypeManager.ImplementsInterface (source_type, target_type)) {
1652 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1656 // From any interface-type S to to any class type T, provided T is not
1657 // sealed, or provided T implements S.
1659 if (source_type.IsInterface) {
1660 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1661 if (target_type.IsClass)
1662 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1665 // Unboxing conversion from any interface-type to any non-nullable-value-type that
1666 // implements the interface-type
1668 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1672 // From System.Collecitons.Generic.IList<T> and its base interfaces to a one-dimensional
1673 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1675 if (IList_To_Array (source_type, target_type))
1676 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1678 return null;
1681 if (source_type.IsArray) {
1682 if (target_type.IsArray) {
1684 // From System.Array to any array-type
1686 if (source_type == TypeManager.array_type)
1687 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1690 // From an array type S with an element type Se to an array type T with an
1691 // element type Te provided all the following are true:
1692 // * S and T differe only in element type, in other words, S and T
1693 // have the same number of dimensions.
1694 // * Both Se and Te are reference types
1695 // * An explicit reference conversions exist from Se to Te
1697 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1699 source_type = TypeManager.GetElementType (source_type);
1700 if (!TypeManager.IsReferenceType (source_type))
1701 return null;
1703 Type target_type_element = TypeManager.GetElementType (target_type);
1704 if (!TypeManager.IsReferenceType (target_type_element))
1705 return null;
1707 if (ExplicitReferenceConversionExists (source_type, target_type_element))
1708 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1710 return null;
1715 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1716 // provided that there is an explicit reference conversion from S to T
1718 if (Array_To_IList (source_type, target_type, true))
1719 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1721 return null;
1725 // From System delegate to any delegate-type
1727 if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
1728 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1730 return null;
1733 /// <summary>
1734 /// Performs an explicit conversion of the expression `expr' whose
1735 /// type is expr.Type to `target_type'.
1736 /// </summary>
1737 static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr,
1738 Type target_type, Location loc)
1740 Type expr_type = expr.Type;
1742 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1743 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true);
1744 if (ne != null)
1745 return ne;
1747 if (TypeManager.IsEnumType (expr_type)) {
1748 Expression underlying = EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type));
1749 expr = ExplicitConversionCore (ec, underlying, target_type, loc);
1750 if (expr != null)
1751 return expr;
1753 return ExplicitUserConversion (ec, underlying, target_type, loc);
1756 if (TypeManager.IsEnumType (target_type)){
1758 // Type System.Enum can be unboxed to any enum-type
1760 if (expr_type == TypeManager.enum_type)
1761 return new UnboxCast (expr, target_type);
1763 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1764 if (ce != null)
1765 return EmptyCast.Create (ce, target_type);
1768 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1770 if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
1771 ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1772 if (ne != null)
1773 return ExplicitConversionCore (ec, ne, target_type, loc);
1776 return null;
1779 ne = ExplicitNumericConversion (expr, target_type);
1780 if (ne != null)
1781 return ne;
1784 // Skip the ExplicitReferenceConversion because we can not convert
1785 // from Null to a ValueType, and ExplicitReference wont check against
1786 // null literal explicitly
1788 if (expr_type != TypeManager.null_type){
1789 ne = ExplicitReferenceConversion (expr, expr_type, target_type);
1790 if (ne != null)
1791 return ne;
1794 if (ec.IsUnsafe){
1795 ne = ExplicitUnsafe (expr, target_type);
1796 if (ne != null)
1797 return ne;
1800 return null;
1803 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1805 Type expr_type = expr.Type;
1807 if (target_type.IsPointer){
1808 if (expr_type.IsPointer)
1809 return EmptyCast.Create (expr, target_type);
1811 if (expr_type == TypeManager.sbyte_type ||
1812 expr_type == TypeManager.short_type ||
1813 expr_type == TypeManager.int32_type)
1814 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1816 if (expr_type == TypeManager.ushort_type ||
1817 expr_type == TypeManager.uint32_type ||
1818 expr_type == TypeManager.uint64_type || expr_type == TypeManager.int64_type ||
1819 expr_type == TypeManager.byte_type)
1820 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1823 if (expr_type.IsPointer){
1824 if (target_type == TypeManager.sbyte_type)
1825 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1826 else if (target_type == TypeManager.byte_type)
1827 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1828 else if (target_type == TypeManager.short_type)
1829 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1830 else if (target_type == TypeManager.ushort_type)
1831 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1832 else if (target_type == TypeManager.int32_type)
1833 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1834 else if (target_type == TypeManager.uint32_type)
1835 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1836 else if (target_type == TypeManager.uint64_type || target_type == TypeManager.int64_type)
1837 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1839 return null;
1842 /// <summary>
1843 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1844 /// </summary>
1845 static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr,
1846 Type target_type, Location l)
1848 int errors = Report.Errors;
1849 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1850 if (Report.Errors > errors)
1851 return null;
1853 if (ne != null)
1854 return ne;
1856 ne = ExplicitNumericConversion (expr, target_type);
1857 if (ne != null)
1858 return ne;
1860 ne = ExplicitReferenceConversion (expr, expr.Type, target_type);
1861 if (ne != null)
1862 return ne;
1864 if (ec.IsUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1865 return EmptyCast.Create (expr, target_type);
1867 expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
1868 return null;
1871 /// <summary>
1872 /// Performs an explicit conversion of the expression `expr' whose
1873 /// type is expr.Type to `target_type'.
1874 /// </summary>
1875 static public Expression ExplicitConversion (ResolveContext ec, Expression expr,
1876 Type target_type, Location loc)
1878 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1879 if (e != null)
1880 return e;
1882 Type expr_type = expr.Type;
1883 if (TypeManager.IsNullableType (target_type)) {
1884 if (TypeManager.IsNullableType (expr_type)) {
1885 Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]);
1886 Expression unwrap = Nullable.Unwrap.Create (expr);
1887 e = ExplicitConversion (ec, unwrap, target, expr.Location);
1888 if (e == null)
1889 return null;
1891 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
1892 } else if (expr_type == TypeManager.object_type) {
1893 return new UnboxCast (expr, target_type);
1894 } else {
1895 Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type) [0]);
1897 e = ExplicitConversionCore (ec, expr, target, loc);
1898 if (e != null)
1899 return Nullable.Wrap.Create (e, target_type);
1901 } else if (TypeManager.IsNullableType (expr_type)) {
1902 e = Nullable.Unwrap.Create (expr, false);
1904 bool use_class_cast;
1905 if (ImplicitBoxingConversionExists (e, target_type, out use_class_cast))
1906 return new BoxedCast (expr, target_type);
1908 e = ExplicitConversion (ec, e, target_type, loc);
1909 if (e != null)
1910 e = EmptyCast.Create (e, target_type);
1911 return e;
1914 e = ExplicitUserConversion (ec, expr, target_type, loc);
1915 if (e != null)
1916 return e;
1918 expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);
1919 return null;