2010-01-12 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / convert.cs
blob4acb499aa45ea6e70b91c27f4e122e428e1de51c
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 // S -> T?
467 Type t_el = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]);
469 // S? -> T?
470 if (TypeManager.IsNullableType (expr_type))
471 expr_type = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (expr_type)[0]);
474 // Predefined implicit identity or implicit numeric conversion
475 // has to exist between underlying type S and underlying type T
478 // Handles probing
479 if (ec == null) {
480 if (expr_type == t_el)
481 return EmptyExpression.Null;
483 return ImplicitNumericConversion (null, expr_type, t_el);
486 Expression unwrap;
487 if (expr_type != expr.Type)
488 unwrap = Nullable.Unwrap.Create (expr);
489 else
490 unwrap = expr;
492 Expression conv = expr_type == t_el ? unwrap : ImplicitNumericConversion (unwrap, expr_type, t_el);
493 if (conv == null)
494 return null;
496 if (expr_type != expr.Type)
497 return new Nullable.Lifted (conv, unwrap, target_type).Resolve (ec);
499 // Do constant optimization for S -> T?
500 if (unwrap is Constant)
501 conv = ((Constant) unwrap).ConvertImplicitly (t_el);
503 return Nullable.Wrap.Create (conv, target_type);
506 /// <summary>
507 /// Implicit Numeric Conversions.
509 /// expr is the expression to convert, returns a new expression of type
510 /// target_type or null if an implicit conversion is not possible.
511 /// </summary>
512 public static Expression ImplicitNumericConversion (Expression expr, Type target_type)
514 return ImplicitNumericConversion (expr, expr.Type, target_type);
517 static Expression ImplicitNumericConversion (Expression expr, Type expr_type, Type target_type)
519 if (expr_type == TypeManager.sbyte_type){
521 // From sbyte to short, int, long, float, double, decimal
523 if (target_type == TypeManager.int32_type)
524 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
525 if (target_type == TypeManager.int64_type)
526 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
527 if (target_type == TypeManager.double_type)
528 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
529 if (target_type == TypeManager.float_type)
530 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
531 if (target_type == TypeManager.short_type)
532 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
533 if (target_type == TypeManager.decimal_type)
534 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
535 } else if (expr_type == TypeManager.byte_type){
537 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
539 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type ||
540 target_type == TypeManager.short_type || target_type == TypeManager.ushort_type)
541 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
543 if (target_type == TypeManager.uint64_type)
544 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
545 if (target_type == TypeManager.int64_type)
546 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
547 if (target_type == TypeManager.float_type)
548 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
549 if (target_type == TypeManager.double_type)
550 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
551 if (target_type == TypeManager.decimal_type)
552 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
554 } else if (expr_type == TypeManager.short_type){
556 // From short to int, long, float, double, decimal
558 if (target_type == TypeManager.int32_type)
559 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
560 if (target_type == TypeManager.int64_type)
561 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
562 if (target_type == TypeManager.double_type)
563 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
564 if (target_type == TypeManager.float_type)
565 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
566 if (target_type == TypeManager.decimal_type)
567 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
569 } else if (expr_type == TypeManager.ushort_type){
571 // From ushort to int, uint, long, ulong, float, double, decimal
573 if (target_type == TypeManager.int32_type || target_type == TypeManager.uint32_type)
574 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
576 if (target_type == TypeManager.uint64_type)
577 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
578 if (target_type == TypeManager.int64_type)
579 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
580 if (target_type == TypeManager.double_type)
581 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
582 if (target_type == TypeManager.float_type)
583 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
584 if (target_type == TypeManager.decimal_type)
585 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
586 } else if (expr_type == TypeManager.int32_type){
588 // From int to long, float, double, decimal
590 if (target_type == TypeManager.int64_type)
591 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
592 if (target_type == TypeManager.double_type)
593 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
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.decimal_type)
597 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
598 } else if (expr_type == TypeManager.uint32_type){
600 // From uint to long, ulong, float, double, decimal
602 if (target_type == TypeManager.int64_type)
603 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
604 if (target_type == TypeManager.uint64_type)
605 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
606 if (target_type == TypeManager.double_type)
607 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
608 if (target_type == TypeManager.float_type)
609 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
610 if (target_type == TypeManager.decimal_type)
611 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
612 } else if (expr_type == TypeManager.int64_type){
614 // From long/ulong to float, double
616 if (target_type == TypeManager.double_type)
617 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
618 if (target_type == TypeManager.float_type)
619 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
620 if (target_type == TypeManager.decimal_type)
621 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
622 } else if (expr_type == TypeManager.uint64_type){
624 // From ulong to float, double
626 if (target_type == TypeManager.double_type)
627 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R8);
628 if (target_type == TypeManager.float_type)
629 return expr == null ? EmptyExpression.Null : new OpcodeCast (new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un), target_type, OpCodes.Conv_R4);
630 if (target_type == TypeManager.decimal_type)
631 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
632 } else if (expr_type == TypeManager.char_type){
634 // From char to ushort, int, uint, long, ulong, float, double, decimal
636 if ((target_type == TypeManager.ushort_type) ||
637 (target_type == TypeManager.int32_type) ||
638 (target_type == TypeManager.uint32_type))
639 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type);
640 if (target_type == TypeManager.uint64_type)
641 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
642 if (target_type == TypeManager.int64_type)
643 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
644 if (target_type == TypeManager.float_type)
645 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
646 if (target_type == TypeManager.double_type)
647 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
648 if (target_type == TypeManager.decimal_type)
649 return expr == null ? EmptyExpression.Null : new CastToDecimal (expr);
650 } else if (expr_type == TypeManager.float_type){
652 // float to double
654 if (target_type == TypeManager.double_type)
655 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
658 return null;
661 /// <summary>
662 /// Same as ImplicitStandardConversionExists except that it also looks at
663 /// implicit user defined conversions - needed for overload resolution
664 /// </summary>
665 public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, Type target_type)
667 if (ImplicitStandardConversionExists (expr, target_type))
668 return true;
670 if (expr.Type == InternalType.AnonymousMethod) {
671 if (!TypeManager.IsDelegateType (target_type) &&
672 TypeManager.DropGenericTypeArguments (target_type) != TypeManager.expression_type)
673 return false;
675 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
676 return ame.ImplicitStandardConversionExists (ec, target_type);
679 if (expr.eclass == ExprClass.MethodGroup) {
680 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1) {
681 MethodGroupExpr mg = expr as MethodGroupExpr;
682 if (mg != null)
683 return DelegateCreation.ImplicitStandardConversionExists (ec, mg, target_type);
686 return false;
689 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
692 public static bool ImplicitUserConversionExists (ResolveContext ec, Type source, Type target)
694 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
697 /// <summary>
698 /// Determines if a standard implicit conversion exists from
699 /// expr_type to target_type
701 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
702 /// </summary>
703 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
705 Type expr_type = expr.Type;
707 if (expr_type == TypeManager.null_type) {
708 NullLiteral nl = expr as NullLiteral;
709 if (nl != null)
710 return nl.ConvertImplicitly (target_type) != null;
713 if (expr_type == TypeManager.void_type)
714 return false;
716 if (TypeManager.IsEqual (expr_type, target_type))
717 return true;
719 if (TypeManager.IsNullableType (target_type)) {
720 return ImplicitNulableConversion (null, expr, target_type) != null;
723 // First numeric conversions
724 if (ImplicitNumericConversion (null, expr_type, target_type) != null)
725 return true;
727 if (ImplicitReferenceConversionExists (expr, target_type))
728 return true;
730 bool use_class_cast;
731 if (ImplicitBoxingConversionExists (expr, target_type, out use_class_cast))
732 return true;
735 // Implicit Constant Expression Conversions
737 if (expr is IntConstant){
738 int value = ((IntConstant) expr).Value;
740 if (target_type == TypeManager.sbyte_type){
741 if (value >= SByte.MinValue && value <= SByte.MaxValue)
742 return true;
743 } else if (target_type == TypeManager.byte_type){
744 if (value >= 0 && value <= Byte.MaxValue)
745 return true;
746 } else if (target_type == TypeManager.short_type){
747 if (value >= Int16.MinValue && value <= Int16.MaxValue)
748 return true;
749 } else if (target_type == TypeManager.ushort_type){
750 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
751 return true;
752 } else if (target_type == TypeManager.uint32_type){
753 if (value >= 0)
754 return true;
755 } else if (target_type == TypeManager.uint64_type){
757 // we can optimize this case: a positive int32
758 // always fits on a uint64. But we need an opcode
759 // to do it.
761 if (value >= 0)
762 return true;
765 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
766 return true;
769 if (expr is LongConstant && target_type == TypeManager.uint64_type){
771 // Try the implicit constant expression conversion
772 // from long to ulong, instead of a nice routine,
773 // we just inline it
775 long v = ((LongConstant) expr).Value;
776 if (v >= 0)
777 return true;
781 // If `expr_type' implements `target_type' (which is an iface)
782 // see TryImplicitIntConversion
784 if (target_type.IsInterface && TypeManager.ImplementsInterface (expr_type, target_type))
785 return true;
787 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
788 return true;
790 // Conversion from __arglist to System.ArgIterator
791 if (expr_type == InternalType.Arglist)
792 return target_type == TypeManager.arg_iterator_type;
794 return false;
797 /// <summary>
798 /// Finds "most encompassed type" according to the spec (13.4.2)
799 /// amongst the methods in the MethodGroupExpr
800 /// </summary>
801 static Type FindMostEncompassedType (ArrayList types)
803 Type best = null;
805 if (types.Count == 0)
806 return null;
808 if (types.Count == 1)
809 return (Type) types [0];
811 EmptyExpression expr = EmptyExpression.Grab ();
813 foreach (Type t in types) {
814 if (best == null) {
815 best = t;
816 continue;
819 expr.SetType (t);
820 if (ImplicitStandardConversionExists (expr, best))
821 best = t;
824 expr.SetType (best);
825 foreach (Type t in types) {
826 if (best == t)
827 continue;
828 if (!ImplicitStandardConversionExists (expr, t)) {
829 best = null;
830 break;
834 EmptyExpression.Release (expr);
836 return best;
839 /// <summary>
840 /// Finds "most encompassing type" according to the spec (13.4.2)
841 /// amongst the types in the given set
842 /// </summary>
843 static Type FindMostEncompassingType (ArrayList types)
845 Type best = null;
847 if (types.Count == 0)
848 return null;
850 if (types.Count == 1)
851 return (Type) types [0];
853 EmptyExpression expr = EmptyExpression.Grab ();
855 foreach (Type t in types) {
856 if (best == null) {
857 best = t;
858 continue;
861 expr.SetType (best);
862 if (ImplicitStandardConversionExists (expr, t))
863 best = t;
866 foreach (Type t in types) {
867 if (best == t)
868 continue;
869 expr.SetType (t);
870 if (!ImplicitStandardConversionExists (expr, best)) {
871 best = null;
872 break;
876 EmptyExpression.Release (expr);
878 return best;
881 /// <summary>
882 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
883 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
884 /// for explicit and implicit conversion operators.
885 /// </summary>
886 static public Type FindMostSpecificSource (IList list,
887 Expression source, bool apply_explicit_conv_rules)
889 ArrayList src_types_set = new ArrayList ();
892 // If any operator converts from S then Sx = S
894 Type source_type = source.Type;
895 foreach (MethodBase mb in list){
896 AParametersCollection pd = TypeManager.GetParameterData (mb);
897 Type param_type = pd.Types [0];
899 if (param_type == source_type)
900 return param_type;
902 src_types_set.Add (param_type);
906 // Explicit Conv rules
908 if (apply_explicit_conv_rules) {
909 ArrayList candidate_set = new ArrayList ();
911 foreach (Type param_type in src_types_set){
912 if (ImplicitStandardConversionExists (source, param_type))
913 candidate_set.Add (param_type);
916 if (candidate_set.Count != 0)
917 return FindMostEncompassedType (candidate_set);
921 // Final case
923 if (apply_explicit_conv_rules)
924 return FindMostEncompassingType (src_types_set);
925 else
926 return FindMostEncompassedType (src_types_set);
929 /// <summary>
930 /// Finds the most specific target Tx according to section 13.4.4
931 /// </summary>
932 static public Type FindMostSpecificTarget (IList list,
933 Type target, bool apply_explicit_conv_rules)
935 ArrayList tgt_types_set = new ArrayList ();
938 // If any operator converts to T then Tx = T
940 foreach (MethodInfo mi in list){
941 Type ret_type = TypeManager.TypeToCoreType (mi.ReturnType);
942 if (ret_type == target)
943 return ret_type;
945 tgt_types_set.Add (ret_type);
949 // Explicit conv rules
951 if (apply_explicit_conv_rules) {
952 ArrayList candidate_set = new ArrayList ();
954 EmptyExpression expr = EmptyExpression.Grab ();
956 foreach (Type ret_type in tgt_types_set){
957 expr.SetType (ret_type);
959 if (ImplicitStandardConversionExists (expr, target))
960 candidate_set.Add (ret_type);
963 EmptyExpression.Release (expr);
965 if (candidate_set.Count != 0)
966 return FindMostEncompassingType (candidate_set);
970 // Okay, final case !
972 if (apply_explicit_conv_rules)
973 return FindMostEncompassedType (tgt_types_set);
974 else
975 return FindMostEncompassingType (tgt_types_set);
978 /// <summary>
979 /// User-defined Implicit conversions
980 /// </summary>
981 static public Expression ImplicitUserConversion (ResolveContext ec, Expression source,
982 Type target, Location loc)
984 return UserDefinedConversion (ec, source, target, loc, false, true);
987 /// <summary>
988 /// User-defined Explicit conversions
989 /// </summary>
990 static public Expression ExplicitUserConversion (ResolveContext ec, Expression source,
991 Type target, Location loc)
993 return UserDefinedConversion (ec, source, target, loc, true, true);
996 static void AddConversionOperators (ArrayList list,
997 Expression source, Type target_type,
998 bool look_for_explicit,
999 MethodGroupExpr mg)
1001 if (mg == null)
1002 return;
1004 Type source_type = source.Type;
1005 EmptyExpression expr = EmptyExpression.Grab ();
1008 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions
1009 // IntPtr -> uint uses int
1010 // UIntPtr -> long uses ulong
1012 if (source_type == TypeManager.intptr_type) {
1013 if (target_type == TypeManager.uint32_type)
1014 target_type = TypeManager.int32_type;
1015 } else if (source_type == TypeManager.uintptr_type) {
1016 if (target_type == TypeManager.int64_type)
1017 target_type = TypeManager.uint64_type;
1020 foreach (MethodInfo m in mg.Methods) {
1021 AParametersCollection pd = TypeManager.GetParameterData (m);
1022 Type return_type = TypeManager.TypeToCoreType (m.ReturnType);
1023 Type arg_type = pd.Types [0];
1025 if (source_type != arg_type) {
1026 if (!ImplicitStandardConversionExists (source, arg_type)) {
1027 if (!look_for_explicit)
1028 continue;
1029 expr.SetType (arg_type);
1030 if (!ImplicitStandardConversionExists (expr, source_type))
1031 continue;
1035 if (target_type != return_type) {
1036 expr.SetType (return_type);
1037 if (!ImplicitStandardConversionExists (expr, target_type)) {
1038 if (!look_for_explicit)
1039 continue;
1040 expr.SetType (target_type);
1041 if (!ImplicitStandardConversionExists (expr, return_type))
1042 continue;
1046 // See LAMESPEC: Exclude IntPtr -> int conversion
1047 if (source_type == TypeManager.uintptr_type && return_type == TypeManager.uint32_type)
1048 continue;
1050 list.Add (m);
1053 EmptyExpression.Release (expr);
1056 /// <summary>
1057 /// Compute the user-defined conversion operator from source_type to target_type.
1058 /// `look_for_explicit' controls whether we should also include the list of explicit operators
1059 /// </summary>
1060 static MethodInfo GetConversionOperator (CompilerContext ctx, Type container_type, Expression source, Type target_type, bool look_for_explicit)
1062 ArrayList ops = new ArrayList (4);
1064 Type source_type = source.Type;
1066 if (source_type != TypeManager.decimal_type) {
1067 AddConversionOperators (ops, source, target_type, look_for_explicit,
1068 Expression.MethodLookup (ctx, container_type, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1069 if (look_for_explicit) {
1070 AddConversionOperators (ops, source, target_type, look_for_explicit,
1071 Expression.MethodLookup (ctx,
1072 container_type, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1076 if (target_type != TypeManager.decimal_type) {
1077 AddConversionOperators (ops, source, target_type, look_for_explicit,
1078 Expression.MethodLookup (ctx, container_type, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1079 if (look_for_explicit) {
1080 AddConversionOperators (ops, source, target_type, look_for_explicit,
1081 Expression.MethodLookup (ctx,
1082 container_type, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1086 if (ops.Count == 0)
1087 return null;
1089 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
1090 if (most_specific_source == null)
1091 return null;
1093 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
1094 if (most_specific_target == null)
1095 return null;
1097 MethodInfo method = null;
1099 foreach (MethodInfo m in ops) {
1100 if (TypeManager.TypeToCoreType (m.ReturnType) != most_specific_target)
1101 continue;
1102 if (TypeManager.GetParameterData (m).Types [0] != most_specific_source)
1103 continue;
1104 // Ambiguous: more than one conversion operator satisfies the signature.
1105 if (method != null)
1106 return null;
1107 method = m;
1110 return method;
1113 /// <summary>
1114 /// User-defined conversions
1115 /// </summary>
1116 public static Expression UserDefinedConversion (ResolveContext ec, Expression source,
1117 Type target, Location loc,
1118 bool look_for_explicit, bool return_convert)
1120 Type source_type = source.Type;
1121 MethodInfo method = null;
1122 Expression expr = null;
1124 object o;
1125 DoubleHash hash;
1126 if (look_for_explicit) {
1127 hash = explicit_conv;
1128 } else {
1129 // Implicit user operators cannot convert to interfaces
1130 if (target.IsInterface)
1131 return null;
1133 hash = implicit_conv;
1136 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1137 method = (MethodInfo) o;
1138 } else {
1139 if (TypeManager.IsDynamicType (source_type))
1140 return null;
1142 method = GetConversionOperator (RootContext.ToplevelTypes.Compiler, null, source, target, look_for_explicit);
1145 if (method != null) {
1146 Type most_specific_source = TypeManager.GetParameterData (method).Types[0];
1149 // This will do the conversion to the best match that we
1150 // found. Now we need to perform an implict standard conversion
1151 // if the best match was not the type that we were requested
1152 // by target.
1154 if (look_for_explicit) {
1155 ReportPrinter temp = new SessionReportPrinter ();
1156 ReportPrinter prev = ec.Report.SetPrinter (temp);
1158 expr = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1160 ec.Report.SetPrinter (prev);
1161 if (temp.ErrorsCount != 0)
1162 expr = null;
1163 } else {
1164 if (ImplicitStandardConversionExists (source, most_specific_source))
1165 expr = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1166 else
1167 expr = null;
1171 if (expr == null) {
1172 bool nullable = false;
1174 if (TypeManager.IsNullableType (source_type)) {
1175 source = Nullable.Unwrap.Create (source);
1176 nullable = true;
1179 Type target_underlying;
1180 if (TypeManager.IsNullableType (target)) {
1181 target_underlying = TypeManager.GetTypeArguments (target)[0];
1182 nullable = true;
1183 } else {
1184 // No implicit conversion S? -> T for non-reference type T
1185 if (!look_for_explicit && !TypeManager.IsReferenceType (target))
1186 nullable = false;
1188 target_underlying = target;
1191 if (nullable) {
1192 expr = UserDefinedConversion (ec, source, target_underlying, loc, look_for_explicit, return_convert);
1194 // Do result expression lifting only when it's needed
1195 if (expr != null && (!look_for_explicit || TypeManager.IsReferenceType (target)))
1196 expr = new Nullable.Lifted (expr, source, target).Resolve (ec);
1198 return expr;
1200 } else {
1201 expr = new UserCast (method, expr, loc).DoResolve (ec);
1203 if (return_convert && !TypeManager.IsEqual (expr.Type, target)) {
1204 if (look_for_explicit) {
1205 expr = ExplicitConversionStandard (ec, expr, target, loc);
1206 } else {
1207 expr = ImplicitConversionStandard (ec, expr, target, loc);
1212 if (!(source is Constant))
1213 hash.Insert (source_type, target, method);
1215 return expr;
1218 /// <summary>
1219 /// Converts implicitly the resolved expression `expr' into the
1220 /// `target_type'. It returns a new expression that can be used
1221 /// in a context that expects a `target_type'.
1222 /// </summary>
1223 static public Expression ImplicitConversion (ResolveContext ec, Expression expr,
1224 Type target_type, Location loc)
1226 Expression e;
1228 if (target_type == null)
1229 throw new Exception ("Target type is null");
1231 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1232 if (e != null)
1233 return e;
1235 e = ImplicitUserConversion (ec, expr, target_type, loc);
1236 if (e != null)
1237 return e;
1239 return null;
1243 /// <summary>
1244 /// Attempts to apply the `Standard Implicit
1245 /// Conversion' rules to the expression `expr' into
1246 /// the `target_type'. It returns a new expression
1247 /// that can be used in a context that expects a
1248 /// `target_type'.
1250 /// This is different from `ImplicitConversion' in that the
1251 /// user defined implicit conversions are excluded.
1252 /// </summary>
1253 static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr,
1254 Type target_type, Location loc)
1256 return ImplicitConversionStandard (ec, expr, target_type, loc, false);
1259 static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, Type target_type, Location loc, bool explicit_cast)
1261 if (expr.eclass == ExprClass.MethodGroup){
1262 if (!TypeManager.IsDelegateType (target_type)){
1263 return null;
1267 // Only allow anonymous method conversions on post ISO_1
1269 if (RootContext.Version != LanguageVersion.ISO_1){
1270 MethodGroupExpr mg = expr as MethodGroupExpr;
1271 if (mg != null)
1272 return ImplicitDelegateCreation.Create (
1273 ec, mg, target_type, loc);
1277 Type expr_type = expr.Type;
1278 Expression e;
1280 if (expr_type.Equals (target_type)) {
1281 if (expr_type != TypeManager.null_type && expr_type != InternalType.AnonymousMethod)
1282 return expr;
1283 return null;
1286 if (TypeManager.IsVariantOf (expr_type, target_type)) {
1287 return expr;
1290 if (TypeManager.IsNullableType (target_type))
1291 return ImplicitNulableConversion (ec, expr, target_type);
1294 // Attempt to do the implicit constant expression conversions
1296 Constant c = expr as Constant;
1297 if (c != null) {
1298 try {
1299 c = c.ConvertImplicitly (target_type);
1300 } catch {
1301 Console.WriteLine ("Conversion error happened in line {0}", loc);
1302 throw;
1304 if (c != null)
1305 return c;
1308 e = ImplicitNumericConversion (expr, expr_type, target_type);
1309 if (e != null)
1310 return e;
1312 e = ImplicitReferenceConversion (expr, target_type, explicit_cast);
1313 if (e != null)
1314 return e;
1316 if (expr is IntConstant && TypeManager.IsEnumType (target_type)){
1317 Constant i = (Constant) expr;
1319 // LAMESPEC: Conversion from any 0 constant is allowed
1321 // An implicit enumeration conversion permits the decimal-integer-literal 0
1322 // to be converted to any enum-type and to any nullable-type whose underlying
1323 // type is an enum-type
1325 if (i.IsDefaultValue)
1326 return new EnumConstant (i, target_type);
1329 if (ec.IsUnsafe) {
1330 if (expr_type.IsPointer){
1331 if (target_type == TypeManager.void_ptr_type)
1332 return EmptyCast.Create (expr, target_type);
1335 // yep, comparing pointer types cant be done with
1336 // t1 == t2, we have to compare their element types.
1338 if (target_type.IsPointer){
1339 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1340 return expr;
1342 //return null;
1346 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1347 return EmptyCast.Create (new NullPointer (loc), target_type);
1350 if (expr_type == InternalType.AnonymousMethod){
1351 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
1352 Expression am = ame.Compatible (ec, target_type);
1353 if (am != null)
1354 return am.DoResolve (ec);
1357 if (expr_type == InternalType.Arglist && target_type == TypeManager.arg_iterator_type)
1358 return expr;
1360 return null;
1363 /// <summary>
1364 /// Attempts to implicitly convert `source' into `target_type', using
1365 /// ImplicitConversion. If there is no implicit conversion, then
1366 /// an error is signaled
1367 /// </summary>
1368 static public Expression ImplicitConversionRequired (ResolveContext ec, Expression source,
1369 Type target_type, Location loc)
1371 Expression e = ImplicitConversion (ec, source, target_type, loc);
1372 if (e != null)
1373 return e;
1375 source.Error_ValueCannotBeConverted (ec, loc, target_type, false);
1376 return null;
1379 /// <summary>
1380 /// Performs the explicit numeric conversions
1382 /// There are a few conversions that are not part of the C# standard,
1383 /// they were interim hacks in the C# compiler that were supposed to
1384 /// become explicit operators in the UIntPtr class and IntPtr class,
1385 /// but for historical reasons it did not happen, so the C# compiler
1386 /// ended up with these special hacks.
1388 /// See bug 59800 for details.
1390 /// The conversion are:
1391 /// UIntPtr->SByte
1392 /// UIntPtr->Int16
1393 /// UIntPtr->Int32
1394 /// IntPtr->UInt64
1395 /// UInt64->IntPtr
1396 /// SByte->UIntPtr
1397 /// Int16->UIntPtr
1399 /// </summary>
1400 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1402 Type expr_type = expr.Type;
1403 Type real_target_type = target_type;
1405 if (expr_type == TypeManager.sbyte_type){
1407 // From sbyte to byte, ushort, uint, ulong, char, uintptr
1409 if (real_target_type == TypeManager.byte_type)
1410 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1411 if (real_target_type == TypeManager.ushort_type)
1412 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1413 if (real_target_type == TypeManager.uint32_type)
1414 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1415 if (real_target_type == TypeManager.uint64_type)
1416 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1417 if (real_target_type == TypeManager.char_type)
1418 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1420 // One of the built-in conversions that belonged in the class library
1421 if (real_target_type == TypeManager.uintptr_type){
1422 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I1_U8);
1424 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1426 } else if (expr_type == TypeManager.byte_type){
1428 // From byte to sbyte and char
1430 if (real_target_type == TypeManager.sbyte_type)
1431 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1432 if (real_target_type == TypeManager.char_type)
1433 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1434 } else if (expr_type == TypeManager.short_type){
1436 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr
1438 if (real_target_type == TypeManager.sbyte_type)
1439 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1440 if (real_target_type == TypeManager.byte_type)
1441 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1442 if (real_target_type == TypeManager.ushort_type)
1443 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1444 if (real_target_type == TypeManager.uint32_type)
1445 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1446 if (real_target_type == TypeManager.uint64_type)
1447 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1448 if (real_target_type == TypeManager.char_type)
1449 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1451 // One of the built-in conversions that belonged in the class library
1452 if (real_target_type == TypeManager.uintptr_type){
1453 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1455 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1457 } else if (expr_type == TypeManager.ushort_type){
1459 // From ushort to sbyte, byte, short, char
1461 if (real_target_type == TypeManager.sbyte_type)
1462 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1463 if (real_target_type == TypeManager.byte_type)
1464 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1465 if (real_target_type == TypeManager.short_type)
1466 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1467 if (real_target_type == TypeManager.char_type)
1468 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1469 } else if (expr_type == TypeManager.int32_type){
1471 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr
1473 if (real_target_type == TypeManager.sbyte_type)
1474 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1475 if (real_target_type == TypeManager.byte_type)
1476 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1477 if (real_target_type == TypeManager.short_type)
1478 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1479 if (real_target_type == TypeManager.ushort_type)
1480 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1481 if (real_target_type == TypeManager.uint32_type)
1482 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1483 if (real_target_type == TypeManager.uint64_type)
1484 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1485 if (real_target_type == TypeManager.char_type)
1486 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1488 // One of the built-in conversions that belonged in the class library
1489 if (real_target_type == TypeManager.uintptr_type){
1490 Expression u8e = new ConvCast (expr, TypeManager.uint64_type, ConvCast.Mode.I2_U8);
1492 return new OperatorCast (u8e, TypeManager.uintptr_type, true);
1494 } else if (expr_type == TypeManager.uint32_type){
1496 // From uint to sbyte, byte, short, ushort, int, char
1498 if (real_target_type == TypeManager.sbyte_type)
1499 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1500 if (real_target_type == TypeManager.byte_type)
1501 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1502 if (real_target_type == TypeManager.short_type)
1503 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1504 if (real_target_type == TypeManager.ushort_type)
1505 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1506 if (real_target_type == TypeManager.int32_type)
1507 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1508 if (real_target_type == TypeManager.char_type)
1509 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1510 } else if (expr_type == TypeManager.int64_type){
1512 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1514 if (real_target_type == TypeManager.sbyte_type)
1515 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1516 if (real_target_type == TypeManager.byte_type)
1517 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1518 if (real_target_type == TypeManager.short_type)
1519 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1520 if (real_target_type == TypeManager.ushort_type)
1521 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1522 if (real_target_type == TypeManager.int32_type)
1523 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1524 if (real_target_type == TypeManager.uint32_type)
1525 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1526 if (real_target_type == TypeManager.uint64_type)
1527 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1528 if (real_target_type == TypeManager.char_type)
1529 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1530 } else if (expr_type == TypeManager.uint64_type){
1532 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1534 if (real_target_type == TypeManager.sbyte_type)
1535 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1536 if (real_target_type == TypeManager.byte_type)
1537 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1538 if (real_target_type == TypeManager.short_type)
1539 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1540 if (real_target_type == TypeManager.ushort_type)
1541 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1542 if (real_target_type == TypeManager.int32_type)
1543 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1544 if (real_target_type == TypeManager.uint32_type)
1545 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1546 if (real_target_type == TypeManager.int64_type)
1547 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1548 if (real_target_type == TypeManager.char_type)
1549 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1551 // One of the built-in conversions that belonged in the class library
1552 if (real_target_type == TypeManager.intptr_type){
1553 return new OperatorCast (EmptyCast.Create (expr, TypeManager.int64_type),
1554 TypeManager.intptr_type, true);
1556 } else if (expr_type == TypeManager.char_type){
1558 // From char to sbyte, byte, short
1560 if (real_target_type == TypeManager.sbyte_type)
1561 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1562 if (real_target_type == TypeManager.byte_type)
1563 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1564 if (real_target_type == TypeManager.short_type)
1565 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1566 } else if (expr_type == TypeManager.float_type){
1568 // From float to sbyte, byte, short,
1569 // ushort, int, uint, long, ulong, char
1570 // or decimal
1572 if (real_target_type == TypeManager.sbyte_type)
1573 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1574 if (real_target_type == TypeManager.byte_type)
1575 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1576 if (real_target_type == TypeManager.short_type)
1577 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1578 if (real_target_type == TypeManager.ushort_type)
1579 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1580 if (real_target_type == TypeManager.int32_type)
1581 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1582 if (real_target_type == TypeManager.uint32_type)
1583 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1584 if (real_target_type == TypeManager.int64_type)
1585 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1586 if (real_target_type == TypeManager.uint64_type)
1587 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1588 if (real_target_type == TypeManager.char_type)
1589 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1590 if (real_target_type == TypeManager.decimal_type)
1591 return new CastToDecimal (expr, true);
1592 } else if (expr_type == TypeManager.double_type){
1594 // From double to sbyte, byte, short,
1595 // ushort, int, uint, long, ulong,
1596 // char, float or decimal
1598 if (real_target_type == TypeManager.sbyte_type)
1599 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1600 if (real_target_type == TypeManager.byte_type)
1601 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1602 if (real_target_type == TypeManager.short_type)
1603 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1604 if (real_target_type == TypeManager.ushort_type)
1605 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1606 if (real_target_type == TypeManager.int32_type)
1607 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1608 if (real_target_type == TypeManager.uint32_type)
1609 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1610 if (real_target_type == TypeManager.int64_type)
1611 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1612 if (real_target_type == TypeManager.uint64_type)
1613 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1614 if (real_target_type == TypeManager.char_type)
1615 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1616 if (real_target_type == TypeManager.float_type)
1617 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1618 if (real_target_type == TypeManager.decimal_type)
1619 return new CastToDecimal (expr, true);
1620 } else if (expr_type == TypeManager.uintptr_type){
1622 // Various built-in conversions that belonged in the class library
1624 // from uintptr to sbyte, short, int32
1626 if (real_target_type == TypeManager.sbyte_type){
1627 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1628 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I1);
1630 if (real_target_type == TypeManager.short_type){
1631 Expression uint32e = new OperatorCast (expr, TypeManager.uint32_type, true);
1632 return new ConvCast (uint32e, TypeManager.sbyte_type, ConvCast.Mode.U4_I2);
1634 if (real_target_type == TypeManager.int32_type){
1635 return EmptyCast.Create (new OperatorCast (expr, TypeManager.uint32_type, true),
1636 TypeManager.int32_type);
1638 } else if (expr_type == TypeManager.intptr_type){
1639 if (real_target_type == TypeManager.uint64_type){
1640 return EmptyCast.Create (new OperatorCast (expr, TypeManager.int64_type, true),
1641 TypeManager.uint64_type);
1643 } else if (expr_type == TypeManager.decimal_type) {
1644 return new CastFromDecimal (expr, target_type).Resolve ();
1646 return null;
1649 /// <summary>
1650 /// Returns whether an explicit reference conversion can be performed
1651 /// from source_type to target_type
1652 /// </summary>
1653 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1655 Expression e = ExplicitReferenceConversion (null, source_type, target_type);
1656 if (e == null)
1657 return false;
1659 if (e == EmptyExpression.Null)
1660 return true;
1662 throw new InternalErrorException ("Invalid probing conversion result");
1665 /// <summary>
1666 /// Implements Explicit Reference conversions
1667 /// </summary>
1668 static Expression ExplicitReferenceConversion (Expression source, Type source_type, Type target_type)
1670 bool target_is_value_type = TypeManager.IsStruct (target_type);
1673 // From object to a generic parameter
1675 if (source_type == TypeManager.object_type && TypeManager.IsGenericParameter (target_type))
1676 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1679 // Explicit type parameter conversion.
1681 if (TypeManager.IsGenericParameter (source_type))
1682 return ExplicitTypeParameterConversion (source, source_type, target_type);
1685 // From object to any reference type or value type (unboxing)
1687 if (source_type == TypeManager.object_type)
1688 return source == null ? EmptyExpression.Null :
1689 target_is_value_type ? (Expression) new UnboxCast (source, target_type) : new ClassCast (source, target_type);
1692 // Unboxing conversion from the types object and System.ValueType to any non-nullable-value-type
1694 if (source_type == TypeManager.value_type && target_is_value_type)
1695 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1698 // From any class S to any class-type T, provided S is a base class of T
1700 if (TypeManager.IsSubclassOf (target_type, source_type))
1701 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1704 // From any class type S to any interface T, provides S is not sealed
1705 // and provided S does not implement T.
1707 if (target_type.IsInterface && !source_type.IsSealed &&
1708 !TypeManager.ImplementsInterface (source_type, target_type)) {
1709 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1713 // From any interface-type S to to any class type T, provided T is not
1714 // sealed, or provided T implements S.
1716 if (source_type.IsInterface) {
1717 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1718 if (target_type.IsClass)
1719 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1722 // Unboxing conversion from any interface-type to any non-nullable-value-type that
1723 // implements the interface-type
1725 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type);
1729 // From System.Collecitons.Generic.IList<T> and its base interfaces to a one-dimensional
1730 // array type S[], provided there is an implicit or explicit reference conversion from S to T.
1732 if (IList_To_Array (source_type, target_type))
1733 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1735 return null;
1738 if (source_type.IsArray) {
1739 if (target_type.IsArray) {
1741 // From System.Array to any array-type
1743 if (source_type == TypeManager.array_type)
1744 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1747 // From an array type S with an element type Se to an array type T with an
1748 // element type Te provided all the following are true:
1749 // * S and T differe only in element type, in other words, S and T
1750 // have the same number of dimensions.
1751 // * Both Se and Te are reference types
1752 // * An explicit reference conversions exist from Se to Te
1754 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1756 source_type = TypeManager.GetElementType (source_type);
1757 if (!TypeManager.IsReferenceType (source_type))
1758 return null;
1760 Type target_type_element = TypeManager.GetElementType (target_type);
1761 if (!TypeManager.IsReferenceType (target_type_element))
1762 return null;
1764 if (ExplicitReferenceConversionExists (source_type, target_type_element))
1765 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1767 return null;
1772 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces,
1773 // provided that there is an explicit reference conversion from S to T
1775 if (Array_To_IList (source_type, target_type, true))
1776 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1778 return null;
1782 // From System delegate to any delegate-type
1784 if (source_type == TypeManager.delegate_type && TypeManager.IsDelegateType (target_type))
1785 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
1787 return null;
1790 /// <summary>
1791 /// Performs an explicit conversion of the expression `expr' whose
1792 /// type is expr.Type to `target_type'.
1793 /// </summary>
1794 static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr,
1795 Type target_type, Location loc)
1797 Type expr_type = expr.Type;
1799 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1800 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true);
1801 if (ne != null)
1802 return ne;
1804 if (TypeManager.IsEnumType (expr_type)) {
1805 Expression underlying = EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type));
1806 expr = ExplicitConversionCore (ec, underlying, target_type, loc);
1807 if (expr != null)
1808 return expr;
1810 return ExplicitUserConversion (ec, underlying, target_type, loc);
1813 if (TypeManager.IsEnumType (target_type)){
1815 // Type System.Enum can be unboxed to any enum-type
1817 if (expr_type == TypeManager.enum_type)
1818 return new UnboxCast (expr, target_type);
1820 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1821 if (ce != null)
1822 return EmptyCast.Create (ce, target_type);
1825 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed
1827 if (expr_type == TypeManager.intptr_type || expr_type == TypeManager.uintptr_type) {
1828 ne = ExplicitUserConversion (ec, expr, TypeManager.GetEnumUnderlyingType (target_type), loc);
1829 if (ne != null)
1830 return ExplicitConversionCore (ec, ne, target_type, loc);
1833 return null;
1836 ne = ExplicitNumericConversion (expr, target_type);
1837 if (ne != null)
1838 return ne;
1841 // Skip the ExplicitReferenceConversion because we can not convert
1842 // from Null to a ValueType, and ExplicitReference wont check against
1843 // null literal explicitly
1845 if (expr_type != TypeManager.null_type){
1846 ne = ExplicitReferenceConversion (expr, expr_type, target_type);
1847 if (ne != null)
1848 return ne;
1851 if (ec.IsUnsafe){
1852 ne = ExplicitUnsafe (expr, target_type);
1853 if (ne != null)
1854 return ne;
1857 return null;
1860 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1862 Type expr_type = expr.Type;
1864 if (target_type.IsPointer){
1865 if (expr_type.IsPointer)
1866 return EmptyCast.Create (expr, target_type);
1868 if (expr_type == TypeManager.sbyte_type ||
1869 expr_type == TypeManager.short_type ||
1870 expr_type == TypeManager.int32_type)
1871 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1873 if (expr_type == TypeManager.ushort_type ||
1874 expr_type == TypeManager.uint32_type ||
1875 expr_type == TypeManager.byte_type)
1876 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1878 if (expr_type == TypeManager.int64_type)
1879 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I);
1881 if (expr_type == TypeManager.uint64_type)
1882 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I);
1885 if (expr_type.IsPointer){
1886 if (target_type == TypeManager.sbyte_type)
1887 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1888 if (target_type == TypeManager.byte_type)
1889 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1890 if (target_type == TypeManager.short_type)
1891 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1892 if (target_type == TypeManager.ushort_type)
1893 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1894 if (target_type == TypeManager.int32_type)
1895 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1896 if (target_type == TypeManager.uint32_type)
1897 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1898 if (target_type == TypeManager.int64_type)
1899 return new ConvCast (expr, target_type, ConvCast.Mode.I_I8);
1900 if (target_type == TypeManager.uint64_type)
1901 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1903 return null;
1906 /// <summary>
1907 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1908 /// </summary>
1909 static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr,
1910 Type target_type, Location l)
1912 int errors = ec.Report.Errors;
1913 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1914 if (ec.Report.Errors > errors)
1915 return null;
1917 if (ne != null)
1918 return ne;
1920 ne = ExplicitNumericConversion (expr, target_type);
1921 if (ne != null)
1922 return ne;
1924 ne = ExplicitReferenceConversion (expr, expr.Type, target_type);
1925 if (ne != null)
1926 return ne;
1928 if (ec.IsUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1929 return EmptyCast.Create (expr, target_type);
1931 expr.Error_ValueCannotBeConverted (ec, l, target_type, true);
1932 return null;
1935 /// <summary>
1936 /// Performs an explicit conversion of the expression `expr' whose
1937 /// type is expr.Type to `target_type'.
1938 /// </summary>
1939 static public Expression ExplicitConversion (ResolveContext ec, Expression expr,
1940 Type target_type, Location loc)
1942 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1943 if (e != null) {
1945 // Don't eliminate explicit precission casts
1947 if (e == expr) {
1948 if (target_type == TypeManager.float_type)
1949 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
1951 if (target_type == TypeManager.double_type)
1952 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
1955 return e;
1958 Type expr_type = expr.Type;
1959 if (TypeManager.IsNullableType (target_type)) {
1960 if (TypeManager.IsNullableType (expr_type)) {
1961 Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type)[0]);
1962 Expression unwrap = Nullable.Unwrap.Create (expr);
1963 e = ExplicitConversion (ec, unwrap, target, expr.Location);
1964 if (e == null)
1965 return null;
1967 return new Nullable.Lifted (e, unwrap, target_type).Resolve (ec);
1968 } else if (expr_type == TypeManager.object_type) {
1969 return new UnboxCast (expr, target_type);
1970 } else {
1971 Type target = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (target_type) [0]);
1973 e = ExplicitConversionCore (ec, expr, target, loc);
1974 if (e != null)
1975 return Nullable.Wrap.Create (e, target_type);
1977 } else if (TypeManager.IsNullableType (expr_type)) {
1978 e = Nullable.Unwrap.Create (expr, false);
1980 bool use_class_cast;
1981 if (ImplicitBoxingConversionExists (e, target_type, out use_class_cast))
1982 return new BoxedCast (expr, target_type);
1984 e = ExplicitConversionCore (ec, e, target_type, loc);
1985 if (e != null)
1986 return EmptyCast.Create (e, target_type);
1989 e = ExplicitUserConversion (ec, expr, target_type, loc);
1990 if (e != null)
1991 return e;
1993 expr.Error_ValueCannotBeConverted (ec, loc, target_type, true);
1994 return null;