2 // conversion.cs: various routines for implementing conversions.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Ravi Pratap (ravi@ximian.com)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
11 namespace Mono.CSharp {
13 using System.Collections;
14 using System.Diagnostics;
15 using System.Reflection;
16 using System.Reflection.Emit;
19 // A container class for all the conversion operations
21 public class Convert {
23 // This is used to prettify the code: a null argument is allowed
24 // for ImplicitStandardConversion as long as it is known that
25 // no anonymous method will play a role.
27 // FIXME: renamed from `const' to `static' to allow bootstraping from older
28 // versions of the compiler that could not cope with this construct.
30 public static EmitContext ConstantEC = null;
32 static void Error_CannotConvertType (Location loc, Type source, Type target)
34 Report.Error (30, loc, "Cannot convert type '" +
35 TypeManager.CSharpName (source) + "' to '" +
36 TypeManager.CSharpName (target) + "'");
39 static Expression TypeParameter_to_Null (Expression expr, Type target_type,
42 if (!TypeParameter_to_Null (target_type)) {
43 Report.Error (403, loc, "Cannot convert null to the type " +
44 "parameter `{0}' becaues it could be a value " +
45 "type. Consider using `default ({0})' instead.",
50 return new NullCast (expr, target_type);
53 static bool TypeParameter_to_Null (Type target_type)
55 if ((target_type.BaseType == null) ||
56 (target_type.BaseType == TypeManager.value_type) ||
57 target_type.BaseType.IsValueType)
63 static Type TypeParam_EffectiveBaseType (EmitContext ec, Type t)
65 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
67 return TypeManager.object_type;
69 return TypeParam_EffectiveBaseType (ec, gc);
72 static Type TypeParam_EffectiveBaseType (EmitContext ec, GenericConstraints gc)
74 ArrayList list = new ArrayList ();
75 list.Add (gc.EffectiveBaseClass);
76 foreach (Type t in gc.InterfaceConstraints) {
77 if (!t.IsGenericParameter)
80 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
82 list.Add (TypeParam_EffectiveBaseType (ec, new_gc));
84 return FindMostEncompassedType (ec, list);
87 static Expression TypeParameterConversion (Expression expr, bool is_reference, Type target_type)
90 return new EmptyCast (expr, target_type);
92 return new BoxedCast (expr, target_type);
95 static Expression ImplicitTypeParameterConversion (EmitContext ec, Expression expr,
98 Type expr_type = expr.Type;
100 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
103 if (target_type == TypeManager.object_type)
104 return new BoxedCast (expr);
109 // We're converting from a type parameter which is known to be a reference type.
110 bool is_reference = gc.IsReferenceType;
111 Type base_type = TypeParam_EffectiveBaseType (ec, gc);
113 if (TypeManager.IsSubclassOf (base_type, target_type))
114 return TypeParameterConversion (expr, is_reference, target_type);
116 if (target_type.IsInterface) {
117 if (TypeManager.ImplementsInterface (base_type, target_type))
118 return TypeParameterConversion (expr, is_reference, target_type);
120 foreach (Type t in gc.InterfaceConstraints) {
121 if (TypeManager.IsSubclassOf (t, target_type))
122 return TypeParameterConversion (expr, is_reference, target_type);
126 foreach (Type t in gc.InterfaceConstraints) {
127 if (!t.IsGenericParameter)
129 if (TypeManager.IsSubclassOf (t, target_type))
130 return TypeParameterConversion (expr, is_reference, target_type);
136 static EmptyExpression MyEmptyExpr;
137 static public Expression ImplicitReferenceConversion (EmitContext ec, Expression expr, Type target_type)
139 Type expr_type = expr.Type;
141 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
142 // if we are a method group, emit a warning
147 if (expr_type == TypeManager.void_type)
150 if (expr_type.IsGenericParameter)
151 return ImplicitTypeParameterConversion (ec, expr, target_type);
154 // notice that it is possible to write "ValueType v = 1", the ValueType here
155 // is an abstract class, and not really a value type, so we apply the same rules.
157 if (target_type == TypeManager.object_type) {
159 // A pointer type cannot be converted to object
161 if (expr_type.IsPointer)
164 if (TypeManager.IsValueType (expr_type))
165 return new BoxedCast (expr);
166 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
167 if (target_type == TypeManager.anonymous_method_type)
169 return new EmptyCast (expr, target_type);
173 } else if (target_type == TypeManager.value_type) {
174 if (TypeManager.IsValueType (expr_type))
175 return new BoxedCast (expr);
176 if (expr_type == TypeManager.null_type)
177 return new NullCast (expr, target_type);
180 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
182 // Special case: enumeration to System.Enum.
183 // System.Enum is not a value type, it is a class, so we need
184 // a boxing conversion
186 if (expr_type.IsEnum || expr_type.IsGenericParameter)
187 return new BoxedCast (expr);
189 return new EmptyCast (expr, target_type);
192 // This code is kind of mirrored inside ImplicitStandardConversionExists
193 // with the small distinction that we only probe there
195 // Always ensure that the code here and there is in sync
197 // from the null type to any reference-type.
198 if (expr_type == TypeManager.null_type){
199 if (target_type.IsPointer)
200 return new EmptyCast (expr, target_type);
202 if (!target_type.IsValueType)
203 return new NullCast (expr, target_type);
206 // from any class-type S to any interface-type T.
207 if (target_type.IsInterface) {
208 if (target_type != TypeManager.iconvertible_type &&
209 expr_type.IsValueType && (expr is Constant) &&
210 !(expr is IntLiteral || expr is BoolLiteral ||
211 expr is FloatLiteral || expr is DoubleLiteral ||
212 expr is LongLiteral || expr is CharLiteral ||
213 expr is StringLiteral || expr is DecimalLiteral ||
214 expr is UIntLiteral || expr is ULongLiteral)) {
218 if (TypeManager.ImplementsInterface (expr_type, target_type)){
219 if (expr_type.IsGenericParameter || TypeManager.IsValueType (expr_type))
220 return new BoxedCast (expr, target_type);
222 return new EmptyCast (expr, target_type);
226 // from any interface type S to interface-type T.
227 if (expr_type.IsInterface && target_type.IsInterface) {
228 if (TypeManager.ImplementsInterface (expr_type, target_type))
229 return new EmptyCast (expr, target_type);
234 // from an array-type S to an array-type of type T
235 if (expr_type.IsArray && target_type.IsArray) {
236 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
238 Type expr_element_type = TypeManager.GetElementType (expr_type);
240 if (MyEmptyExpr == null)
241 MyEmptyExpr = new EmptyExpression ();
243 MyEmptyExpr.SetType (expr_element_type);
244 Type target_element_type = TypeManager.GetElementType (target_type);
246 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
247 if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
248 target_element_type))
249 return new EmptyCast (expr, target_type);
253 // from an array-type to System.Array
254 if (expr_type.IsArray && target_type == TypeManager.array_type)
255 return new EmptyCast (expr, target_type);
257 // from any delegate type to System.Delegate
258 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
259 target_type == TypeManager.delegate_type)
260 return new EmptyCast (expr, target_type);
262 // from any array-type or delegate type into System.ICloneable.
263 if (expr_type.IsArray ||
264 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
265 if (target_type == TypeManager.icloneable_type)
266 return new EmptyCast (expr, target_type);
268 // from a generic type definition to a generic instance.
269 if (TypeManager.IsEqual (expr_type, target_type))
270 return new EmptyCast (expr, target_type);
276 // Tests whether an implicit reference conversion exists between expr_type
279 public static bool ImplicitReferenceConversionExists (EmitContext ec, Expression expr, Type target_type)
281 Type expr_type = expr.Type;
283 if (expr_type.IsGenericParameter)
284 return ImplicitTypeParameterConversion (ec, expr, target_type) != null;
287 // This is the boxed case.
289 if (target_type == TypeManager.object_type) {
290 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
291 expr_type.IsInterface || expr_type == TypeManager.enum_type)
292 if (target_type != TypeManager.anonymous_method_type)
296 } else if (TypeManager.IsSubclassOf (expr_type, target_type))
299 // Please remember that all code below actually comes
300 // from ImplicitReferenceConversion so make sure code remains in sync
302 // from any class-type S to any interface-type T.
303 if (target_type.IsInterface) {
304 if (target_type != TypeManager.iconvertible_type &&
305 expr_type.IsValueType && (expr is Constant) &&
306 !(expr is IntLiteral || expr is BoolLiteral ||
307 expr is FloatLiteral || expr is DoubleLiteral ||
308 expr is LongLiteral || expr is CharLiteral ||
309 expr is StringLiteral || expr is DecimalLiteral ||
310 expr is UIntLiteral || expr is ULongLiteral)) {
314 if (TypeManager.ImplementsInterface (expr_type, target_type))
318 // from any interface type S to interface-type T.
319 if (expr_type.IsInterface && target_type.IsInterface)
320 if (TypeManager.ImplementsInterface (expr_type, target_type))
323 // from an array-type S to an array-type of type T
324 if (expr_type.IsArray && target_type.IsArray) {
325 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
327 Type expr_element_type = expr_type.GetElementType ();
329 if (MyEmptyExpr == null)
330 MyEmptyExpr = new EmptyExpression ();
332 MyEmptyExpr.SetType (expr_element_type);
333 Type target_element_type = TypeManager.GetElementType (target_type);
335 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
336 if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
337 target_element_type))
342 // from an array-type to System.Array
343 if (expr_type.IsArray && (target_type == TypeManager.array_type))
346 // from any delegate type to System.Delegate
347 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
348 target_type == TypeManager.delegate_type)
349 if (target_type.IsAssignableFrom (expr_type))
352 // from any array-type or delegate type into System.ICloneable.
353 if (expr_type.IsArray ||
354 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
355 if (target_type == TypeManager.icloneable_type)
358 // from the null type to any reference-type.
359 if (expr_type == TypeManager.null_type){
360 if (target_type.IsPointer)
363 if (!target_type.IsValueType)
367 // from a generic type definition to a generic instance.
368 if (TypeManager.IsEqual (expr_type, target_type))
375 /// Implicit Numeric Conversions.
377 /// expr is the expression to convert, returns a new expression of type
378 /// target_type or null if an implicit conversion is not possible.
380 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
381 Type target_type, Location loc)
383 Type expr_type = expr.Type;
386 // Attempt to do the implicit constant expression conversions
388 if (expr is Constant){
389 if (expr is IntConstant){
392 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
396 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
398 // Try the implicit constant expression conversion
399 // from long to ulong, instead of a nice routine,
402 long v = ((LongConstant) expr).Value;
404 return new ULongConstant ((ulong) v);
408 Type real_target_type = target_type;
410 if (expr_type == TypeManager.sbyte_type){
412 // From sbyte to short, int, long, float, double.
414 if (real_target_type == TypeManager.int32_type)
415 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
416 if (real_target_type == TypeManager.int64_type)
417 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
418 if (real_target_type == TypeManager.double_type)
419 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
420 if (real_target_type == TypeManager.float_type)
421 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
422 if (real_target_type == TypeManager.short_type)
423 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
424 } else if (expr_type == TypeManager.byte_type){
426 // From byte to short, ushort, int, uint, long, ulong, float, double
428 if ((real_target_type == TypeManager.short_type) ||
429 (real_target_type == TypeManager.ushort_type) ||
430 (real_target_type == TypeManager.int32_type) ||
431 (real_target_type == TypeManager.uint32_type))
432 return new EmptyCast (expr, target_type);
434 if (real_target_type == TypeManager.uint64_type)
435 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
436 if (real_target_type == TypeManager.int64_type)
437 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
438 if (real_target_type == TypeManager.float_type)
439 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
440 if (real_target_type == TypeManager.double_type)
441 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
442 } else if (expr_type == TypeManager.short_type){
444 // From short to int, long, float, double
446 if (real_target_type == TypeManager.int32_type)
447 return new EmptyCast (expr, target_type);
448 if (real_target_type == TypeManager.int64_type)
449 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
450 if (real_target_type == TypeManager.double_type)
451 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
452 if (real_target_type == TypeManager.float_type)
453 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
454 } else if (expr_type == TypeManager.ushort_type){
456 // From ushort to int, uint, long, ulong, float, double
458 if (real_target_type == TypeManager.uint32_type)
459 return new EmptyCast (expr, target_type);
461 if (real_target_type == TypeManager.uint64_type)
462 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
463 if (real_target_type == TypeManager.int32_type)
464 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
465 if (real_target_type == TypeManager.int64_type)
466 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
467 if (real_target_type == TypeManager.double_type)
468 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
469 if (real_target_type == TypeManager.float_type)
470 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
471 } else if (expr_type == TypeManager.int32_type){
473 // From int to long, float, double
475 if (real_target_type == TypeManager.int64_type)
476 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
477 if (real_target_type == TypeManager.double_type)
478 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
479 if (real_target_type == TypeManager.float_type)
480 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
481 } else if (expr_type == TypeManager.uint32_type){
483 // From uint to long, ulong, float, double
485 if (real_target_type == TypeManager.int64_type)
486 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
487 if (real_target_type == TypeManager.uint64_type)
488 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
489 if (real_target_type == TypeManager.double_type)
490 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
492 if (real_target_type == TypeManager.float_type)
493 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
495 } else if (expr_type == TypeManager.int64_type){
497 // From long/ulong to float, double
499 if (real_target_type == TypeManager.double_type)
500 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
501 if (real_target_type == TypeManager.float_type)
502 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
503 } else if (expr_type == TypeManager.uint64_type){
505 // From ulong to float, double
507 if (real_target_type == TypeManager.double_type)
508 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
510 if (real_target_type == TypeManager.float_type)
511 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
513 } else if (expr_type == TypeManager.char_type){
515 // From char to ushort, int, uint, long, ulong, float, double
517 if ((real_target_type == TypeManager.ushort_type) ||
518 (real_target_type == TypeManager.int32_type) ||
519 (real_target_type == TypeManager.uint32_type))
520 return new EmptyCast (expr, target_type);
521 if (real_target_type == TypeManager.uint64_type)
522 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
523 if (real_target_type == TypeManager.int64_type)
524 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
525 if (real_target_type == TypeManager.float_type)
526 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
527 if (real_target_type == TypeManager.double_type)
528 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
529 } else if (expr_type == TypeManager.float_type){
533 if (real_target_type == TypeManager.double_type)
534 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
542 /// Same as ImplicitStandardConversionExists except that it also looks at
543 /// implicit user defined conversions - needed for overload resolution
545 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
547 if ((expr is NullLiteral) && target_type.IsGenericParameter)
548 return TypeParameter_to_Null (target_type);
550 if (ImplicitStandardConversionExists (ec, expr, target_type))
553 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
561 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
563 Expression dummy = ImplicitUserConversion (
564 ec, new EmptyExpression (source), target, Location.Null);
565 return dummy != null;
569 /// Determines if a standard implicit conversion exists from
570 /// expr_type to target_type
572 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
574 public static bool ImplicitStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
576 Type expr_type = expr.Type;
578 if (expr_type == TypeManager.void_type)
581 //Console.WriteLine ("Expr is {0}", expr);
582 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
583 if (expr_type.Equals (target_type))
586 // First numeric conversions
588 if (expr_type == TypeManager.sbyte_type){
590 // From sbyte to short, int, long, float, double.
592 if ((target_type == TypeManager.int32_type) ||
593 (target_type == TypeManager.int64_type) ||
594 (target_type == TypeManager.double_type) ||
595 (target_type == TypeManager.float_type) ||
596 (target_type == TypeManager.short_type) ||
597 (target_type == TypeManager.decimal_type))
600 } else if (expr_type == TypeManager.byte_type){
602 // From byte to short, ushort, int, uint, long, ulong, float, double
604 if ((target_type == TypeManager.short_type) ||
605 (target_type == TypeManager.ushort_type) ||
606 (target_type == TypeManager.int32_type) ||
607 (target_type == TypeManager.uint32_type) ||
608 (target_type == TypeManager.uint64_type) ||
609 (target_type == TypeManager.int64_type) ||
610 (target_type == TypeManager.float_type) ||
611 (target_type == TypeManager.double_type) ||
612 (target_type == TypeManager.decimal_type))
615 } else if (expr_type == TypeManager.short_type){
617 // From short to int, long, float, double
619 if ((target_type == TypeManager.int32_type) ||
620 (target_type == TypeManager.int64_type) ||
621 (target_type == TypeManager.double_type) ||
622 (target_type == TypeManager.float_type) ||
623 (target_type == TypeManager.decimal_type))
626 } else if (expr_type == TypeManager.ushort_type){
628 // From ushort to int, uint, long, ulong, float, double
630 if ((target_type == TypeManager.uint32_type) ||
631 (target_type == TypeManager.uint64_type) ||
632 (target_type == TypeManager.int32_type) ||
633 (target_type == TypeManager.int64_type) ||
634 (target_type == TypeManager.double_type) ||
635 (target_type == TypeManager.float_type) ||
636 (target_type == TypeManager.decimal_type))
639 } else if (expr_type == TypeManager.int32_type){
641 // From int to long, float, double
643 if ((target_type == TypeManager.int64_type) ||
644 (target_type == TypeManager.double_type) ||
645 (target_type == TypeManager.float_type) ||
646 (target_type == TypeManager.decimal_type))
649 } else if (expr_type == TypeManager.uint32_type){
651 // From uint to long, ulong, float, double
653 if ((target_type == TypeManager.int64_type) ||
654 (target_type == TypeManager.uint64_type) ||
655 (target_type == TypeManager.double_type) ||
656 (target_type == TypeManager.float_type) ||
657 (target_type == TypeManager.decimal_type))
660 } else if ((expr_type == TypeManager.uint64_type) ||
661 (expr_type == TypeManager.int64_type)) {
663 // From long/ulong to float, double
665 if ((target_type == TypeManager.double_type) ||
666 (target_type == TypeManager.float_type) ||
667 (target_type == TypeManager.decimal_type))
670 } else if (expr_type == TypeManager.char_type){
672 // From char to ushort, int, uint, long, ulong, float, double
674 if ((target_type == TypeManager.ushort_type) ||
675 (target_type == TypeManager.int32_type) ||
676 (target_type == TypeManager.uint32_type) ||
677 (target_type == TypeManager.uint64_type) ||
678 (target_type == TypeManager.int64_type) ||
679 (target_type == TypeManager.float_type) ||
680 (target_type == TypeManager.double_type) ||
681 (target_type == TypeManager.decimal_type))
684 } else if (expr_type == TypeManager.float_type){
688 if (target_type == TypeManager.double_type)
692 if (ImplicitReferenceConversionExists (ec, expr, target_type))
696 // Implicit Constant Expression Conversions
698 if (expr is IntConstant){
699 int value = ((IntConstant) expr).Value;
701 if (target_type == TypeManager.sbyte_type){
702 if (value >= SByte.MinValue && value <= SByte.MaxValue)
704 } else if (target_type == TypeManager.byte_type){
705 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
707 } else if (target_type == TypeManager.short_type){
708 if (value >= Int16.MinValue && value <= Int16.MaxValue)
710 } else if (target_type == TypeManager.ushort_type){
711 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
713 } else if (target_type == TypeManager.uint32_type){
716 } else if (target_type == TypeManager.uint64_type){
718 // we can optimize this case: a positive int32
719 // always fits on a uint64. But we need an opcode
726 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
730 if (expr is LongConstant && target_type == TypeManager.uint64_type){
732 // Try the implicit constant expression conversion
733 // from long to ulong, instead of a nice routine,
736 long v = ((LongConstant) expr).Value;
741 if ((target_type == TypeManager.enum_type ||
742 target_type.IsSubclassOf (TypeManager.enum_type)) &&
744 IntLiteral i = (IntLiteral) expr;
750 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
753 if (expr_type == TypeManager.anonymous_method_type){
754 if (!TypeManager.IsDelegateType (target_type))
757 AnonymousMethod am = (AnonymousMethod) expr;
758 int errors = Report.Errors;
760 Expression conv = am.Compatible (ec, target_type, true);
769 // Used internally by FindMostEncompassedType, this is used
770 // to avoid creating lots of objects in the tight loop inside
771 // FindMostEncompassedType
773 static EmptyExpression priv_fmet_param;
776 /// Finds "most encompassed type" according to the spec (13.4.2)
777 /// amongst the methods in the MethodGroupExpr
779 static Type FindMostEncompassedType (EmitContext ec, ArrayList types)
783 if (priv_fmet_param == null)
784 priv_fmet_param = new EmptyExpression ();
786 foreach (Type t in types){
787 priv_fmet_param.SetType (t);
794 if (ImplicitStandardConversionExists (ec, priv_fmet_param, best))
802 // Used internally by FindMostEncompassingType, this is used
803 // to avoid creating lots of objects in the tight loop inside
804 // FindMostEncompassingType
806 static EmptyExpression priv_fmee_ret;
809 /// Finds "most encompassing type" according to the spec (13.4.2)
810 /// amongst the types in the given set
812 static Type FindMostEncompassingType (EmitContext ec, ArrayList types)
816 if (priv_fmee_ret == null)
817 priv_fmee_ret = new EmptyExpression ();
819 foreach (Type t in types){
820 priv_fmee_ret.SetType (best);
827 if (ImplicitStandardConversionExists (ec, priv_fmee_ret, t))
835 // Used to avoid creating too many objects
837 static EmptyExpression priv_fms_expr;
840 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
841 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
842 /// for explicit and implicit conversion operators.
844 static public Type FindMostSpecificSource (EmitContext ec, MethodGroupExpr me,
845 Expression source, bool apply_explicit_conv_rules,
848 ArrayList src_types_set = new ArrayList ();
850 if (priv_fms_expr == null)
851 priv_fms_expr = new EmptyExpression ();
854 // If any operator converts from S then Sx = S
856 Type source_type = source.Type;
857 foreach (MethodBase mb in me.Methods){
858 ParameterData pd = Invocation.GetParameterData (mb);
859 Type param_type = pd.ParameterType (0);
861 if (param_type == source_type)
864 if (apply_explicit_conv_rules) {
867 // Find the set of applicable user-defined conversion operators, U. This set
869 // user-defined implicit or explicit conversion operators declared by
870 // the classes or structs in D that convert from a type encompassing
871 // or encompassed by S to a type encompassing or encompassed by T
873 priv_fms_expr.SetType (param_type);
874 if (ImplicitStandardConversionExists (ec, priv_fms_expr, source_type))
875 src_types_set.Add (param_type);
877 if (ImplicitStandardConversionExists (ec, source, param_type))
878 src_types_set.Add (param_type);
882 // Only if S is encompassed by param_type
884 if (ImplicitStandardConversionExists (ec, source, param_type))
885 src_types_set.Add (param_type);
890 // Explicit Conv rules
892 if (apply_explicit_conv_rules) {
893 ArrayList candidate_set = new ArrayList ();
895 foreach (Type param_type in src_types_set){
896 if (ImplicitStandardConversionExists (ec, source, param_type))
897 candidate_set.Add (param_type);
900 if (candidate_set.Count != 0)
901 return FindMostEncompassedType (ec, candidate_set);
907 if (apply_explicit_conv_rules)
908 return FindMostEncompassingType (ec, src_types_set);
910 return FindMostEncompassedType (ec, src_types_set);
914 // Useful in avoiding proliferation of objects
916 static EmptyExpression priv_fmt_expr;
919 /// Finds the most specific target Tx according to section 13.4.4
921 static public Type FindMostSpecificTarget (EmitContext ec, MethodGroupExpr me,
922 Type target, bool apply_explicit_conv_rules,
925 ArrayList tgt_types_set = new ArrayList ();
927 if (priv_fmt_expr == null)
928 priv_fmt_expr = new EmptyExpression ();
931 // If any operator converts to T then Tx = T
933 foreach (MethodInfo mi in me.Methods){
934 Type ret_type = mi.ReturnType;
936 if (ret_type == target)
939 if (apply_explicit_conv_rules) {
942 // Find the set of applicable user-defined conversion operators, U.
944 // This set consists of the
945 // user-defined implicit or explicit conversion operators declared by
946 // the classes or structs in D that convert from a type encompassing
947 // or encompassed by S to a type encompassing or encompassed by T
949 priv_fms_expr.SetType (ret_type);
950 if (ImplicitStandardConversionExists (ec, priv_fms_expr, target))
951 tgt_types_set.Add (ret_type);
953 priv_fms_expr.SetType (target);
954 if (ImplicitStandardConversionExists (ec, priv_fms_expr, ret_type))
955 tgt_types_set.Add (ret_type);
959 // Only if T is encompassed by param_type
961 priv_fms_expr.SetType (ret_type);
962 if (ImplicitStandardConversionExists (ec, priv_fms_expr, target))
963 tgt_types_set.Add (ret_type);
968 // Explicit conv rules
970 if (apply_explicit_conv_rules) {
971 ArrayList candidate_set = new ArrayList ();
973 foreach (Type ret_type in tgt_types_set){
974 priv_fmt_expr.SetType (ret_type);
976 if (ImplicitStandardConversionExists (ec, priv_fmt_expr, target))
977 candidate_set.Add (ret_type);
980 if (candidate_set.Count != 0)
981 return FindMostEncompassingType (ec, candidate_set);
985 // Okay, final case !
987 if (apply_explicit_conv_rules)
988 return FindMostEncompassedType (ec, tgt_types_set);
990 return FindMostEncompassingType (ec, tgt_types_set);
994 /// User-defined Implicit conversions
996 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
997 Type target, Location loc)
999 return UserDefinedConversion (ec, source, target, loc, false);
1003 /// User-defined Explicit conversions
1005 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1006 Type target, Location loc)
1008 return UserDefinedConversion (ec, source, target, loc, true);
1011 static DoubleHash explicit_conv = new DoubleHash (100);
1012 static DoubleHash implicit_conv = new DoubleHash (100);
1014 /// Computes the MethodGroup for the user-defined conversion
1015 /// operators from source_type to target_type. `look_for_explicit'
1016 /// controls whether we should also include the list of explicit
1019 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1020 Type source_type, Type target_type,
1021 Location loc, bool look_for_explicit)
1023 Expression mg1 = null, mg2 = null;
1024 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1027 op_name = "op_Implicit";
1029 MethodGroupExpr union3;
1031 if ((look_for_explicit ? explicit_conv : implicit_conv).Lookup (source_type, target_type, out r))
1032 return (MethodGroupExpr) r;
1034 mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
1035 if (source_type.BaseType != null)
1036 mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1039 union3 = (MethodGroupExpr) mg2;
1040 else if (mg2 == null)
1041 union3 = (MethodGroupExpr) mg1;
1043 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1045 mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
1048 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1050 union3 = (MethodGroupExpr) mg1;
1053 if (target_type.BaseType != null)
1054 mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1058 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1060 union3 = (MethodGroupExpr) mg1;
1063 MethodGroupExpr union4 = null;
1065 if (look_for_explicit) {
1066 op_name = "op_Explicit";
1068 mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
1069 if (source_type.BaseType != null)
1070 mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1072 mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
1073 if (target_type.BaseType != null)
1074 mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1076 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1077 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1079 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1082 MethodGroupExpr ret = Invocation.MakeUnionSet (union3, union4, loc);
1083 (look_for_explicit ? explicit_conv : implicit_conv).Insert (source_type, target_type, ret);
1088 /// User-defined conversions
1090 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1091 Type target, Location loc,
1092 bool look_for_explicit)
1094 MethodGroupExpr union;
1095 Type source_type = source.Type;
1096 MethodBase method = null;
1098 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1102 Type most_specific_source, most_specific_target;
1104 most_specific_source = FindMostSpecificSource (ec, union, source, look_for_explicit, loc);
1105 if (most_specific_source == null)
1108 most_specific_target = FindMostSpecificTarget (ec, union, target, look_for_explicit, loc);
1109 if (most_specific_target == null)
1115 foreach (MethodBase mb in union.Methods){
1116 ParameterData pd = Invocation.GetParameterData (mb);
1117 MethodInfo mi = (MethodInfo) mb;
1119 if (pd.ParameterType (0) == most_specific_source &&
1120 mi.ReturnType == most_specific_target) {
1126 if (method == null || count > 1)
1131 // This will do the conversion to the best match that we
1132 // found. Now we need to perform an implict standard conversion
1133 // if the best match was not the type that we were requested
1136 if (look_for_explicit)
1137 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1139 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1145 e = new UserCast ((MethodInfo) method, source, loc);
1146 if (e.Type != target){
1147 if (!look_for_explicit)
1148 e = ImplicitConversionStandard (ec, e, target, loc);
1150 e = ExplicitConversionStandard (ec, e, target, loc);
1157 /// Converts implicitly the resolved expression `expr' into the
1158 /// `target_type'. It returns a new expression that can be used
1159 /// in a context that expects a `target_type'.
1161 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1162 Type target_type, Location loc)
1166 if (target_type == null)
1167 throw new Exception ("Target type is null");
1169 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1173 e = ImplicitUserConversion (ec, expr, target_type, loc);
1182 /// Attempts to apply the `Standard Implicit
1183 /// Conversion' rules to the expression `expr' into
1184 /// the `target_type'. It returns a new expression
1185 /// that can be used in a context that expects a
1188 /// This is different from `ImplicitConversion' in that the
1189 /// user defined implicit conversions are excluded.
1191 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1192 Type target_type, Location loc)
1194 Type expr_type = expr.Type;
1197 if ((expr is NullLiteral) && target_type.IsGenericParameter)
1198 return TypeParameter_to_Null (expr, target_type, loc);
1200 if (expr.eclass == ExprClass.MethodGroup){
1201 if (!TypeManager.IsDelegateType (target_type)){
1206 // Only allow anonymous method conversions on post ISO_1
1208 if (RootContext.Version != LanguageVersion.ISO_1){
1209 MethodGroupExpr mg = expr as MethodGroupExpr;
1211 return ImplicitDelegateCreation.Create (ec, mg, target_type, loc);
1215 if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
1218 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1222 e = ImplicitReferenceConversion (ec, expr, target_type);
1226 if ((target_type == TypeManager.enum_type ||
1227 target_type.IsSubclassOf (TypeManager.enum_type)) &&
1228 expr is IntLiteral){
1229 IntLiteral i = (IntLiteral) expr;
1232 return new EnumConstant ((Constant) expr, target_type);
1236 if (expr_type.IsPointer){
1237 if (target_type == TypeManager.void_ptr_type)
1238 return new EmptyCast (expr, target_type);
1241 // yep, comparing pointer types cant be done with
1242 // t1 == t2, we have to compare their element types.
1244 if (target_type.IsPointer){
1245 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1250 if (target_type.IsPointer) {
1251 if (expr_type == TypeManager.null_type)
1252 return new EmptyCast (expr, target_type);
1254 if (expr_type == TypeManager.void_ptr_type)
1255 return new EmptyCast (expr, target_type);
1259 if (expr_type == TypeManager.anonymous_method_type){
1260 if (!TypeManager.IsDelegateType (target_type)){
1261 Report.Error (1660, loc,
1262 "Cannot convert anonymous method to `{0}', since it is not a delegate",
1263 TypeManager.CSharpName (target_type));
1267 AnonymousMethod am = (AnonymousMethod) expr;
1268 int errors = Report.Errors;
1270 Expression conv = am.Compatible (ec, target_type, false);
1275 // We return something instead of null, to avoid
1276 // the duplicate error, since am.Compatible would have
1277 // reported that already
1279 if (errors != Report.Errors)
1280 return new EmptyCast (expr, target_type);
1287 /// Attemps to perform an implict constant conversion of the IntConstant
1288 /// into a different data type using casts (See Implicit Constant
1289 /// Expression Conversions)
1291 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1293 int value = ic.Value;
1295 if (target_type == TypeManager.sbyte_type){
1296 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1297 return new SByteConstant ((sbyte) value);
1298 } else if (target_type == TypeManager.byte_type){
1299 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1300 return new ByteConstant ((byte) value);
1301 } else if (target_type == TypeManager.short_type){
1302 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1303 return new ShortConstant ((short) value);
1304 } else if (target_type == TypeManager.ushort_type){
1305 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1306 return new UShortConstant ((ushort) value);
1307 } else if (target_type == TypeManager.uint32_type){
1309 return new UIntConstant ((uint) value);
1310 } else if (target_type == TypeManager.uint64_type){
1312 // we can optimize this case: a positive int32
1313 // always fits on a uint64. But we need an opcode
1317 return new ULongConstant ((ulong) value);
1318 } else if (target_type == TypeManager.double_type)
1319 return new DoubleConstant ((double) value);
1320 else if (target_type == TypeManager.float_type)
1321 return new FloatConstant ((float) value);
1323 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1324 Type underlying = TypeManager.EnumToUnderlying (target_type);
1325 Constant e = (Constant) ic;
1328 // Possibly, we need to create a different 0 literal before passing
1331 if (underlying == TypeManager.int64_type)
1332 e = new LongLiteral (0);
1333 else if (underlying == TypeManager.uint64_type)
1334 e = new ULongLiteral (0);
1336 return new EnumConstant (e, target_type);
1341 static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
1343 Report.Error (29, loc, "Cannot convert implicitly from {0} to `{1}'",
1344 source == TypeManager.anonymous_method_type ?
1345 "anonymous method" : "`" + TypeManager.CSharpName (source) + "'",
1346 TypeManager.CSharpName (target));
1350 /// Attemptes to implicityly convert `target' into `type', using
1351 /// ImplicitConversion. If there is no implicit conversion, then
1352 /// an error is signaled
1354 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1355 Type target_type, Location loc)
1359 int errors = Report.Errors;
1360 e = ImplicitConversion (ec, source, target_type, loc);
1361 if (Report.Errors > errors)
1366 if (source is DoubleLiteral && target_type == TypeManager.float_type){
1367 Report.Error (664, loc,
1368 "Double literal cannot be implicitly converted to " +
1369 "float type, use F suffix to create a float literal");
1372 if (source is Constant){
1373 Constant c = (Constant) source;
1375 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
1379 Error_CannotImplicitConversion (loc, source.Type, target_type);
1385 /// Performs the explicit numeric conversions
1387 static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
1389 Type expr_type = expr.Type;
1392 // If we have an enumeration, extract the underlying type,
1393 // use this during the comparison, but wrap around the original
1396 Type real_target_type = target_type;
1398 if (TypeManager.IsEnumType (real_target_type))
1399 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
1401 if (ImplicitStandardConversionExists (ec, expr, real_target_type)){
1402 Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc);
1404 if (real_target_type != target_type)
1405 return new EmptyCast (ce, target_type);
1409 if (expr_type == TypeManager.sbyte_type){
1411 // From sbyte to byte, ushort, uint, ulong, char
1413 if (real_target_type == TypeManager.byte_type)
1414 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
1415 if (real_target_type == TypeManager.ushort_type)
1416 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
1417 if (real_target_type == TypeManager.uint32_type)
1418 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
1419 if (real_target_type == TypeManager.uint64_type)
1420 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
1421 if (real_target_type == TypeManager.char_type)
1422 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
1423 } else if (expr_type == TypeManager.byte_type){
1425 // From byte to sbyte and char
1427 if (real_target_type == TypeManager.sbyte_type)
1428 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
1429 if (real_target_type == TypeManager.char_type)
1430 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
1431 } else if (expr_type == TypeManager.short_type){
1433 // From short to sbyte, byte, ushort, uint, ulong, char
1435 if (real_target_type == TypeManager.sbyte_type)
1436 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1437 if (real_target_type == TypeManager.byte_type)
1438 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1439 if (real_target_type == TypeManager.ushort_type)
1440 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
1441 if (real_target_type == TypeManager.uint32_type)
1442 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
1443 if (real_target_type == TypeManager.uint64_type)
1444 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
1445 if (real_target_type == TypeManager.char_type)
1446 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
1447 } else if (expr_type == TypeManager.ushort_type){
1449 // From ushort to sbyte, byte, short, char
1451 if (real_target_type == TypeManager.sbyte_type)
1452 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
1453 if (real_target_type == TypeManager.byte_type)
1454 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1455 if (real_target_type == TypeManager.short_type)
1456 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
1457 if (real_target_type == TypeManager.char_type)
1458 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
1459 } else if (expr_type == TypeManager.int32_type){
1461 // From int to sbyte, byte, short, ushort, uint, ulong, char
1463 if (real_target_type == TypeManager.sbyte_type)
1464 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1465 if (real_target_type == TypeManager.byte_type)
1466 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1467 if (real_target_type == TypeManager.short_type)
1468 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1469 if (real_target_type == TypeManager.ushort_type)
1470 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1471 if (real_target_type == TypeManager.uint32_type)
1472 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
1473 if (real_target_type == TypeManager.uint64_type)
1474 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
1475 if (real_target_type == TypeManager.char_type)
1476 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
1477 } else if (expr_type == TypeManager.uint32_type){
1479 // From uint to sbyte, byte, short, ushort, int, char
1481 if (real_target_type == TypeManager.sbyte_type)
1482 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
1483 if (real_target_type == TypeManager.byte_type)
1484 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1485 if (real_target_type == TypeManager.short_type)
1486 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
1487 if (real_target_type == TypeManager.ushort_type)
1488 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1489 if (real_target_type == TypeManager.int32_type)
1490 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
1491 if (real_target_type == TypeManager.char_type)
1492 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
1493 } else if (expr_type == TypeManager.int64_type){
1495 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1497 if (real_target_type == TypeManager.sbyte_type)
1498 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1499 if (real_target_type == TypeManager.byte_type)
1500 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1501 if (real_target_type == TypeManager.short_type)
1502 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1503 if (real_target_type == TypeManager.ushort_type)
1504 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1505 if (real_target_type == TypeManager.int32_type)
1506 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1507 if (real_target_type == TypeManager.uint32_type)
1508 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
1509 if (real_target_type == TypeManager.uint64_type)
1510 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
1511 if (real_target_type == TypeManager.char_type)
1512 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
1513 } else if (expr_type == TypeManager.uint64_type){
1515 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1517 if (real_target_type == TypeManager.sbyte_type)
1518 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
1519 if (real_target_type == TypeManager.byte_type)
1520 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1521 if (real_target_type == TypeManager.short_type)
1522 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
1523 if (real_target_type == TypeManager.ushort_type)
1524 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1525 if (real_target_type == TypeManager.int32_type)
1526 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
1527 if (real_target_type == TypeManager.uint32_type)
1528 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
1529 if (real_target_type == TypeManager.int64_type)
1530 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
1531 if (real_target_type == TypeManager.char_type)
1532 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
1533 } else if (expr_type == TypeManager.char_type){
1535 // From char to sbyte, byte, short
1537 if (real_target_type == TypeManager.sbyte_type)
1538 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
1539 if (real_target_type == TypeManager.byte_type)
1540 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
1541 if (real_target_type == TypeManager.short_type)
1542 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
1543 } else if (expr_type == TypeManager.float_type){
1545 // From float to sbyte, byte, short,
1546 // ushort, int, uint, long, ulong, char
1549 if (real_target_type == TypeManager.sbyte_type)
1550 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1);
1551 if (real_target_type == TypeManager.byte_type)
1552 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1);
1553 if (real_target_type == TypeManager.short_type)
1554 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
1555 if (real_target_type == TypeManager.ushort_type)
1556 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
1557 if (real_target_type == TypeManager.int32_type)
1558 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4);
1559 if (real_target_type == TypeManager.uint32_type)
1560 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
1561 if (real_target_type == TypeManager.int64_type)
1562 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8);
1563 if (real_target_type == TypeManager.uint64_type)
1564 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
1565 if (real_target_type == TypeManager.char_type)
1566 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
1567 } else if (expr_type == TypeManager.double_type){
1569 // From double to byte, byte, short,
1570 // ushort, int, uint, long, ulong,
1571 // char, float or decimal
1573 if (real_target_type == TypeManager.sbyte_type)
1574 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
1575 if (real_target_type == TypeManager.byte_type)
1576 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1577 if (real_target_type == TypeManager.short_type)
1578 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1579 if (real_target_type == TypeManager.ushort_type)
1580 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
1581 if (real_target_type == TypeManager.int32_type)
1582 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1583 if (real_target_type == TypeManager.uint32_type)
1584 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
1585 if (real_target_type == TypeManager.int64_type)
1586 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1587 if (real_target_type == TypeManager.uint64_type)
1588 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
1589 if (real_target_type == TypeManager.char_type)
1590 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
1591 if (real_target_type == TypeManager.float_type)
1592 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
1595 // decimal is taken care of by the op_Explicit methods.
1601 /// Returns whether an explicit reference conversion can be performed
1602 /// from source_type to target_type
1604 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1606 bool target_is_type_param = target_type.IsGenericParameter;
1607 bool target_is_value_type = target_type.IsValueType;
1609 if (source_type == target_type)
1613 // From object to a generic parameter
1615 if (source_type == TypeManager.object_type && target_is_type_param)
1619 // From object to any reference type
1621 if (source_type == TypeManager.object_type && !target_is_value_type)
1625 // From any class S to any class-type T, provided S is a base class of T
1627 if (TypeManager.IsSubclassOf (target_type, source_type))
1631 // From any interface type S to any interface T provided S is not derived from T
1633 if (source_type.IsInterface && target_type.IsInterface){
1634 if (!TypeManager.IsSubclassOf (target_type, source_type))
1639 // From any class type S to any interface T, provided S is not sealed
1640 // and provided S does not implement T.
1642 if (target_type.IsInterface && !source_type.IsSealed &&
1643 !TypeManager.ImplementsInterface (source_type, target_type))
1647 // From any interface-type S to to any class type T, provided T is not
1648 // sealed, or provided T implements S.
1650 if (source_type.IsInterface &&
1651 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1655 // From an array type S with an element type Se to an array type T with an
1656 // element type Te provided all the following are true:
1657 // * S and T differe only in element type, in other words, S and T
1658 // have the same number of dimensions.
1659 // * Both Se and Te are reference types
1660 // * An explicit referenc conversions exist from Se to Te
1662 if (source_type.IsArray && target_type.IsArray) {
1663 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1665 Type source_element_type = TypeManager.GetElementType (source_type);
1666 Type target_element_type = TypeManager.GetElementType (target_type);
1668 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1669 if (ExplicitReferenceConversionExists (source_element_type,
1670 target_element_type))
1676 // From System.Array to any array-type
1677 if (source_type == TypeManager.array_type &&
1678 target_type.IsArray){
1683 // From System delegate to any delegate-type
1685 if (source_type == TypeManager.delegate_type &&
1686 TypeManager.IsDelegateType (target_type))
1690 // From ICloneable to Array or Delegate types
1692 if (source_type == TypeManager.icloneable_type &&
1693 (target_type == TypeManager.array_type ||
1694 target_type == TypeManager.delegate_type))
1701 /// Implements Explicit Reference conversions
1703 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1705 Type source_type = source.Type;
1706 bool target_is_type_param = target_type.IsGenericParameter;
1707 bool target_is_value_type = target_type.IsValueType;
1710 // From object to a generic parameter
1712 if (source_type == TypeManager.object_type && target_is_type_param)
1713 return new UnboxCast (source, target_type);
1716 // From object to any reference type
1718 if (source_type == TypeManager.object_type && !target_is_value_type)
1719 return new ClassCast (source, target_type);
1722 // Unboxing conversion.
1724 if (((source_type == TypeManager.enum_type &&
1725 !(source is EmptyCast)) ||
1726 source_type == TypeManager.value_type) && target_is_value_type)
1727 return new UnboxCast (source, target_type);
1730 // From any class S to any class-type T, provided S is a base class of T
1732 if (TypeManager.IsSubclassOf (target_type, source_type))
1733 return new ClassCast (source, target_type);
1736 // From any interface type S to any interface T provided S is not derived from T
1738 if (source_type.IsInterface && target_type.IsInterface){
1739 if (TypeManager.ImplementsInterface (source_type, target_type))
1742 return new ClassCast (source, target_type);
1746 // From any class type S to any interface T, provides S is not sealed
1747 // and provided S does not implement T.
1749 if (target_type.IsInterface && !source_type.IsSealed) {
1750 if (TypeManager.ImplementsInterface (source_type, target_type))
1753 return new ClassCast (source, target_type);
1758 // From any interface-type S to to any class type T, provided T is not
1759 // sealed, or provided T implements S.
1761 if (source_type.IsInterface) {
1762 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1763 if (target_type.IsClass)
1764 return new ClassCast (source, target_type);
1766 return new UnboxCast (source, target_type);
1772 // From an array type S with an element type Se to an array type T with an
1773 // element type Te provided all the following are true:
1774 // * S and T differe only in element type, in other words, S and T
1775 // have the same number of dimensions.
1776 // * Both Se and Te are reference types
1777 // * An explicit referenc conversions exist from Se to Te
1779 if (source_type.IsArray && target_type.IsArray) {
1780 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1782 Type source_element_type = TypeManager.GetElementType (source_type);
1783 Type target_element_type = TypeManager.GetElementType (target_type);
1785 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1786 if (ExplicitReferenceConversionExists (source_element_type,
1787 target_element_type))
1788 return new ClassCast (source, target_type);
1793 // From System.Array to any array-type
1794 if (source_type == TypeManager.array_type &&
1795 target_type.IsArray) {
1796 return new ClassCast (source, target_type);
1800 // From System delegate to any delegate-type
1802 if (source_type == TypeManager.delegate_type &&
1803 TypeManager.IsDelegateType (target_type))
1804 return new ClassCast (source, target_type);
1807 // From ICloneable to Array or Delegate types
1809 if (source_type == TypeManager.icloneable_type &&
1810 (target_type == TypeManager.array_type ||
1811 target_type == TypeManager.delegate_type))
1812 return new ClassCast (source, target_type);
1818 /// Performs an explicit conversion of the expression `expr' whose
1819 /// type is expr.Type to `target_type'.
1821 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1822 Type target_type, Location loc)
1824 Type expr_type = expr.Type;
1825 Type original_expr_type = expr_type;
1827 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
1828 if (target_type == TypeManager.enum_type ||
1829 target_type == TypeManager.object_type) {
1830 if (expr is EnumConstant)
1831 expr = ((EnumConstant) expr).Child;
1832 // We really need all these casts here .... :-(
1833 expr = new BoxedCast (new EmptyCast (expr, expr_type));
1834 return new EmptyCast (expr, target_type);
1835 } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
1836 target_type.IsSubclassOf (TypeManager.enum_type))
1837 return new UnboxCast (expr, target_type);
1840 // Notice that we have kept the expr_type unmodified, which is only
1842 if (expr is EnumConstant)
1843 expr = ((EnumConstant) expr).Child;
1845 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
1846 expr_type = expr.Type;
1849 int errors = Report.Errors;
1850 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1851 if (Report.Errors > errors)
1857 ne = ExplicitNumericConversion (ec, expr, target_type, loc);
1862 // Unboxing conversion.
1864 if (expr_type == TypeManager.object_type && target_type.IsValueType)
1865 return new UnboxCast (expr, target_type);
1868 // Skip the ExplicitReferenceConversion because we can not convert
1869 // from Null to a ValueType, and ExplicitReference wont check against
1870 // null literal explicitly
1872 if (expr_type != TypeManager.null_type){
1873 ne = ExplicitReferenceConversion (expr, target_type);
1880 if (target_type.IsPointer){
1881 if (expr_type.IsPointer)
1882 return new EmptyCast (expr, target_type);
1884 if (expr_type == TypeManager.sbyte_type ||
1885 expr_type == TypeManager.byte_type ||
1886 expr_type == TypeManager.short_type ||
1887 expr_type == TypeManager.ushort_type ||
1888 expr_type == TypeManager.int32_type ||
1889 expr_type == TypeManager.uint32_type ||
1890 expr_type == TypeManager.uint64_type ||
1891 expr_type == TypeManager.int64_type)
1892 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1894 if (expr_type.IsPointer){
1895 Expression e = null;
1897 if (target_type == TypeManager.sbyte_type)
1898 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1899 else if (target_type == TypeManager.byte_type)
1900 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1901 else if (target_type == TypeManager.short_type)
1902 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1903 else if (target_type == TypeManager.ushort_type)
1904 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1905 else if (target_type == TypeManager.int32_type)
1906 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1907 else if (target_type == TypeManager.uint32_type)
1908 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1909 else if (target_type == TypeManager.uint64_type)
1910 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1911 else if (target_type == TypeManager.int64_type){
1912 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1918 ci = ImplicitConversionStandard (ec, e, target_type, loc);
1923 ce = ExplicitNumericConversion (ec, e, target_type, loc);
1927 // We should always be able to go from an uint32
1928 // implicitly or explicitly to the other integral
1931 throw new Exception ("Internal compiler error");
1936 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1940 if (expr is NullLiteral){
1941 Report.Error (37, loc, "Cannot convert null to value type `" +
1942 TypeManager.CSharpName (target_type) + "'");
1946 Error_CannotConvertType (loc, original_expr_type, target_type);
1951 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1953 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1954 Type target_type, Location l)
1956 int errors = Report.Errors;
1957 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1958 if (Report.Errors > errors)
1964 ne = ExplicitNumericConversion (ec, expr, target_type, l);
1968 ne = ExplicitReferenceConversion (expr, target_type);
1972 Error_CannotConvertType (l, expr.Type, target_type);