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 {
22 static void Error_CannotConvertType (Location loc, Type source, Type target)
24 Report.Error (30, loc, "Cannot convert type '" +
25 TypeManager.CSharpName (source) + "' to '" +
26 TypeManager.CSharpName (target) + "'");
29 static Expression TypeParameter_to_Null (Expression expr, Type target_type,
32 if (!TypeParameter_to_Null (target_type)) {
33 Report.Error (403, loc, "Cannot convert null to the type " +
34 "parameter `{0}' becaues it could be a value " +
35 "type. Consider using `default ({0})' instead.",
40 return new NullCast (expr, target_type);
43 static bool TypeParameter_to_Null (Type target_type)
45 if ((target_type.BaseType == null) ||
46 (target_type.BaseType == TypeManager.value_type) ||
47 target_type.BaseType.IsValueType)
53 static EmptyExpression MyEmptyExpr;
54 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
56 Type expr_type = expr.Type;
58 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
59 // if we are a method group, emit a warning
64 if (expr_type == TypeManager.void_type)
68 // notice that it is possible to write "ValueType v = 1", the ValueType here
69 // is an abstract class, and not really a value type, so we apply the same rules.
71 if (target_type == TypeManager.object_type) {
73 // A pointer type cannot be converted to object
75 if (expr_type.IsPointer)
78 if (TypeManager.IsValueType (expr_type))
79 return new BoxedCast (expr);
80 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type)
81 return new EmptyCast (expr, target_type);
82 } else if (target_type == TypeManager.value_type) {
83 if (TypeManager.IsValueType (expr_type))
84 return new BoxedCast (expr);
85 if (expr is NullLiteral)
86 return new NullCast (expr, target_type);
87 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
89 // Special case: enumeration to System.Enum.
90 // System.Enum is not a value type, it is a class, so we need
91 // a boxing conversion
93 if (expr_type.IsEnum || expr_type.IsGenericParameter)
94 return new BoxedCast (expr);
96 return new EmptyCast (expr, target_type);
99 // This code is kind of mirrored inside ImplicitStandardConversionExists
100 // with the small distinction that we only probe there
102 // Always ensure that the code here and there is in sync
104 // from the null type to any reference-type.
105 if (expr is NullLiteral){
106 if (target_type.IsPointer)
107 return NullPointer.Null;
109 if (!target_type.IsValueType)
110 return new NullCast (expr, target_type);
113 // from any class-type S to any interface-type T.
114 if (target_type.IsInterface) {
115 if (TypeManager.ImplementsInterface (expr_type, target_type)){
116 if (expr_type.IsGenericParameter)
117 return new BoxedCast (expr, target_type);
118 else if (expr_type.IsClass)
119 return new EmptyCast (expr, target_type);
120 else if (TypeManager.IsValueType (expr_type) ||
121 TypeManager.IsEnumType (expr_type))
122 return new BoxedCast (expr, target_type);
124 return new EmptyCast (expr, target_type);
128 // from any interface type S to interface-type T.
129 if (expr_type.IsInterface && target_type.IsInterface) {
130 if (TypeManager.ImplementsInterface (expr_type, target_type))
131 return new EmptyCast (expr, target_type);
136 // from an array-type S to an array-type of type T
137 if (expr_type.IsArray && target_type.IsArray) {
138 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
140 Type expr_element_type = TypeManager.GetElementType (expr_type);
142 if (MyEmptyExpr == null)
143 MyEmptyExpr = new EmptyExpression ();
145 MyEmptyExpr.SetType (expr_element_type);
146 Type target_element_type = TypeManager.GetElementType (target_type);
148 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
149 if (ImplicitStandardConversionExists (MyEmptyExpr,
150 target_element_type))
151 return new EmptyCast (expr, target_type);
156 // from an array-type to System.Array
157 if (expr_type.IsArray && target_type == TypeManager.array_type)
158 return new EmptyCast (expr, target_type);
160 // from any delegate type to System.Delegate
161 if ((expr_type == TypeManager.delegate_type ||
162 TypeManager.IsDelegateType (expr_type)) &&
163 target_type == TypeManager.delegate_type)
164 return new EmptyCast (expr, target_type);
166 // from any array-type or delegate type into System.ICloneable.
167 if (expr_type.IsArray ||
168 expr_type == TypeManager.delegate_type ||
169 TypeManager.IsDelegateType (expr_type))
170 if (target_type == TypeManager.icloneable_type)
171 return new EmptyCast (expr, target_type);
173 // from a generic type definition to a generic instance.
174 if (TypeManager.IsEqualGenericType (expr_type, target_type))
175 return new EmptyCast (expr, target_type);
185 // Tests whether an implicit reference conversion exists between expr_type
188 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
190 Type expr_type = expr.Type;
193 // This is the boxed case.
195 if (target_type == TypeManager.object_type) {
196 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
197 expr_type.IsInterface || expr_type == TypeManager.enum_type)
199 } else if (TypeManager.IsSubclassOf (expr_type, target_type))
202 // Please remember that all code below actually comes
203 // from ImplicitReferenceConversion so make sure code remains in sync
205 // from any class-type S to any interface-type T.
206 if (target_type.IsInterface) {
207 if (TypeManager.ImplementsInterface (expr_type, target_type))
211 // from any interface type S to interface-type T.
212 if (expr_type.IsInterface && target_type.IsInterface)
213 if (TypeManager.ImplementsInterface (expr_type, target_type))
216 // from an array-type S to an array-type of type T
217 if (expr_type.IsArray && target_type.IsArray) {
218 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
220 Type expr_element_type = expr_type.GetElementType ();
222 if (MyEmptyExpr == null)
223 MyEmptyExpr = new EmptyExpression ();
225 MyEmptyExpr.SetType (expr_element_type);
226 Type target_element_type = TypeManager.GetElementType (target_type);
228 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
229 if (ImplicitStandardConversionExists (MyEmptyExpr,
230 target_element_type))
235 // from an array-type to System.Array
236 if (expr_type.IsArray && (target_type == TypeManager.array_type))
239 // from any delegate type to System.Delegate
240 if ((expr_type == TypeManager.delegate_type ||
241 TypeManager.IsDelegateType (expr_type)) &&
242 target_type == TypeManager.delegate_type)
243 if (target_type.IsAssignableFrom (expr_type))
246 // from any array-type or delegate type into System.ICloneable.
247 if (expr_type.IsArray ||
248 expr_type == TypeManager.delegate_type ||
249 TypeManager.IsDelegateType (expr_type))
250 if (target_type == TypeManager.icloneable_type)
253 // from the null type to any reference-type.
254 if (expr is NullLiteral && !target_type.IsValueType &&
255 !TypeManager.IsEnumType (target_type))
258 // from a generic type definition to a generic instance.
259 if (TypeManager.IsEqualGenericType (expr_type, target_type))
266 /// Implicit Numeric Conversions.
268 /// expr is the expression to convert, returns a new expression of type
269 /// target_type or null if an implicit conversion is not possible.
271 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
272 Type target_type, Location loc)
274 Type expr_type = expr.Type;
277 // Attempt to do the implicit constant expression conversions
279 if (expr is Constant){
280 if (expr is IntConstant){
283 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
287 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
289 // Try the implicit constant expression conversion
290 // from long to ulong, instead of a nice routine,
293 long v = ((LongConstant) expr).Value;
295 return new ULongConstant ((ulong) v);
299 Type real_target_type = target_type;
301 if (expr_type == TypeManager.sbyte_type){
303 // From sbyte to short, int, long, float, double.
305 if (real_target_type == TypeManager.int32_type)
306 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
307 if (real_target_type == TypeManager.int64_type)
308 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
309 if (real_target_type == TypeManager.double_type)
310 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
311 if (real_target_type == TypeManager.float_type)
312 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
313 if (real_target_type == TypeManager.short_type)
314 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
315 } else if (expr_type == TypeManager.byte_type){
317 // From byte to short, ushort, int, uint, long, ulong, float, double
319 if ((real_target_type == TypeManager.short_type) ||
320 (real_target_type == TypeManager.ushort_type) ||
321 (real_target_type == TypeManager.int32_type) ||
322 (real_target_type == TypeManager.uint32_type))
323 return new EmptyCast (expr, target_type);
325 if (real_target_type == TypeManager.uint64_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
327 if (real_target_type == TypeManager.int64_type)
328 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
329 if (real_target_type == TypeManager.float_type)
330 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
331 if (real_target_type == TypeManager.double_type)
332 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
333 } else if (expr_type == TypeManager.short_type){
335 // From short to int, long, float, double
337 if (real_target_type == TypeManager.int32_type)
338 return new EmptyCast (expr, target_type);
339 if (real_target_type == TypeManager.int64_type)
340 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
341 if (real_target_type == TypeManager.double_type)
342 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
343 if (real_target_type == TypeManager.float_type)
344 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
345 } else if (expr_type == TypeManager.ushort_type){
347 // From ushort to int, uint, long, ulong, float, double
349 if (real_target_type == TypeManager.uint32_type)
350 return new EmptyCast (expr, target_type);
352 if (real_target_type == TypeManager.uint64_type)
353 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
354 if (real_target_type == TypeManager.int32_type)
355 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
356 if (real_target_type == TypeManager.int64_type)
357 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
358 if (real_target_type == TypeManager.double_type)
359 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
360 if (real_target_type == TypeManager.float_type)
361 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
362 } else if (expr_type == TypeManager.int32_type){
364 // From int to long, float, double
366 if (real_target_type == TypeManager.int64_type)
367 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
368 if (real_target_type == TypeManager.double_type)
369 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
370 if (real_target_type == TypeManager.float_type)
371 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
372 } else if (expr_type == TypeManager.uint32_type){
374 // From uint to long, ulong, float, double
376 if (real_target_type == TypeManager.int64_type)
377 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
378 if (real_target_type == TypeManager.uint64_type)
379 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
380 if (real_target_type == TypeManager.double_type)
381 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
383 if (real_target_type == TypeManager.float_type)
384 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
386 } else if (expr_type == TypeManager.int64_type){
388 // From long/ulong to float, double
390 if (real_target_type == TypeManager.double_type)
391 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
392 if (real_target_type == TypeManager.float_type)
393 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
394 } else if (expr_type == TypeManager.uint64_type){
396 // From ulong to float, double
398 if (real_target_type == TypeManager.double_type)
399 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
401 if (real_target_type == TypeManager.float_type)
402 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
404 } else if (expr_type == TypeManager.char_type){
406 // From char to ushort, int, uint, long, ulong, float, double
408 if ((real_target_type == TypeManager.ushort_type) ||
409 (real_target_type == TypeManager.int32_type) ||
410 (real_target_type == TypeManager.uint32_type))
411 return new EmptyCast (expr, target_type);
412 if (real_target_type == TypeManager.uint64_type)
413 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
414 if (real_target_type == TypeManager.int64_type)
415 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
416 if (real_target_type == TypeManager.float_type)
417 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
418 if (real_target_type == TypeManager.double_type)
419 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
420 } else if (expr_type == TypeManager.float_type){
424 if (real_target_type == TypeManager.double_type)
425 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
433 /// Same as ImplicitStandardConversionExists except that it also looks at
434 /// implicit user defined conversions - needed for overload resolution
436 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
438 if ((expr is NullLiteral) && target_type.IsGenericParameter)
439 return TypeParameter_to_Null (target_type);
441 if (ImplicitStandardConversionExists (expr, target_type))
444 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
452 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
454 Expression dummy = ImplicitUserConversion (
455 ec, new EmptyExpression (source), target, Location.Null);
456 return dummy != null;
460 /// Determines if a standard implicit conversion exists from
461 /// expr_type to target_type
463 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
465 Type expr_type = expr.Type;
467 if (expr_type == TypeManager.void_type)
470 //Console.WriteLine ("Expr is {0}", expr);
471 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
472 if (expr_type.Equals (target_type))
475 // First numeric conversions
477 if (expr_type == TypeManager.sbyte_type){
479 // From sbyte to short, int, long, float, double.
481 if ((target_type == TypeManager.int32_type) ||
482 (target_type == TypeManager.int64_type) ||
483 (target_type == TypeManager.double_type) ||
484 (target_type == TypeManager.float_type) ||
485 (target_type == TypeManager.short_type) ||
486 (target_type == TypeManager.decimal_type))
489 } else if (expr_type == TypeManager.byte_type){
491 // From byte to short, ushort, int, uint, long, ulong, float, double
493 if ((target_type == TypeManager.short_type) ||
494 (target_type == TypeManager.ushort_type) ||
495 (target_type == TypeManager.int32_type) ||
496 (target_type == TypeManager.uint32_type) ||
497 (target_type == TypeManager.uint64_type) ||
498 (target_type == TypeManager.int64_type) ||
499 (target_type == TypeManager.float_type) ||
500 (target_type == TypeManager.double_type) ||
501 (target_type == TypeManager.decimal_type))
504 } else if (expr_type == TypeManager.short_type){
506 // From short to int, long, float, double
508 if ((target_type == TypeManager.int32_type) ||
509 (target_type == TypeManager.int64_type) ||
510 (target_type == TypeManager.double_type) ||
511 (target_type == TypeManager.float_type) ||
512 (target_type == TypeManager.decimal_type))
515 } else if (expr_type == TypeManager.ushort_type){
517 // From ushort to int, uint, long, ulong, float, double
519 if ((target_type == TypeManager.uint32_type) ||
520 (target_type == TypeManager.uint64_type) ||
521 (target_type == TypeManager.int32_type) ||
522 (target_type == TypeManager.int64_type) ||
523 (target_type == TypeManager.double_type) ||
524 (target_type == TypeManager.float_type) ||
525 (target_type == TypeManager.decimal_type))
528 } else if (expr_type == TypeManager.int32_type){
530 // From int to long, float, double
532 if ((target_type == TypeManager.int64_type) ||
533 (target_type == TypeManager.double_type) ||
534 (target_type == TypeManager.float_type) ||
535 (target_type == TypeManager.decimal_type))
538 } else if (expr_type == TypeManager.uint32_type){
540 // From uint to long, ulong, float, double
542 if ((target_type == TypeManager.int64_type) ||
543 (target_type == TypeManager.uint64_type) ||
544 (target_type == TypeManager.double_type) ||
545 (target_type == TypeManager.float_type) ||
546 (target_type == TypeManager.decimal_type))
549 } else if ((expr_type == TypeManager.uint64_type) ||
550 (expr_type == TypeManager.int64_type)) {
552 // From long/ulong to float, double
554 if ((target_type == TypeManager.double_type) ||
555 (target_type == TypeManager.float_type) ||
556 (target_type == TypeManager.decimal_type))
559 } else if (expr_type == TypeManager.char_type){
561 // From char to ushort, int, uint, long, ulong, float, double
563 if ((target_type == TypeManager.ushort_type) ||
564 (target_type == TypeManager.int32_type) ||
565 (target_type == TypeManager.uint32_type) ||
566 (target_type == TypeManager.uint64_type) ||
567 (target_type == TypeManager.int64_type) ||
568 (target_type == TypeManager.float_type) ||
569 (target_type == TypeManager.double_type) ||
570 (target_type == TypeManager.decimal_type))
573 } else if (expr_type == TypeManager.float_type){
577 if (target_type == TypeManager.double_type)
581 if (ImplicitReferenceConversionExists (expr, target_type))
585 // Implicit Constant Expression Conversions
587 if (expr is IntConstant){
588 int value = ((IntConstant) expr).Value;
590 if (target_type == TypeManager.sbyte_type){
591 if (value >= SByte.MinValue && value <= SByte.MaxValue)
593 } else if (target_type == TypeManager.byte_type){
594 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
596 } else if (target_type == TypeManager.short_type){
597 if (value >= Int16.MinValue && value <= Int16.MaxValue)
599 } else if (target_type == TypeManager.ushort_type){
600 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
602 } else if (target_type == TypeManager.uint32_type){
605 } else if (target_type == TypeManager.uint64_type){
607 // we can optimize this case: a positive int32
608 // always fits on a uint64. But we need an opcode
615 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
619 if (expr is LongConstant && target_type == TypeManager.uint64_type){
621 // Try the implicit constant expression conversion
622 // from long to ulong, instead of a nice routine,
625 long v = ((LongConstant) expr).Value;
630 if ((target_type == TypeManager.enum_type ||
631 target_type.IsSubclassOf (TypeManager.enum_type)) &&
633 IntLiteral i = (IntLiteral) expr;
639 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
646 // Used internally by FindMostEncompassedType, this is used
647 // to avoid creating lots of objects in the tight loop inside
648 // FindMostEncompassedType
650 static EmptyExpression priv_fmet_param;
653 /// Finds "most encompassed type" according to the spec (13.4.2)
654 /// amongst the methods in the MethodGroupExpr
656 static Type FindMostEncompassedType (ArrayList types)
660 if (priv_fmet_param == null)
661 priv_fmet_param = new EmptyExpression ();
663 foreach (Type t in types){
664 priv_fmet_param.SetType (t);
671 if (ImplicitStandardConversionExists (priv_fmet_param, best))
679 // Used internally by FindMostEncompassingType, this is used
680 // to avoid creating lots of objects in the tight loop inside
681 // FindMostEncompassingType
683 static EmptyExpression priv_fmee_ret;
686 /// Finds "most encompassing type" according to the spec (13.4.2)
687 /// amongst the types in the given set
689 static Type FindMostEncompassingType (ArrayList types)
693 if (priv_fmee_ret == null)
694 priv_fmee_ret = new EmptyExpression ();
696 foreach (Type t in types){
697 priv_fmee_ret.SetType (best);
704 if (ImplicitStandardConversionExists (priv_fmee_ret, t))
712 // Used to avoid creating too many objects
714 static EmptyExpression priv_fms_expr;
717 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
718 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
719 /// for explicit and implicit conversion operators.
721 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
722 bool apply_explicit_conv_rules,
725 ArrayList src_types_set = new ArrayList ();
727 if (priv_fms_expr == null)
728 priv_fms_expr = new EmptyExpression ();
731 // If any operator converts from S then Sx = S
733 Type source_type = source.Type;
734 foreach (MethodBase mb in me.Methods){
735 ParameterData pd = Invocation.GetParameterData (mb);
736 Type param_type = pd.ParameterType (0);
738 if (param_type == source_type)
741 if (apply_explicit_conv_rules) {
744 // Find the set of applicable user-defined conversion operators, U. This set
746 // user-defined implicit or explicit conversion operators declared by
747 // the classes or structs in D that convert from a type encompassing
748 // or encompassed by S to a type encompassing or encompassed by T
750 priv_fms_expr.SetType (param_type);
751 if (ImplicitStandardConversionExists (priv_fms_expr, source_type))
752 src_types_set.Add (param_type);
754 if (ImplicitStandardConversionExists (source, param_type))
755 src_types_set.Add (param_type);
759 // Only if S is encompassed by param_type
761 if (ImplicitStandardConversionExists (source, param_type))
762 src_types_set.Add (param_type);
767 // Explicit Conv rules
769 if (apply_explicit_conv_rules) {
770 ArrayList candidate_set = new ArrayList ();
772 foreach (Type param_type in src_types_set){
773 if (ImplicitStandardConversionExists (source, param_type))
774 candidate_set.Add (param_type);
777 if (candidate_set.Count != 0)
778 return FindMostEncompassedType (candidate_set);
784 if (apply_explicit_conv_rules)
785 return FindMostEncompassingType (src_types_set);
787 return FindMostEncompassedType (src_types_set);
791 // Useful in avoiding proliferation of objects
793 static EmptyExpression priv_fmt_expr;
796 /// Finds the most specific target Tx according to section 13.4.4
798 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
799 bool apply_explicit_conv_rules,
802 ArrayList tgt_types_set = new ArrayList ();
804 if (priv_fmt_expr == null)
805 priv_fmt_expr = new EmptyExpression ();
808 // If any operator converts to T then Tx = T
810 foreach (MethodInfo mi in me.Methods){
811 Type ret_type = mi.ReturnType;
813 if (ret_type == target)
816 if (apply_explicit_conv_rules) {
819 // Find the set of applicable user-defined conversion operators, U.
821 // This set consists of the
822 // user-defined implicit or explicit conversion operators declared by
823 // the classes or structs in D that convert from a type encompassing
824 // or encompassed by S to a type encompassing or encompassed by T
826 priv_fms_expr.SetType (ret_type);
827 if (ImplicitStandardConversionExists (priv_fms_expr, target))
828 tgt_types_set.Add (ret_type);
830 priv_fms_expr.SetType (target);
831 if (ImplicitStandardConversionExists (priv_fms_expr, ret_type))
832 tgt_types_set.Add (ret_type);
836 // Only if T is encompassed by param_type
838 priv_fms_expr.SetType (ret_type);
839 if (ImplicitStandardConversionExists (priv_fms_expr, target))
840 tgt_types_set.Add (ret_type);
845 // Explicit conv rules
847 if (apply_explicit_conv_rules) {
848 ArrayList candidate_set = new ArrayList ();
850 foreach (Type ret_type in tgt_types_set){
851 priv_fmt_expr.SetType (ret_type);
853 if (ImplicitStandardConversionExists (priv_fmt_expr, target))
854 candidate_set.Add (ret_type);
857 if (candidate_set.Count != 0)
858 return FindMostEncompassingType (candidate_set);
862 // Okay, final case !
864 if (apply_explicit_conv_rules)
865 return FindMostEncompassedType (tgt_types_set);
867 return FindMostEncompassingType (tgt_types_set);
871 /// User-defined Implicit conversions
873 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
874 Type target, Location loc)
876 return UserDefinedConversion (ec, source, target, loc, false);
880 /// User-defined Explicit conversions
882 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
883 Type target, Location loc)
885 return UserDefinedConversion (ec, source, target, loc, true);
889 /// Computes the MethodGroup for the user-defined conversion
890 /// operators from source_type to target_type. `look_for_explicit'
891 /// controls whether we should also include the list of explicit
894 static MethodGroupExpr GetConversionOperators (EmitContext ec,
895 Type source_type, Type target_type,
896 Location loc, bool look_for_explicit)
898 Expression mg1 = null, mg2 = null;
899 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
902 op_name = "op_Implicit";
904 MethodGroupExpr union3;
906 mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
907 if (source_type.BaseType != null)
908 mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
911 union3 = (MethodGroupExpr) mg2;
912 else if (mg2 == null)
913 union3 = (MethodGroupExpr) mg1;
915 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
917 mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
920 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
922 union3 = (MethodGroupExpr) mg1;
925 if (target_type.BaseType != null)
926 mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
930 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
932 union3 = (MethodGroupExpr) mg1;
935 MethodGroupExpr union4 = null;
937 if (look_for_explicit) {
938 op_name = "op_Explicit";
940 mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
941 if (source_type.BaseType != null)
942 mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
944 mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
945 if (target_type.BaseType != null)
946 mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
948 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
949 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
951 union4 = Invocation.MakeUnionSet (union5, union6, loc);
954 return Invocation.MakeUnionSet (union3, union4, loc);
958 /// User-defined conversions
960 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
961 Type target, Location loc,
962 bool look_for_explicit)
964 MethodGroupExpr union;
965 Type source_type = source.Type;
966 MethodBase method = null;
968 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
972 Type most_specific_source, most_specific_target;
974 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
975 if (most_specific_source == null)
978 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
979 if (most_specific_target == null)
985 foreach (MethodBase mb in union.Methods){
986 ParameterData pd = Invocation.GetParameterData (mb);
987 MethodInfo mi = (MethodInfo) mb;
989 if (pd.ParameterType (0) == most_specific_source &&
990 mi.ReturnType == most_specific_target) {
996 if (method == null || count > 1)
1001 // This will do the conversion to the best match that we
1002 // found. Now we need to perform an implict standard conversion
1003 // if the best match was not the type that we were requested
1006 if (look_for_explicit)
1007 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1009 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1015 e = new UserCast ((MethodInfo) method, source, loc);
1016 if (e.Type != target){
1017 if (!look_for_explicit)
1018 e = ImplicitConversionStandard (ec, e, target, loc);
1020 e = ExplicitConversionStandard (ec, e, target, loc);
1027 /// Converts implicitly the resolved expression `expr' into the
1028 /// `target_type'. It returns a new expression that can be used
1029 /// in a context that expects a `target_type'.
1031 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1032 Type target_type, Location loc)
1036 if (target_type == null)
1037 throw new Exception ("Target type is null");
1039 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1043 e = ImplicitUserConversion (ec, expr, target_type, loc);
1052 /// Attempts to apply the `Standard Implicit
1053 /// Conversion' rules to the expression `expr' into
1054 /// the `target_type'. It returns a new expression
1055 /// that can be used in a context that expects a
1058 /// This is different from `ImplicitConversion' in that the
1059 /// user defined implicit conversions are excluded.
1061 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1062 Type target_type, Location loc)
1064 Type expr_type = expr.Type;
1067 if ((expr is NullLiteral) && target_type.IsGenericParameter)
1068 return TypeParameter_to_Null (expr, target_type, loc);
1070 if (expr.eclass == ExprClass.MethodGroup){
1071 if (!TypeManager.IsDelegateType (target_type)){
1072 Report.Error (428, loc,
1074 "Cannot convert method group to `{0}', since it is not a delegate",
1075 TypeManager.CSharpName (target_type)));
1079 return ImplicitDelegateCreation.Create (ec, (MethodGroupExpr) expr, target_type, loc);
1082 if (expr_type.Equals (target_type) && !(expr is NullLiteral))
1085 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1089 e = ImplicitReferenceConversion (expr, target_type);
1093 if ((target_type == TypeManager.enum_type ||
1094 target_type.IsSubclassOf (TypeManager.enum_type)) &&
1095 expr is IntLiteral){
1096 IntLiteral i = (IntLiteral) expr;
1099 return new EnumConstant ((Constant) expr, target_type);
1103 if (expr_type.IsPointer){
1104 if (target_type == TypeManager.void_ptr_type)
1105 return new EmptyCast (expr, target_type);
1108 // yep, comparing pointer types cant be done with
1109 // t1 == t2, we have to compare their element types.
1111 if (target_type.IsPointer){
1112 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1117 if (target_type.IsPointer) {
1118 if (expr is NullLiteral)
1119 return new EmptyCast (expr, target_type);
1121 if (expr_type == TypeManager.void_ptr_type)
1122 return new EmptyCast (expr, target_type);
1130 /// Attemps to perform an implict constant conversion of the IntConstant
1131 /// into a different data type using casts (See Implicit Constant
1132 /// Expression Conversions)
1134 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1136 int value = ic.Value;
1138 if (target_type == TypeManager.sbyte_type){
1139 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1140 return new SByteConstant ((sbyte) value);
1141 } else if (target_type == TypeManager.byte_type){
1142 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1143 return new ByteConstant ((byte) value);
1144 } else if (target_type == TypeManager.short_type){
1145 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1146 return new ShortConstant ((short) value);
1147 } else if (target_type == TypeManager.ushort_type){
1148 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1149 return new UShortConstant ((ushort) value);
1150 } else if (target_type == TypeManager.uint32_type){
1152 return new UIntConstant ((uint) value);
1153 } else if (target_type == TypeManager.uint64_type){
1155 // we can optimize this case: a positive int32
1156 // always fits on a uint64. But we need an opcode
1160 return new ULongConstant ((ulong) value);
1161 } else if (target_type == TypeManager.double_type)
1162 return new DoubleConstant ((double) value);
1163 else if (target_type == TypeManager.float_type)
1164 return new FloatConstant ((float) value);
1166 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1167 Type underlying = TypeManager.EnumToUnderlying (target_type);
1168 Constant e = (Constant) ic;
1171 // Possibly, we need to create a different 0 literal before passing
1174 if (underlying == TypeManager.int64_type)
1175 e = new LongLiteral (0);
1176 else if (underlying == TypeManager.uint64_type)
1177 e = new ULongLiteral (0);
1179 return new EnumConstant (e, target_type);
1184 static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
1186 string msg = "Cannot convert implicitly from `"+
1187 TypeManager.CSharpName (source) + "' to `" +
1188 TypeManager.CSharpName (target) + "'";
1190 Report.Error (29, loc, msg);
1194 /// Attemptes to implicityly convert `target' into `type', using
1195 /// ImplicitConversion. If there is no implicit conversion, then
1196 /// an error is signaled
1198 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1199 Type target_type, Location loc)
1203 int errors = Report.Errors;
1204 e = ImplicitConversion (ec, source, target_type, loc);
1205 if (Report.Errors > errors)
1210 if (source is DoubleLiteral && target_type == TypeManager.float_type){
1211 Report.Error (664, loc,
1212 "Double literal cannot be implicitly converted to " +
1213 "float type, use F suffix to create a float literal");
1216 if (source is Constant){
1217 Constant c = (Constant) source;
1219 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
1223 Error_CannotImplicitConversion (loc, source.Type, target_type);
1229 /// Performs the explicit numeric conversions
1231 static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
1233 Type expr_type = expr.Type;
1236 // If we have an enumeration, extract the underlying type,
1237 // use this during the comparison, but wrap around the original
1240 Type real_target_type = target_type;
1242 if (TypeManager.IsEnumType (real_target_type))
1243 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
1245 if (ImplicitStandardConversionExists (expr, real_target_type)){
1246 Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc);
1248 if (real_target_type != target_type)
1249 return new EmptyCast (ce, target_type);
1253 if (expr_type == TypeManager.sbyte_type){
1255 // From sbyte to byte, ushort, uint, ulong, char
1257 if (real_target_type == TypeManager.byte_type)
1258 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
1259 if (real_target_type == TypeManager.ushort_type)
1260 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
1261 if (real_target_type == TypeManager.uint32_type)
1262 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
1263 if (real_target_type == TypeManager.uint64_type)
1264 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
1265 if (real_target_type == TypeManager.char_type)
1266 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
1267 } else if (expr_type == TypeManager.byte_type){
1269 // From byte to sbyte and char
1271 if (real_target_type == TypeManager.sbyte_type)
1272 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
1273 if (real_target_type == TypeManager.char_type)
1274 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
1275 } else if (expr_type == TypeManager.short_type){
1277 // From short to sbyte, byte, ushort, uint, ulong, char
1279 if (real_target_type == TypeManager.sbyte_type)
1280 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1281 if (real_target_type == TypeManager.byte_type)
1282 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1283 if (real_target_type == TypeManager.ushort_type)
1284 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
1285 if (real_target_type == TypeManager.uint32_type)
1286 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
1287 if (real_target_type == TypeManager.uint64_type)
1288 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
1289 if (real_target_type == TypeManager.char_type)
1290 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
1291 } else if (expr_type == TypeManager.ushort_type){
1293 // From ushort to sbyte, byte, short, char
1295 if (real_target_type == TypeManager.sbyte_type)
1296 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
1297 if (real_target_type == TypeManager.byte_type)
1298 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1299 if (real_target_type == TypeManager.short_type)
1300 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
1301 if (real_target_type == TypeManager.char_type)
1302 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
1303 } else if (expr_type == TypeManager.int32_type){
1305 // From int to sbyte, byte, short, ushort, uint, ulong, char
1307 if (real_target_type == TypeManager.sbyte_type)
1308 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1309 if (real_target_type == TypeManager.byte_type)
1310 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1311 if (real_target_type == TypeManager.short_type)
1312 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1313 if (real_target_type == TypeManager.ushort_type)
1314 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1315 if (real_target_type == TypeManager.uint32_type)
1316 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
1317 if (real_target_type == TypeManager.uint64_type)
1318 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
1319 if (real_target_type == TypeManager.char_type)
1320 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
1321 } else if (expr_type == TypeManager.uint32_type){
1323 // From uint to sbyte, byte, short, ushort, int, char
1325 if (real_target_type == TypeManager.sbyte_type)
1326 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
1327 if (real_target_type == TypeManager.byte_type)
1328 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1329 if (real_target_type == TypeManager.short_type)
1330 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
1331 if (real_target_type == TypeManager.ushort_type)
1332 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1333 if (real_target_type == TypeManager.int32_type)
1334 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
1335 if (real_target_type == TypeManager.char_type)
1336 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
1337 } else if (expr_type == TypeManager.int64_type){
1339 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1341 if (real_target_type == TypeManager.sbyte_type)
1342 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1343 if (real_target_type == TypeManager.byte_type)
1344 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1345 if (real_target_type == TypeManager.short_type)
1346 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1347 if (real_target_type == TypeManager.ushort_type)
1348 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1349 if (real_target_type == TypeManager.int32_type)
1350 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1351 if (real_target_type == TypeManager.uint32_type)
1352 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
1353 if (real_target_type == TypeManager.uint64_type)
1354 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
1355 if (real_target_type == TypeManager.char_type)
1356 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
1357 } else if (expr_type == TypeManager.uint64_type){
1359 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1361 if (real_target_type == TypeManager.sbyte_type)
1362 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
1363 if (real_target_type == TypeManager.byte_type)
1364 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1365 if (real_target_type == TypeManager.short_type)
1366 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
1367 if (real_target_type == TypeManager.ushort_type)
1368 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1369 if (real_target_type == TypeManager.int32_type)
1370 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
1371 if (real_target_type == TypeManager.uint32_type)
1372 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
1373 if (real_target_type == TypeManager.int64_type)
1374 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
1375 if (real_target_type == TypeManager.char_type)
1376 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
1377 } else if (expr_type == TypeManager.char_type){
1379 // From char to sbyte, byte, short
1381 if (real_target_type == TypeManager.sbyte_type)
1382 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
1383 if (real_target_type == TypeManager.byte_type)
1384 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
1385 if (real_target_type == TypeManager.short_type)
1386 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
1387 } else if (expr_type == TypeManager.float_type){
1389 // From float to sbyte, byte, short,
1390 // ushort, int, uint, long, ulong, char
1393 if (real_target_type == TypeManager.sbyte_type)
1394 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1);
1395 if (real_target_type == TypeManager.byte_type)
1396 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1);
1397 if (real_target_type == TypeManager.short_type)
1398 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
1399 if (real_target_type == TypeManager.ushort_type)
1400 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
1401 if (real_target_type == TypeManager.int32_type)
1402 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4);
1403 if (real_target_type == TypeManager.uint32_type)
1404 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
1405 if (real_target_type == TypeManager.int64_type)
1406 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8);
1407 if (real_target_type == TypeManager.uint64_type)
1408 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
1409 if (real_target_type == TypeManager.char_type)
1410 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
1411 } else if (expr_type == TypeManager.double_type){
1413 // From double to byte, byte, short,
1414 // ushort, int, uint, long, ulong,
1415 // char, float or decimal
1417 if (real_target_type == TypeManager.sbyte_type)
1418 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
1419 if (real_target_type == TypeManager.byte_type)
1420 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1421 if (real_target_type == TypeManager.short_type)
1422 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1423 if (real_target_type == TypeManager.ushort_type)
1424 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
1425 if (real_target_type == TypeManager.int32_type)
1426 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1427 if (real_target_type == TypeManager.uint32_type)
1428 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
1429 if (real_target_type == TypeManager.int64_type)
1430 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1431 if (real_target_type == TypeManager.uint64_type)
1432 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
1433 if (real_target_type == TypeManager.char_type)
1434 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
1435 if (real_target_type == TypeManager.float_type)
1436 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
1439 // decimal is taken care of by the op_Explicit methods.
1445 /// Returns whether an explicit reference conversion can be performed
1446 /// from source_type to target_type
1448 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1450 bool target_is_type_param = target_type.IsGenericParameter;
1451 bool target_is_value_type = target_type.IsValueType;
1453 if (source_type == target_type)
1457 // From object to a generic parameter
1459 if (source_type == TypeManager.object_type && target_is_type_param)
1463 // From object to any reference type
1465 if (source_type == TypeManager.object_type && !target_is_value_type)
1469 // From any class S to any class-type T, provided S is a base class of T
1471 if (TypeManager.IsSubclassOf (target_type, source_type))
1475 // From any interface type S to any interface T provided S is not derived from T
1477 if (source_type.IsInterface && target_type.IsInterface){
1478 if (!TypeManager.IsSubclassOf (target_type, source_type))
1483 // From any class type S to any interface T, provided S is not sealed
1484 // and provided S does not implement T.
1486 if (target_type.IsInterface && !source_type.IsSealed &&
1487 !TypeManager.ImplementsInterface (source_type, target_type))
1491 // From any interface-type S to to any class type T, provided T is not
1492 // sealed, or provided T implements S.
1494 if (source_type.IsInterface &&
1495 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1499 // From an array type S with an element type Se to an array type T with an
1500 // element type Te provided all the following are true:
1501 // * S and T differe only in element type, in other words, S and T
1502 // have the same number of dimensions.
1503 // * Both Se and Te are reference types
1504 // * An explicit referenc conversions exist from Se to Te
1506 if (source_type.IsArray && target_type.IsArray) {
1507 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1509 Type source_element_type = TypeManager.GetElementType (source_type);
1510 Type target_element_type = TypeManager.GetElementType (target_type);
1512 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1513 if (ExplicitReferenceConversionExists (source_element_type,
1514 target_element_type))
1520 // From System.Array to any array-type
1521 if (source_type == TypeManager.array_type &&
1522 target_type.IsArray){
1527 // From System delegate to any delegate-type
1529 if (source_type == TypeManager.delegate_type &&
1530 TypeManager.IsDelegateType (target_type))
1534 // From ICloneable to Array or Delegate types
1536 if (source_type == TypeManager.icloneable_type &&
1537 (target_type == TypeManager.array_type ||
1538 target_type == TypeManager.delegate_type))
1545 /// Implements Explicit Reference conversions
1547 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1549 Type source_type = source.Type;
1550 bool target_is_type_param = target_type.IsGenericParameter;
1551 bool target_is_value_type = target_type.IsValueType;
1554 // From object to a generic parameter
1556 if (source_type == TypeManager.object_type && target_is_type_param)
1557 return new UnboxCast (source, target_type);
1560 // From object to any reference type
1562 if (source_type == TypeManager.object_type && !target_is_value_type)
1563 return new ClassCast (source, target_type);
1566 // Unboxing conversion.
1568 if (((source_type == TypeManager.enum_type &&
1569 !(source is EmptyCast)) ||
1570 source_type == TypeManager.value_type) && target_is_value_type)
1571 return new UnboxCast (source, target_type);
1574 // From any class S to any class-type T, provided S is a base class of T
1576 if (TypeManager.IsSubclassOf (target_type, source_type))
1577 return new ClassCast (source, target_type);
1580 // From any interface type S to any interface T provided S is not derived from T
1582 if (source_type.IsInterface && target_type.IsInterface){
1583 if (TypeManager.ImplementsInterface (source_type, target_type))
1586 return new ClassCast (source, target_type);
1590 // From any class type S to any interface T, provides S is not sealed
1591 // and provided S does not implement T.
1593 if (target_type.IsInterface && !source_type.IsSealed) {
1594 if (TypeManager.ImplementsInterface (source_type, target_type))
1597 return new ClassCast (source, target_type);
1602 // From any interface-type S to to any class type T, provided T is not
1603 // sealed, or provided T implements S.
1605 if (source_type.IsInterface) {
1606 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1607 if (target_type.IsClass)
1608 return new ClassCast (source, target_type);
1610 return new UnboxCast (source, target_type);
1616 // From an array type S with an element type Se to an array type T with an
1617 // element type Te provided all the following are true:
1618 // * S and T differe only in element type, in other words, S and T
1619 // have the same number of dimensions.
1620 // * Both Se and Te are reference types
1621 // * An explicit referenc conversions exist from Se to Te
1623 if (source_type.IsArray && target_type.IsArray) {
1624 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1626 Type source_element_type = TypeManager.GetElementType (source_type);
1627 Type target_element_type = TypeManager.GetElementType (target_type);
1629 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1630 if (ExplicitReferenceConversionExists (source_element_type,
1631 target_element_type))
1632 return new ClassCast (source, target_type);
1637 // From System.Array to any array-type
1638 if (source_type == TypeManager.array_type &&
1639 target_type.IsArray) {
1640 return new ClassCast (source, target_type);
1644 // From System delegate to any delegate-type
1646 if (source_type == TypeManager.delegate_type &&
1647 TypeManager.IsDelegateType (target_type))
1648 return new ClassCast (source, target_type);
1651 // From ICloneable to Array or Delegate types
1653 if (source_type == TypeManager.icloneable_type &&
1654 (target_type == TypeManager.array_type ||
1655 target_type == TypeManager.delegate_type))
1656 return new ClassCast (source, target_type);
1662 /// Performs an explicit conversion of the expression `expr' whose
1663 /// type is expr.Type to `target_type'.
1665 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1666 Type target_type, Location loc)
1668 Type expr_type = expr.Type;
1669 Type original_expr_type = expr_type;
1671 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
1672 if (target_type == TypeManager.enum_type ||
1673 target_type == TypeManager.object_type) {
1674 if (expr is EnumConstant)
1675 expr = ((EnumConstant) expr).Child;
1676 // We really need all these casts here .... :-(
1677 expr = new BoxedCast (new EmptyCast (expr, expr_type));
1678 return new EmptyCast (expr, target_type);
1679 } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
1680 target_type.IsSubclassOf (TypeManager.enum_type))
1681 return new UnboxCast (expr, target_type);
1684 // Notice that we have kept the expr_type unmodified, which is only
1686 if (expr is EnumConstant)
1687 expr = ((EnumConstant) expr).Child;
1689 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
1690 expr_type = expr.Type;
1693 int errors = Report.Errors;
1694 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1695 if (Report.Errors > errors)
1701 ne = ExplicitNumericConversion (ec, expr, target_type, loc);
1706 // Unboxing conversion.
1708 if (expr_type == TypeManager.object_type && target_type.IsValueType){
1709 if (expr is NullLiteral){
1711 // Skip the ExplicitReferenceConversion because we can not convert
1712 // from Null to a ValueType, and ExplicitReference wont check against
1713 // null literal explicitly
1717 return new UnboxCast (expr, target_type);
1721 ne = ExplicitReferenceConversion (expr, target_type);
1727 if (target_type.IsPointer){
1728 if (expr_type.IsPointer)
1729 return new EmptyCast (expr, target_type);
1731 if (expr_type == TypeManager.sbyte_type ||
1732 expr_type == TypeManager.byte_type ||
1733 expr_type == TypeManager.short_type ||
1734 expr_type == TypeManager.ushort_type ||
1735 expr_type == TypeManager.int32_type ||
1736 expr_type == TypeManager.uint32_type ||
1737 expr_type == TypeManager.uint64_type ||
1738 expr_type == TypeManager.int64_type)
1739 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1741 if (expr_type.IsPointer){
1742 Expression e = null;
1744 if (target_type == TypeManager.sbyte_type)
1745 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1746 else if (target_type == TypeManager.byte_type)
1747 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1748 else if (target_type == TypeManager.short_type)
1749 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1750 else if (target_type == TypeManager.ushort_type)
1751 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1752 else if (target_type == TypeManager.int32_type)
1753 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1754 else if (target_type == TypeManager.uint32_type)
1755 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1756 else if (target_type == TypeManager.uint64_type)
1757 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1758 else if (target_type == TypeManager.int64_type){
1759 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1765 ci = ImplicitConversionStandard (ec, e, target_type, loc);
1770 ce = ExplicitNumericConversion (ec, e, target_type, loc);
1774 // We should always be able to go from an uint32
1775 // implicitly or explicitly to the other integral
1778 throw new Exception ("Internal compiler error");
1783 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1787 if (expr is NullLiteral){
1788 Report.Error (37, loc, "Cannot convert null to value type `" +
1789 TypeManager.CSharpName (target_type) + "'");
1793 Error_CannotConvertType (loc, original_expr_type, target_type);
1798 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1800 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1801 Type target_type, Location l)
1803 int errors = Report.Errors;
1804 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1805 if (Report.Errors > errors)
1811 ne = ExplicitNumericConversion (ec, expr, target_type, l);
1815 ne = ExplicitReferenceConversion (expr, target_type);
1819 Error_CannotConvertType (l, expr.Type, target_type);