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 NullPointer.Null;
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 (TypeManager.ImplementsInterface (expr_type, target_type))
308 // from any interface type S to interface-type T.
309 if (expr_type.IsInterface && target_type.IsInterface)
310 if (TypeManager.ImplementsInterface (expr_type, target_type))
313 // from an array-type S to an array-type of type T
314 if (expr_type.IsArray && target_type.IsArray) {
315 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
317 Type expr_element_type = expr_type.GetElementType ();
319 if (MyEmptyExpr == null)
320 MyEmptyExpr = new EmptyExpression ();
322 MyEmptyExpr.SetType (expr_element_type);
323 Type target_element_type = TypeManager.GetElementType (target_type);
325 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
326 if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
327 target_element_type))
332 // from an array-type to System.Array
333 if (expr_type.IsArray && (target_type == TypeManager.array_type))
336 // from any delegate type to System.Delegate
337 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
338 target_type == TypeManager.delegate_type)
339 if (target_type.IsAssignableFrom (expr_type))
342 // from any array-type or delegate type into System.ICloneable.
343 if (expr_type.IsArray ||
344 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
345 if (target_type == TypeManager.icloneable_type)
348 // from the null type to any reference-type.
349 if (expr_type == TypeManager.null_type && !target_type.IsValueType && !TypeManager.IsEnumType (target_type))
352 // from a generic type definition to a generic instance.
353 if (TypeManager.IsEqual (expr_type, target_type))
360 /// Implicit Numeric Conversions.
362 /// expr is the expression to convert, returns a new expression of type
363 /// target_type or null if an implicit conversion is not possible.
365 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
366 Type target_type, Location loc)
368 Type expr_type = expr.Type;
371 // Attempt to do the implicit constant expression conversions
373 if (expr is Constant){
374 if (expr is IntConstant){
377 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
381 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
383 // Try the implicit constant expression conversion
384 // from long to ulong, instead of a nice routine,
387 long v = ((LongConstant) expr).Value;
389 return new ULongConstant ((ulong) v);
393 Type real_target_type = target_type;
395 if (expr_type == TypeManager.sbyte_type){
397 // From sbyte to short, int, long, float, double.
399 if (real_target_type == TypeManager.int32_type)
400 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
401 if (real_target_type == TypeManager.int64_type)
402 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
403 if (real_target_type == TypeManager.double_type)
404 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
405 if (real_target_type == TypeManager.float_type)
406 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
407 if (real_target_type == TypeManager.short_type)
408 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
409 } else if (expr_type == TypeManager.byte_type){
411 // From byte to short, ushort, int, uint, long, ulong, float, double
413 if ((real_target_type == TypeManager.short_type) ||
414 (real_target_type == TypeManager.ushort_type) ||
415 (real_target_type == TypeManager.int32_type) ||
416 (real_target_type == TypeManager.uint32_type))
417 return new EmptyCast (expr, target_type);
419 if (real_target_type == TypeManager.uint64_type)
420 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
421 if (real_target_type == TypeManager.int64_type)
422 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
423 if (real_target_type == TypeManager.float_type)
424 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
425 if (real_target_type == TypeManager.double_type)
426 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
427 } else if (expr_type == TypeManager.short_type){
429 // From short to int, long, float, double
431 if (real_target_type == TypeManager.int32_type)
432 return new EmptyCast (expr, target_type);
433 if (real_target_type == TypeManager.int64_type)
434 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
435 if (real_target_type == TypeManager.double_type)
436 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
437 if (real_target_type == TypeManager.float_type)
438 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
439 } else if (expr_type == TypeManager.ushort_type){
441 // From ushort to int, uint, long, ulong, float, double
443 if (real_target_type == TypeManager.uint32_type)
444 return new EmptyCast (expr, target_type);
446 if (real_target_type == TypeManager.uint64_type)
447 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
448 if (real_target_type == TypeManager.int32_type)
449 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
450 if (real_target_type == TypeManager.int64_type)
451 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
452 if (real_target_type == TypeManager.double_type)
453 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
454 if (real_target_type == TypeManager.float_type)
455 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
456 } else if (expr_type == TypeManager.int32_type){
458 // From int to long, float, double
460 if (real_target_type == TypeManager.int64_type)
461 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
462 if (real_target_type == TypeManager.double_type)
463 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
464 if (real_target_type == TypeManager.float_type)
465 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
466 } else if (expr_type == TypeManager.uint32_type){
468 // From uint to long, ulong, float, double
470 if (real_target_type == TypeManager.int64_type)
471 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
472 if (real_target_type == TypeManager.uint64_type)
473 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
474 if (real_target_type == TypeManager.double_type)
475 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
477 if (real_target_type == TypeManager.float_type)
478 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
480 } else if (expr_type == TypeManager.int64_type){
482 // From long/ulong to float, double
484 if (real_target_type == TypeManager.double_type)
485 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
486 if (real_target_type == TypeManager.float_type)
487 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
488 } else if (expr_type == TypeManager.uint64_type){
490 // From ulong to float, double
492 if (real_target_type == TypeManager.double_type)
493 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
495 if (real_target_type == TypeManager.float_type)
496 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
498 } else if (expr_type == TypeManager.char_type){
500 // From char to ushort, int, uint, long, ulong, float, double
502 if ((real_target_type == TypeManager.ushort_type) ||
503 (real_target_type == TypeManager.int32_type) ||
504 (real_target_type == TypeManager.uint32_type))
505 return new EmptyCast (expr, target_type);
506 if (real_target_type == TypeManager.uint64_type)
507 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
508 if (real_target_type == TypeManager.int64_type)
509 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
510 if (real_target_type == TypeManager.float_type)
511 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
512 if (real_target_type == TypeManager.double_type)
513 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
514 } else if (expr_type == TypeManager.float_type){
518 if (real_target_type == TypeManager.double_type)
519 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
527 /// Same as ImplicitStandardConversionExists except that it also looks at
528 /// implicit user defined conversions - needed for overload resolution
530 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
532 if ((expr is NullLiteral) && target_type.IsGenericParameter)
533 return TypeParameter_to_Null (target_type);
535 if (ImplicitStandardConversionExists (ec, expr, target_type))
538 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
546 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
548 Expression dummy = ImplicitUserConversion (
549 ec, new EmptyExpression (source), target, Location.Null);
550 return dummy != null;
554 /// Determines if a standard implicit conversion exists from
555 /// expr_type to target_type
557 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
559 public static bool ImplicitStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
561 Type expr_type = expr.Type;
563 if (expr_type == TypeManager.void_type)
566 //Console.WriteLine ("Expr is {0}", expr);
567 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
568 if (expr_type.Equals (target_type))
571 // First numeric conversions
573 if (expr_type == TypeManager.sbyte_type){
575 // From sbyte to short, int, long, float, double.
577 if ((target_type == TypeManager.int32_type) ||
578 (target_type == TypeManager.int64_type) ||
579 (target_type == TypeManager.double_type) ||
580 (target_type == TypeManager.float_type) ||
581 (target_type == TypeManager.short_type) ||
582 (target_type == TypeManager.decimal_type))
585 } else if (expr_type == TypeManager.byte_type){
587 // From byte to short, ushort, int, uint, long, ulong, float, double
589 if ((target_type == TypeManager.short_type) ||
590 (target_type == TypeManager.ushort_type) ||
591 (target_type == TypeManager.int32_type) ||
592 (target_type == TypeManager.uint32_type) ||
593 (target_type == TypeManager.uint64_type) ||
594 (target_type == TypeManager.int64_type) ||
595 (target_type == TypeManager.float_type) ||
596 (target_type == TypeManager.double_type) ||
597 (target_type == TypeManager.decimal_type))
600 } else if (expr_type == TypeManager.short_type){
602 // From short to int, long, float, double
604 if ((target_type == TypeManager.int32_type) ||
605 (target_type == TypeManager.int64_type) ||
606 (target_type == TypeManager.double_type) ||
607 (target_type == TypeManager.float_type) ||
608 (target_type == TypeManager.decimal_type))
611 } else if (expr_type == TypeManager.ushort_type){
613 // From ushort to int, uint, long, ulong, float, double
615 if ((target_type == TypeManager.uint32_type) ||
616 (target_type == TypeManager.uint64_type) ||
617 (target_type == TypeManager.int32_type) ||
618 (target_type == TypeManager.int64_type) ||
619 (target_type == TypeManager.double_type) ||
620 (target_type == TypeManager.float_type) ||
621 (target_type == TypeManager.decimal_type))
624 } else if (expr_type == TypeManager.int32_type){
626 // From int to long, float, double
628 if ((target_type == TypeManager.int64_type) ||
629 (target_type == TypeManager.double_type) ||
630 (target_type == TypeManager.float_type) ||
631 (target_type == TypeManager.decimal_type))
634 } else if (expr_type == TypeManager.uint32_type){
636 // From uint to long, ulong, float, double
638 if ((target_type == TypeManager.int64_type) ||
639 (target_type == TypeManager.uint64_type) ||
640 (target_type == TypeManager.double_type) ||
641 (target_type == TypeManager.float_type) ||
642 (target_type == TypeManager.decimal_type))
645 } else if ((expr_type == TypeManager.uint64_type) ||
646 (expr_type == TypeManager.int64_type)) {
648 // From long/ulong to float, double
650 if ((target_type == TypeManager.double_type) ||
651 (target_type == TypeManager.float_type) ||
652 (target_type == TypeManager.decimal_type))
655 } else if (expr_type == TypeManager.char_type){
657 // From char to ushort, int, uint, long, ulong, float, double
659 if ((target_type == TypeManager.ushort_type) ||
660 (target_type == TypeManager.int32_type) ||
661 (target_type == TypeManager.uint32_type) ||
662 (target_type == TypeManager.uint64_type) ||
663 (target_type == TypeManager.int64_type) ||
664 (target_type == TypeManager.float_type) ||
665 (target_type == TypeManager.double_type) ||
666 (target_type == TypeManager.decimal_type))
669 } else if (expr_type == TypeManager.float_type){
673 if (target_type == TypeManager.double_type)
677 if (ImplicitReferenceConversionExists (ec, expr, target_type))
681 // Implicit Constant Expression Conversions
683 if (expr is IntConstant){
684 int value = ((IntConstant) expr).Value;
686 if (target_type == TypeManager.sbyte_type){
687 if (value >= SByte.MinValue && value <= SByte.MaxValue)
689 } else if (target_type == TypeManager.byte_type){
690 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
692 } else if (target_type == TypeManager.short_type){
693 if (value >= Int16.MinValue && value <= Int16.MaxValue)
695 } else if (target_type == TypeManager.ushort_type){
696 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
698 } else if (target_type == TypeManager.uint32_type){
701 } else if (target_type == TypeManager.uint64_type){
703 // we can optimize this case: a positive int32
704 // always fits on a uint64. But we need an opcode
711 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
715 if (expr is LongConstant && target_type == TypeManager.uint64_type){
717 // Try the implicit constant expression conversion
718 // from long to ulong, instead of a nice routine,
721 long v = ((LongConstant) expr).Value;
726 if ((target_type == TypeManager.enum_type ||
727 target_type.IsSubclassOf (TypeManager.enum_type)) &&
729 IntLiteral i = (IntLiteral) expr;
735 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
738 if (expr_type == TypeManager.anonymous_method_type){
739 if (!TypeManager.IsDelegateType (target_type))
742 AnonymousMethod am = (AnonymousMethod) expr;
743 int errors = Report.Errors;
745 Expression conv = am.Compatible (ec, target_type, true);
754 // Used internally by FindMostEncompassedType, this is used
755 // to avoid creating lots of objects in the tight loop inside
756 // FindMostEncompassedType
758 static EmptyExpression priv_fmet_param;
761 /// Finds "most encompassed type" according to the spec (13.4.2)
762 /// amongst the methods in the MethodGroupExpr
764 static Type FindMostEncompassedType (EmitContext ec, ArrayList types)
768 if (priv_fmet_param == null)
769 priv_fmet_param = new EmptyExpression ();
771 foreach (Type t in types){
772 priv_fmet_param.SetType (t);
779 if (ImplicitStandardConversionExists (ec, priv_fmet_param, best))
787 // Used internally by FindMostEncompassingType, this is used
788 // to avoid creating lots of objects in the tight loop inside
789 // FindMostEncompassingType
791 static EmptyExpression priv_fmee_ret;
794 /// Finds "most encompassing type" according to the spec (13.4.2)
795 /// amongst the types in the given set
797 static Type FindMostEncompassingType (EmitContext ec, ArrayList types)
801 if (priv_fmee_ret == null)
802 priv_fmee_ret = new EmptyExpression ();
804 foreach (Type t in types){
805 priv_fmee_ret.SetType (best);
812 if (ImplicitStandardConversionExists (ec, priv_fmee_ret, t))
820 // Used to avoid creating too many objects
822 static EmptyExpression priv_fms_expr;
825 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
826 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
827 /// for explicit and implicit conversion operators.
829 static public Type FindMostSpecificSource (EmitContext ec, MethodGroupExpr me,
830 Expression source, bool apply_explicit_conv_rules,
833 ArrayList src_types_set = new ArrayList ();
835 if (priv_fms_expr == null)
836 priv_fms_expr = new EmptyExpression ();
839 // If any operator converts from S then Sx = S
841 Type source_type = source.Type;
842 foreach (MethodBase mb in me.Methods){
843 ParameterData pd = Invocation.GetParameterData (mb);
844 Type param_type = pd.ParameterType (0);
846 if (param_type == source_type)
849 if (apply_explicit_conv_rules) {
852 // Find the set of applicable user-defined conversion operators, U. This set
854 // user-defined implicit or explicit conversion operators declared by
855 // the classes or structs in D that convert from a type encompassing
856 // or encompassed by S to a type encompassing or encompassed by T
858 priv_fms_expr.SetType (param_type);
859 if (ImplicitStandardConversionExists (ec, priv_fms_expr, source_type))
860 src_types_set.Add (param_type);
862 if (ImplicitStandardConversionExists (ec, source, param_type))
863 src_types_set.Add (param_type);
867 // Only if S is encompassed by param_type
869 if (ImplicitStandardConversionExists (ec, source, param_type))
870 src_types_set.Add (param_type);
875 // Explicit Conv rules
877 if (apply_explicit_conv_rules) {
878 ArrayList candidate_set = new ArrayList ();
880 foreach (Type param_type in src_types_set){
881 if (ImplicitStandardConversionExists (ec, source, param_type))
882 candidate_set.Add (param_type);
885 if (candidate_set.Count != 0)
886 return FindMostEncompassedType (ec, candidate_set);
892 if (apply_explicit_conv_rules)
893 return FindMostEncompassingType (ec, src_types_set);
895 return FindMostEncompassedType (ec, src_types_set);
899 // Useful in avoiding proliferation of objects
901 static EmptyExpression priv_fmt_expr;
904 /// Finds the most specific target Tx according to section 13.4.4
906 static public Type FindMostSpecificTarget (EmitContext ec, MethodGroupExpr me,
907 Type target, bool apply_explicit_conv_rules,
910 ArrayList tgt_types_set = new ArrayList ();
912 if (priv_fmt_expr == null)
913 priv_fmt_expr = new EmptyExpression ();
916 // If any operator converts to T then Tx = T
918 foreach (MethodInfo mi in me.Methods){
919 Type ret_type = mi.ReturnType;
921 if (ret_type == target)
924 if (apply_explicit_conv_rules) {
927 // Find the set of applicable user-defined conversion operators, U.
929 // This set consists of the
930 // user-defined implicit or explicit conversion operators declared by
931 // the classes or structs in D that convert from a type encompassing
932 // or encompassed by S to a type encompassing or encompassed by T
934 priv_fms_expr.SetType (ret_type);
935 if (ImplicitStandardConversionExists (ec, priv_fms_expr, target))
936 tgt_types_set.Add (ret_type);
938 priv_fms_expr.SetType (target);
939 if (ImplicitStandardConversionExists (ec, priv_fms_expr, ret_type))
940 tgt_types_set.Add (ret_type);
944 // Only if T is encompassed by param_type
946 priv_fms_expr.SetType (ret_type);
947 if (ImplicitStandardConversionExists (ec, priv_fms_expr, target))
948 tgt_types_set.Add (ret_type);
953 // Explicit conv rules
955 if (apply_explicit_conv_rules) {
956 ArrayList candidate_set = new ArrayList ();
958 foreach (Type ret_type in tgt_types_set){
959 priv_fmt_expr.SetType (ret_type);
961 if (ImplicitStandardConversionExists (ec, priv_fmt_expr, target))
962 candidate_set.Add (ret_type);
965 if (candidate_set.Count != 0)
966 return FindMostEncompassingType (ec, candidate_set);
970 // Okay, final case !
972 if (apply_explicit_conv_rules)
973 return FindMostEncompassedType (ec, tgt_types_set);
975 return FindMostEncompassingType (ec, tgt_types_set);
979 /// User-defined Implicit conversions
981 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
982 Type target, Location loc)
984 return UserDefinedConversion (ec, source, target, loc, false);
988 /// User-defined Explicit conversions
990 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
991 Type target, Location loc)
993 return UserDefinedConversion (ec, source, target, loc, true);
996 static DoubleHash explicit_conv = new DoubleHash (100);
997 static DoubleHash implicit_conv = new DoubleHash (100);
999 /// Computes the MethodGroup for the user-defined conversion
1000 /// operators from source_type to target_type. `look_for_explicit'
1001 /// controls whether we should also include the list of explicit
1004 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1005 Type source_type, Type target_type,
1006 Location loc, bool look_for_explicit)
1008 Expression mg1 = null, mg2 = null;
1009 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1012 op_name = "op_Implicit";
1014 MethodGroupExpr union3;
1016 if ((look_for_explicit ? explicit_conv : implicit_conv).Lookup (source_type, target_type, out r))
1017 return (MethodGroupExpr) r;
1019 mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
1020 if (source_type.BaseType != null)
1021 mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1024 union3 = (MethodGroupExpr) mg2;
1025 else if (mg2 == null)
1026 union3 = (MethodGroupExpr) mg1;
1028 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1030 mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
1033 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1035 union3 = (MethodGroupExpr) mg1;
1038 if (target_type.BaseType != null)
1039 mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1043 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1045 union3 = (MethodGroupExpr) mg1;
1048 MethodGroupExpr union4 = null;
1050 if (look_for_explicit) {
1051 op_name = "op_Explicit";
1053 mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
1054 if (source_type.BaseType != null)
1055 mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1057 mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
1058 if (target_type.BaseType != null)
1059 mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1061 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1062 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1064 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1067 MethodGroupExpr ret = Invocation.MakeUnionSet (union3, union4, loc);
1068 (look_for_explicit ? explicit_conv : implicit_conv).Insert (source_type, target_type, ret);
1073 /// User-defined conversions
1075 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1076 Type target, Location loc,
1077 bool look_for_explicit)
1079 MethodGroupExpr union;
1080 Type source_type = source.Type;
1081 MethodBase method = null;
1083 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1087 Type most_specific_source, most_specific_target;
1089 most_specific_source = FindMostSpecificSource (ec, union, source, look_for_explicit, loc);
1090 if (most_specific_source == null)
1093 most_specific_target = FindMostSpecificTarget (ec, union, target, look_for_explicit, loc);
1094 if (most_specific_target == null)
1100 foreach (MethodBase mb in union.Methods){
1101 ParameterData pd = Invocation.GetParameterData (mb);
1102 MethodInfo mi = (MethodInfo) mb;
1104 if (pd.ParameterType (0) == most_specific_source &&
1105 mi.ReturnType == most_specific_target) {
1111 if (method == null || count > 1)
1116 // This will do the conversion to the best match that we
1117 // found. Now we need to perform an implict standard conversion
1118 // if the best match was not the type that we were requested
1121 if (look_for_explicit)
1122 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1124 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1130 e = new UserCast ((MethodInfo) method, source, loc);
1131 if (e.Type != target){
1132 if (!look_for_explicit)
1133 e = ImplicitConversionStandard (ec, e, target, loc);
1135 e = ExplicitConversionStandard (ec, e, target, loc);
1142 /// Converts implicitly the resolved expression `expr' into the
1143 /// `target_type'. It returns a new expression that can be used
1144 /// in a context that expects a `target_type'.
1146 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1147 Type target_type, Location loc)
1151 if (target_type == null)
1152 throw new Exception ("Target type is null");
1154 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1158 e = ImplicitUserConversion (ec, expr, target_type, loc);
1167 /// Attempts to apply the `Standard Implicit
1168 /// Conversion' rules to the expression `expr' into
1169 /// the `target_type'. It returns a new expression
1170 /// that can be used in a context that expects a
1173 /// This is different from `ImplicitConversion' in that the
1174 /// user defined implicit conversions are excluded.
1176 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1177 Type target_type, Location loc)
1179 Type expr_type = expr.Type;
1182 if ((expr is NullLiteral) && target_type.IsGenericParameter)
1183 return TypeParameter_to_Null (expr, target_type, loc);
1185 if (expr.eclass == ExprClass.MethodGroup){
1186 if (!TypeManager.IsDelegateType (target_type)){
1191 // Only allow anonymous method conversions on post ISO_1
1193 if (RootContext.Version != LanguageVersion.ISO_1){
1194 MethodGroupExpr mg = expr as MethodGroupExpr;
1196 return ImplicitDelegateCreation.Create (ec, mg, target_type, loc);
1200 if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
1203 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1207 e = ImplicitReferenceConversion (ec, expr, target_type);
1211 if ((target_type == TypeManager.enum_type ||
1212 target_type.IsSubclassOf (TypeManager.enum_type)) &&
1213 expr is IntLiteral){
1214 IntLiteral i = (IntLiteral) expr;
1217 return new EnumConstant ((Constant) expr, target_type);
1221 if (expr_type.IsPointer){
1222 if (target_type == TypeManager.void_ptr_type)
1223 return new EmptyCast (expr, target_type);
1226 // yep, comparing pointer types cant be done with
1227 // t1 == t2, we have to compare their element types.
1229 if (target_type.IsPointer){
1230 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1235 if (target_type.IsPointer) {
1236 if (expr_type == TypeManager.null_type)
1237 return new EmptyCast (expr, target_type);
1239 if (expr_type == TypeManager.void_ptr_type)
1240 return new EmptyCast (expr, target_type);
1244 if (expr_type == TypeManager.anonymous_method_type){
1245 if (!TypeManager.IsDelegateType (target_type)){
1246 Report.Error (1660, loc,
1247 "Cannot convert anonymous method to `{0}', since it is not a delegate",
1248 TypeManager.CSharpName (target_type));
1252 AnonymousMethod am = (AnonymousMethod) expr;
1253 int errors = Report.Errors;
1255 Expression conv = am.Compatible (ec, target_type, false);
1260 // We return something instead of null, to avoid
1261 // the duplicate error, since am.Compatible would have
1262 // reported that already
1264 if (errors != Report.Errors)
1265 return new EmptyCast (expr, target_type);
1272 /// Attemps to perform an implict constant conversion of the IntConstant
1273 /// into a different data type using casts (See Implicit Constant
1274 /// Expression Conversions)
1276 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1278 int value = ic.Value;
1280 if (target_type == TypeManager.sbyte_type){
1281 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1282 return new SByteConstant ((sbyte) value);
1283 } else if (target_type == TypeManager.byte_type){
1284 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1285 return new ByteConstant ((byte) value);
1286 } else if (target_type == TypeManager.short_type){
1287 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1288 return new ShortConstant ((short) value);
1289 } else if (target_type == TypeManager.ushort_type){
1290 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1291 return new UShortConstant ((ushort) value);
1292 } else if (target_type == TypeManager.uint32_type){
1294 return new UIntConstant ((uint) value);
1295 } else if (target_type == TypeManager.uint64_type){
1297 // we can optimize this case: a positive int32
1298 // always fits on a uint64. But we need an opcode
1302 return new ULongConstant ((ulong) value);
1303 } else if (target_type == TypeManager.double_type)
1304 return new DoubleConstant ((double) value);
1305 else if (target_type == TypeManager.float_type)
1306 return new FloatConstant ((float) value);
1308 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1309 Type underlying = TypeManager.EnumToUnderlying (target_type);
1310 Constant e = (Constant) ic;
1313 // Possibly, we need to create a different 0 literal before passing
1316 if (underlying == TypeManager.int64_type)
1317 e = new LongLiteral (0);
1318 else if (underlying == TypeManager.uint64_type)
1319 e = new ULongLiteral (0);
1321 return new EnumConstant (e, target_type);
1326 static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
1328 Report.Error (29, loc, "Cannot convert implicitly from {0} to `{1}'",
1329 source == TypeManager.anonymous_method_type ?
1330 "anonymous method" : "`" + TypeManager.CSharpName (source) + "'",
1331 TypeManager.CSharpName (target));
1335 /// Attemptes to implicityly convert `target' into `type', using
1336 /// ImplicitConversion. If there is no implicit conversion, then
1337 /// an error is signaled
1339 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1340 Type target_type, Location loc)
1344 int errors = Report.Errors;
1345 e = ImplicitConversion (ec, source, target_type, loc);
1346 if (Report.Errors > errors)
1351 if (source is DoubleLiteral && target_type == TypeManager.float_type){
1352 Report.Error (664, loc,
1353 "Double literal cannot be implicitly converted to " +
1354 "float type, use F suffix to create a float literal");
1357 if (source is Constant){
1358 Constant c = (Constant) source;
1360 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
1364 Error_CannotImplicitConversion (loc, source.Type, target_type);
1370 /// Performs the explicit numeric conversions
1372 static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
1374 Type expr_type = expr.Type;
1377 // If we have an enumeration, extract the underlying type,
1378 // use this during the comparison, but wrap around the original
1381 Type real_target_type = target_type;
1383 if (TypeManager.IsEnumType (real_target_type))
1384 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
1386 if (ImplicitStandardConversionExists (ec, expr, real_target_type)){
1387 Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc);
1389 if (real_target_type != target_type)
1390 return new EmptyCast (ce, target_type);
1394 if (expr_type == TypeManager.sbyte_type){
1396 // From sbyte to byte, ushort, uint, ulong, char
1398 if (real_target_type == TypeManager.byte_type)
1399 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
1400 if (real_target_type == TypeManager.ushort_type)
1401 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
1402 if (real_target_type == TypeManager.uint32_type)
1403 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
1404 if (real_target_type == TypeManager.uint64_type)
1405 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
1406 if (real_target_type == TypeManager.char_type)
1407 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
1408 } else if (expr_type == TypeManager.byte_type){
1410 // From byte to sbyte and char
1412 if (real_target_type == TypeManager.sbyte_type)
1413 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
1414 if (real_target_type == TypeManager.char_type)
1415 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
1416 } else if (expr_type == TypeManager.short_type){
1418 // From short to sbyte, byte, ushort, uint, ulong, char
1420 if (real_target_type == TypeManager.sbyte_type)
1421 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1422 if (real_target_type == TypeManager.byte_type)
1423 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1424 if (real_target_type == TypeManager.ushort_type)
1425 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
1426 if (real_target_type == TypeManager.uint32_type)
1427 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
1428 if (real_target_type == TypeManager.uint64_type)
1429 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
1430 if (real_target_type == TypeManager.char_type)
1431 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
1432 } else if (expr_type == TypeManager.ushort_type){
1434 // From ushort to sbyte, byte, short, char
1436 if (real_target_type == TypeManager.sbyte_type)
1437 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
1438 if (real_target_type == TypeManager.byte_type)
1439 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1440 if (real_target_type == TypeManager.short_type)
1441 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
1442 if (real_target_type == TypeManager.char_type)
1443 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
1444 } else if (expr_type == TypeManager.int32_type){
1446 // From int to sbyte, byte, short, ushort, uint, ulong, char
1448 if (real_target_type == TypeManager.sbyte_type)
1449 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1450 if (real_target_type == TypeManager.byte_type)
1451 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1452 if (real_target_type == TypeManager.short_type)
1453 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1454 if (real_target_type == TypeManager.ushort_type)
1455 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1456 if (real_target_type == TypeManager.uint32_type)
1457 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
1458 if (real_target_type == TypeManager.uint64_type)
1459 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
1460 if (real_target_type == TypeManager.char_type)
1461 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
1462 } else if (expr_type == TypeManager.uint32_type){
1464 // From uint to sbyte, byte, short, ushort, int, char
1466 if (real_target_type == TypeManager.sbyte_type)
1467 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
1468 if (real_target_type == TypeManager.byte_type)
1469 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1470 if (real_target_type == TypeManager.short_type)
1471 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
1472 if (real_target_type == TypeManager.ushort_type)
1473 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1474 if (real_target_type == TypeManager.int32_type)
1475 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
1476 if (real_target_type == TypeManager.char_type)
1477 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
1478 } else if (expr_type == TypeManager.int64_type){
1480 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1482 if (real_target_type == TypeManager.sbyte_type)
1483 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1484 if (real_target_type == TypeManager.byte_type)
1485 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1486 if (real_target_type == TypeManager.short_type)
1487 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1488 if (real_target_type == TypeManager.ushort_type)
1489 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1490 if (real_target_type == TypeManager.int32_type)
1491 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1492 if (real_target_type == TypeManager.uint32_type)
1493 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
1494 if (real_target_type == TypeManager.uint64_type)
1495 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
1496 if (real_target_type == TypeManager.char_type)
1497 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
1498 } else if (expr_type == TypeManager.uint64_type){
1500 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1502 if (real_target_type == TypeManager.sbyte_type)
1503 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
1504 if (real_target_type == TypeManager.byte_type)
1505 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1506 if (real_target_type == TypeManager.short_type)
1507 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
1508 if (real_target_type == TypeManager.ushort_type)
1509 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1510 if (real_target_type == TypeManager.int32_type)
1511 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
1512 if (real_target_type == TypeManager.uint32_type)
1513 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
1514 if (real_target_type == TypeManager.int64_type)
1515 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
1516 if (real_target_type == TypeManager.char_type)
1517 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
1518 } else if (expr_type == TypeManager.char_type){
1520 // From char to sbyte, byte, short
1522 if (real_target_type == TypeManager.sbyte_type)
1523 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
1524 if (real_target_type == TypeManager.byte_type)
1525 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
1526 if (real_target_type == TypeManager.short_type)
1527 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
1528 } else if (expr_type == TypeManager.float_type){
1530 // From float to sbyte, byte, short,
1531 // ushort, int, uint, long, ulong, char
1534 if (real_target_type == TypeManager.sbyte_type)
1535 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1);
1536 if (real_target_type == TypeManager.byte_type)
1537 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1);
1538 if (real_target_type == TypeManager.short_type)
1539 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
1540 if (real_target_type == TypeManager.ushort_type)
1541 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
1542 if (real_target_type == TypeManager.int32_type)
1543 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4);
1544 if (real_target_type == TypeManager.uint32_type)
1545 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
1546 if (real_target_type == TypeManager.int64_type)
1547 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8);
1548 if (real_target_type == TypeManager.uint64_type)
1549 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
1550 if (real_target_type == TypeManager.char_type)
1551 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
1552 } else if (expr_type == TypeManager.double_type){
1554 // From double to byte, byte, short,
1555 // ushort, int, uint, long, ulong,
1556 // char, float or decimal
1558 if (real_target_type == TypeManager.sbyte_type)
1559 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
1560 if (real_target_type == TypeManager.byte_type)
1561 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1562 if (real_target_type == TypeManager.short_type)
1563 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1564 if (real_target_type == TypeManager.ushort_type)
1565 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
1566 if (real_target_type == TypeManager.int32_type)
1567 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1568 if (real_target_type == TypeManager.uint32_type)
1569 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
1570 if (real_target_type == TypeManager.int64_type)
1571 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1572 if (real_target_type == TypeManager.uint64_type)
1573 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
1574 if (real_target_type == TypeManager.char_type)
1575 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
1576 if (real_target_type == TypeManager.float_type)
1577 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
1580 // decimal is taken care of by the op_Explicit methods.
1586 /// Returns whether an explicit reference conversion can be performed
1587 /// from source_type to target_type
1589 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1591 bool target_is_type_param = target_type.IsGenericParameter;
1592 bool target_is_value_type = target_type.IsValueType;
1594 if (source_type == target_type)
1598 // From object to a generic parameter
1600 if (source_type == TypeManager.object_type && target_is_type_param)
1604 // From object to any reference type
1606 if (source_type == TypeManager.object_type && !target_is_value_type)
1610 // From any class S to any class-type T, provided S is a base class of T
1612 if (TypeManager.IsSubclassOf (target_type, source_type))
1616 // From any interface type S to any interface T provided S is not derived from T
1618 if (source_type.IsInterface && target_type.IsInterface){
1619 if (!TypeManager.IsSubclassOf (target_type, source_type))
1624 // From any class type S to any interface T, provided S is not sealed
1625 // and provided S does not implement T.
1627 if (target_type.IsInterface && !source_type.IsSealed &&
1628 !TypeManager.ImplementsInterface (source_type, target_type))
1632 // From any interface-type S to to any class type T, provided T is not
1633 // sealed, or provided T implements S.
1635 if (source_type.IsInterface &&
1636 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1640 // From an array type S with an element type Se to an array type T with an
1641 // element type Te provided all the following are true:
1642 // * S and T differe only in element type, in other words, S and T
1643 // have the same number of dimensions.
1644 // * Both Se and Te are reference types
1645 // * An explicit referenc conversions exist from Se to Te
1647 if (source_type.IsArray && target_type.IsArray) {
1648 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1650 Type source_element_type = TypeManager.GetElementType (source_type);
1651 Type target_element_type = TypeManager.GetElementType (target_type);
1653 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1654 if (ExplicitReferenceConversionExists (source_element_type,
1655 target_element_type))
1661 // From System.Array to any array-type
1662 if (source_type == TypeManager.array_type &&
1663 target_type.IsArray){
1668 // From System delegate to any delegate-type
1670 if (source_type == TypeManager.delegate_type &&
1671 TypeManager.IsDelegateType (target_type))
1675 // From ICloneable to Array or Delegate types
1677 if (source_type == TypeManager.icloneable_type &&
1678 (target_type == TypeManager.array_type ||
1679 target_type == TypeManager.delegate_type))
1686 /// Implements Explicit Reference conversions
1688 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1690 Type source_type = source.Type;
1691 bool target_is_type_param = target_type.IsGenericParameter;
1692 bool target_is_value_type = target_type.IsValueType;
1695 // From object to a generic parameter
1697 if (source_type == TypeManager.object_type && target_is_type_param)
1698 return new UnboxCast (source, target_type);
1701 // From object to any reference type
1703 if (source_type == TypeManager.object_type && !target_is_value_type)
1704 return new ClassCast (source, target_type);
1707 // Unboxing conversion.
1709 if (((source_type == TypeManager.enum_type &&
1710 !(source is EmptyCast)) ||
1711 source_type == TypeManager.value_type) && target_is_value_type)
1712 return new UnboxCast (source, target_type);
1715 // From any class S to any class-type T, provided S is a base class of T
1717 if (TypeManager.IsSubclassOf (target_type, source_type))
1718 return new ClassCast (source, target_type);
1721 // From any interface type S to any interface T provided S is not derived from T
1723 if (source_type.IsInterface && target_type.IsInterface){
1724 if (TypeManager.ImplementsInterface (source_type, target_type))
1727 return new ClassCast (source, target_type);
1731 // From any class type S to any interface T, provides S is not sealed
1732 // and provided S does not implement T.
1734 if (target_type.IsInterface && !source_type.IsSealed) {
1735 if (TypeManager.ImplementsInterface (source_type, target_type))
1738 return new ClassCast (source, target_type);
1743 // From any interface-type S to to any class type T, provided T is not
1744 // sealed, or provided T implements S.
1746 if (source_type.IsInterface) {
1747 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1748 if (target_type.IsClass)
1749 return new ClassCast (source, target_type);
1751 return new UnboxCast (source, target_type);
1757 // From an array type S with an element type Se to an array type T with an
1758 // element type Te provided all the following are true:
1759 // * S and T differe only in element type, in other words, S and T
1760 // have the same number of dimensions.
1761 // * Both Se and Te are reference types
1762 // * An explicit referenc conversions exist from Se to Te
1764 if (source_type.IsArray && target_type.IsArray) {
1765 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1767 Type source_element_type = TypeManager.GetElementType (source_type);
1768 Type target_element_type = TypeManager.GetElementType (target_type);
1770 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1771 if (ExplicitReferenceConversionExists (source_element_type,
1772 target_element_type))
1773 return new ClassCast (source, target_type);
1778 // From System.Array to any array-type
1779 if (source_type == TypeManager.array_type &&
1780 target_type.IsArray) {
1781 return new ClassCast (source, target_type);
1785 // From System delegate to any delegate-type
1787 if (source_type == TypeManager.delegate_type &&
1788 TypeManager.IsDelegateType (target_type))
1789 return new ClassCast (source, target_type);
1792 // From ICloneable to Array or Delegate types
1794 if (source_type == TypeManager.icloneable_type &&
1795 (target_type == TypeManager.array_type ||
1796 target_type == TypeManager.delegate_type))
1797 return new ClassCast (source, target_type);
1803 /// Performs an explicit conversion of the expression `expr' whose
1804 /// type is expr.Type to `target_type'.
1806 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1807 Type target_type, Location loc)
1809 Type expr_type = expr.Type;
1810 Type original_expr_type = expr_type;
1812 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
1813 if (target_type == TypeManager.enum_type ||
1814 target_type == TypeManager.object_type) {
1815 if (expr is EnumConstant)
1816 expr = ((EnumConstant) expr).Child;
1817 // We really need all these casts here .... :-(
1818 expr = new BoxedCast (new EmptyCast (expr, expr_type));
1819 return new EmptyCast (expr, target_type);
1820 } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
1821 target_type.IsSubclassOf (TypeManager.enum_type))
1822 return new UnboxCast (expr, target_type);
1825 // Notice that we have kept the expr_type unmodified, which is only
1827 if (expr is EnumConstant)
1828 expr = ((EnumConstant) expr).Child;
1830 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
1831 expr_type = expr.Type;
1834 int errors = Report.Errors;
1835 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1836 if (Report.Errors > errors)
1842 ne = ExplicitNumericConversion (ec, expr, target_type, loc);
1847 // Unboxing conversion.
1849 if (expr_type == TypeManager.object_type && target_type.IsValueType)
1850 return new UnboxCast (expr, target_type);
1853 // Skip the ExplicitReferenceConversion because we can not convert
1854 // from Null to a ValueType, and ExplicitReference wont check against
1855 // null literal explicitly
1857 if (expr_type != TypeManager.null_type){
1858 ne = ExplicitReferenceConversion (expr, target_type);
1865 if (target_type.IsPointer){
1866 if (expr_type.IsPointer)
1867 return new EmptyCast (expr, target_type);
1869 if (expr_type == TypeManager.sbyte_type ||
1870 expr_type == TypeManager.byte_type ||
1871 expr_type == TypeManager.short_type ||
1872 expr_type == TypeManager.ushort_type ||
1873 expr_type == TypeManager.int32_type ||
1874 expr_type == TypeManager.uint32_type ||
1875 expr_type == TypeManager.uint64_type ||
1876 expr_type == TypeManager.int64_type)
1877 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1879 if (expr_type.IsPointer){
1880 Expression e = null;
1882 if (target_type == TypeManager.sbyte_type)
1883 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1884 else if (target_type == TypeManager.byte_type)
1885 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1886 else if (target_type == TypeManager.short_type)
1887 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1888 else if (target_type == TypeManager.ushort_type)
1889 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1890 else if (target_type == TypeManager.int32_type)
1891 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1892 else if (target_type == TypeManager.uint32_type)
1893 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1894 else if (target_type == TypeManager.uint64_type)
1895 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1896 else if (target_type == TypeManager.int64_type){
1897 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1903 ci = ImplicitConversionStandard (ec, e, target_type, loc);
1908 ce = ExplicitNumericConversion (ec, e, target_type, loc);
1912 // We should always be able to go from an uint32
1913 // implicitly or explicitly to the other integral
1916 throw new Exception ("Internal compiler error");
1921 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1925 if (expr is NullLiteral){
1926 Report.Error (37, loc, "Cannot convert null to value type `" +
1927 TypeManager.CSharpName (target_type) + "'");
1931 Error_CannotConvertType (loc, original_expr_type, target_type);
1936 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1938 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1939 Type target_type, Location l)
1941 int errors = Report.Errors;
1942 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1943 if (Report.Errors > errors)
1949 ne = ExplicitNumericConversion (ec, expr, target_type, l);
1953 ne = ExplicitReferenceConversion (expr, target_type);
1957 Error_CannotConvertType (l, expr.Type, target_type);