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);
84 } else if (target_type == TypeManager.value_type) {
85 if (TypeManager.IsValueType (expr_type))
86 return new BoxedCast (expr);
87 if (expr is NullLiteral)
88 return new NullCast (expr, target_type);
91 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
93 // Special case: enumeration to System.Enum.
94 // System.Enum is not a value type, it is a class, so we need
95 // a boxing conversion
97 if (expr_type.IsEnum || expr_type.IsGenericParameter)
98 return new BoxedCast (expr);
100 return new EmptyCast (expr, target_type);
103 // This code is kind of mirrored inside ImplicitStandardConversionExists
104 // with the small distinction that we only probe there
106 // Always ensure that the code here and there is in sync
108 // from the null type to any reference-type.
109 if (expr is NullLiteral){
110 if (target_type.IsPointer)
111 return NullPointer.Null;
113 if (!target_type.IsValueType)
114 return new NullCast (expr, target_type);
117 // from any class-type S to any interface-type T.
118 if (target_type.IsInterface) {
119 if (target_type != TypeManager.iconvertible_type &&
120 expr_type.IsValueType && (expr is Constant) &&
121 !(expr is IntLiteral || expr is BoolLiteral ||
122 expr is FloatLiteral || expr is DoubleLiteral ||
123 expr is LongLiteral || expr is CharLiteral ||
124 expr is StringLiteral || expr is DecimalLiteral ||
125 expr is UIntLiteral || expr is ULongLiteral)) {
129 if (TypeManager.ImplementsInterface (expr_type, target_type)){
130 if (expr_type.IsGenericParameter || TypeManager.IsValueType (expr_type))
131 return new BoxedCast (expr, target_type);
133 return new EmptyCast (expr, target_type);
137 // from any interface type S to interface-type T.
138 if (expr_type.IsInterface && target_type.IsInterface) {
139 if (TypeManager.ImplementsInterface (expr_type, target_type))
140 return new EmptyCast (expr, target_type);
145 // from an array-type S to an array-type of type T
146 if (expr_type.IsArray && target_type.IsArray) {
147 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
149 Type expr_element_type = TypeManager.GetElementType (expr_type);
151 if (MyEmptyExpr == null)
152 MyEmptyExpr = new EmptyExpression ();
154 MyEmptyExpr.SetType (expr_element_type);
155 Type target_element_type = TypeManager.GetElementType (target_type);
157 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
158 if (ImplicitStandardConversionExists (MyEmptyExpr,
159 target_element_type))
160 return new EmptyCast (expr, target_type);
164 // from an array-type to System.Array
165 if (expr_type.IsArray && target_type == TypeManager.array_type)
166 return new EmptyCast (expr, target_type);
168 // from any delegate type to System.Delegate
169 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
170 target_type == TypeManager.delegate_type)
171 return new EmptyCast (expr, target_type);
173 // from any array-type or delegate type into System.ICloneable.
174 if (expr_type.IsArray ||
175 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
176 if (target_type == TypeManager.icloneable_type)
177 return new EmptyCast (expr, target_type);
179 // from a generic type definition to a generic instance.
180 if (TypeManager.IsEqualGenericType (expr_type, target_type))
181 return new EmptyCast (expr, target_type);
187 // Tests whether an implicit reference conversion exists between expr_type
190 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
192 Type expr_type = expr.Type;
195 // This is the boxed case.
197 if (target_type == TypeManager.object_type) {
198 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
199 expr_type.IsInterface || expr_type == TypeManager.enum_type)
203 } else if (TypeManager.IsSubclassOf (expr_type, target_type))
206 // Please remember that all code below actually comes
207 // from ImplicitReferenceConversion so make sure code remains in sync
209 // from any class-type S to any interface-type T.
210 if (target_type.IsInterface) {
211 if (TypeManager.ImplementsInterface (expr_type, target_type))
215 // from any interface type S to interface-type T.
216 if (expr_type.IsInterface && target_type.IsInterface)
217 if (TypeManager.ImplementsInterface (expr_type, target_type))
220 // from an array-type S to an array-type of type T
221 if (expr_type.IsArray && target_type.IsArray) {
222 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
224 Type expr_element_type = expr_type.GetElementType ();
226 if (MyEmptyExpr == null)
227 MyEmptyExpr = new EmptyExpression ();
229 MyEmptyExpr.SetType (expr_element_type);
230 Type target_element_type = TypeManager.GetElementType (target_type);
232 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
233 if (ImplicitStandardConversionExists (MyEmptyExpr,
234 target_element_type))
239 // from an array-type to System.Array
240 if (expr_type.IsArray && (target_type == TypeManager.array_type))
243 // from any delegate type to System.Delegate
244 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
245 target_type == TypeManager.delegate_type)
246 if (target_type.IsAssignableFrom (expr_type))
249 // from any array-type or delegate type into System.ICloneable.
250 if (expr_type.IsArray ||
251 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
252 if (target_type == TypeManager.icloneable_type)
255 // from the null type to any reference-type.
256 if (expr is NullLiteral && !target_type.IsValueType && !TypeManager.IsEnumType (target_type))
259 // from a generic type definition to a generic instance.
260 if (TypeManager.IsEqualGenericType (expr_type, target_type))
267 /// Implicit Numeric Conversions.
269 /// expr is the expression to convert, returns a new expression of type
270 /// target_type or null if an implicit conversion is not possible.
272 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
273 Type target_type, Location loc)
275 Type expr_type = expr.Type;
278 // Attempt to do the implicit constant expression conversions
280 if (expr is Constant){
281 if (expr is IntConstant){
284 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
288 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
290 // Try the implicit constant expression conversion
291 // from long to ulong, instead of a nice routine,
294 long v = ((LongConstant) expr).Value;
296 return new ULongConstant ((ulong) v);
300 Type real_target_type = target_type;
302 if (expr_type == TypeManager.sbyte_type){
304 // From sbyte to short, int, long, float, double.
306 if (real_target_type == TypeManager.int32_type)
307 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
308 if (real_target_type == TypeManager.int64_type)
309 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
310 if (real_target_type == TypeManager.double_type)
311 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
312 if (real_target_type == TypeManager.float_type)
313 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
314 if (real_target_type == TypeManager.short_type)
315 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
316 } else if (expr_type == TypeManager.byte_type){
318 // From byte to short, ushort, int, uint, long, ulong, float, double
320 if ((real_target_type == TypeManager.short_type) ||
321 (real_target_type == TypeManager.ushort_type) ||
322 (real_target_type == TypeManager.int32_type) ||
323 (real_target_type == TypeManager.uint32_type))
324 return new EmptyCast (expr, target_type);
326 if (real_target_type == TypeManager.uint64_type)
327 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
328 if (real_target_type == TypeManager.int64_type)
329 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
330 if (real_target_type == TypeManager.float_type)
331 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
332 if (real_target_type == TypeManager.double_type)
333 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
334 } else if (expr_type == TypeManager.short_type){
336 // From short to int, long, float, double
338 if (real_target_type == TypeManager.int32_type)
339 return new EmptyCast (expr, target_type);
340 if (real_target_type == TypeManager.int64_type)
341 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
342 if (real_target_type == TypeManager.double_type)
343 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
344 if (real_target_type == TypeManager.float_type)
345 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
346 } else if (expr_type == TypeManager.ushort_type){
348 // From ushort to int, uint, long, ulong, float, double
350 if (real_target_type == TypeManager.uint32_type)
351 return new EmptyCast (expr, target_type);
353 if (real_target_type == TypeManager.uint64_type)
354 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
355 if (real_target_type == TypeManager.int32_type)
356 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
357 if (real_target_type == TypeManager.int64_type)
358 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
359 if (real_target_type == TypeManager.double_type)
360 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
361 if (real_target_type == TypeManager.float_type)
362 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
363 } else if (expr_type == TypeManager.int32_type){
365 // From int to long, float, double
367 if (real_target_type == TypeManager.int64_type)
368 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
369 if (real_target_type == TypeManager.double_type)
370 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
371 if (real_target_type == TypeManager.float_type)
372 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
373 } else if (expr_type == TypeManager.uint32_type){
375 // From uint to long, ulong, float, double
377 if (real_target_type == TypeManager.int64_type)
378 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
379 if (real_target_type == TypeManager.uint64_type)
380 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
381 if (real_target_type == TypeManager.double_type)
382 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
384 if (real_target_type == TypeManager.float_type)
385 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
387 } else if (expr_type == TypeManager.int64_type){
389 // From long/ulong to float, double
391 if (real_target_type == TypeManager.double_type)
392 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
393 if (real_target_type == TypeManager.float_type)
394 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
395 } else if (expr_type == TypeManager.uint64_type){
397 // From ulong to float, double
399 if (real_target_type == TypeManager.double_type)
400 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
402 if (real_target_type == TypeManager.float_type)
403 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
405 } else if (expr_type == TypeManager.char_type){
407 // From char to ushort, int, uint, long, ulong, float, double
409 if ((real_target_type == TypeManager.ushort_type) ||
410 (real_target_type == TypeManager.int32_type) ||
411 (real_target_type == TypeManager.uint32_type))
412 return new EmptyCast (expr, target_type);
413 if (real_target_type == TypeManager.uint64_type)
414 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
415 if (real_target_type == TypeManager.int64_type)
416 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
417 if (real_target_type == TypeManager.float_type)
418 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
419 if (real_target_type == TypeManager.double_type)
420 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
421 } else if (expr_type == TypeManager.float_type){
425 if (real_target_type == TypeManager.double_type)
426 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
434 /// Same as ImplicitStandardConversionExists except that it also looks at
435 /// implicit user defined conversions - needed for overload resolution
437 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
439 if ((expr is NullLiteral) && target_type.IsGenericParameter)
440 return TypeParameter_to_Null (target_type);
442 if (ImplicitStandardConversionExists (expr, target_type))
445 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
453 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
455 Expression dummy = ImplicitUserConversion (
456 ec, new EmptyExpression (source), target, Location.Null);
457 return dummy != null;
461 /// Determines if a standard implicit conversion exists from
462 /// expr_type to target_type
464 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
466 Type expr_type = expr.Type;
468 if (expr_type == TypeManager.void_type)
471 //Console.WriteLine ("Expr is {0}", expr);
472 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
473 if (expr_type.Equals (target_type))
476 // First numeric conversions
478 if (expr_type == TypeManager.sbyte_type){
480 // From sbyte to short, int, long, float, double.
482 if ((target_type == TypeManager.int32_type) ||
483 (target_type == TypeManager.int64_type) ||
484 (target_type == TypeManager.double_type) ||
485 (target_type == TypeManager.float_type) ||
486 (target_type == TypeManager.short_type) ||
487 (target_type == TypeManager.decimal_type))
490 } else if (expr_type == TypeManager.byte_type){
492 // From byte to short, ushort, int, uint, long, ulong, float, double
494 if ((target_type == TypeManager.short_type) ||
495 (target_type == TypeManager.ushort_type) ||
496 (target_type == TypeManager.int32_type) ||
497 (target_type == TypeManager.uint32_type) ||
498 (target_type == TypeManager.uint64_type) ||
499 (target_type == TypeManager.int64_type) ||
500 (target_type == TypeManager.float_type) ||
501 (target_type == TypeManager.double_type) ||
502 (target_type == TypeManager.decimal_type))
505 } else if (expr_type == TypeManager.short_type){
507 // From short to int, long, float, double
509 if ((target_type == TypeManager.int32_type) ||
510 (target_type == TypeManager.int64_type) ||
511 (target_type == TypeManager.double_type) ||
512 (target_type == TypeManager.float_type) ||
513 (target_type == TypeManager.decimal_type))
516 } else if (expr_type == TypeManager.ushort_type){
518 // From ushort to int, uint, long, ulong, float, double
520 if ((target_type == TypeManager.uint32_type) ||
521 (target_type == TypeManager.uint64_type) ||
522 (target_type == TypeManager.int32_type) ||
523 (target_type == TypeManager.int64_type) ||
524 (target_type == TypeManager.double_type) ||
525 (target_type == TypeManager.float_type) ||
526 (target_type == TypeManager.decimal_type))
529 } else if (expr_type == TypeManager.int32_type){
531 // From int to long, float, double
533 if ((target_type == TypeManager.int64_type) ||
534 (target_type == TypeManager.double_type) ||
535 (target_type == TypeManager.float_type) ||
536 (target_type == TypeManager.decimal_type))
539 } else if (expr_type == TypeManager.uint32_type){
541 // From uint to long, ulong, float, double
543 if ((target_type == TypeManager.int64_type) ||
544 (target_type == TypeManager.uint64_type) ||
545 (target_type == TypeManager.double_type) ||
546 (target_type == TypeManager.float_type) ||
547 (target_type == TypeManager.decimal_type))
550 } else if ((expr_type == TypeManager.uint64_type) ||
551 (expr_type == TypeManager.int64_type)) {
553 // From long/ulong to float, double
555 if ((target_type == TypeManager.double_type) ||
556 (target_type == TypeManager.float_type) ||
557 (target_type == TypeManager.decimal_type))
560 } else if (expr_type == TypeManager.char_type){
562 // From char to ushort, int, uint, long, ulong, float, double
564 if ((target_type == TypeManager.ushort_type) ||
565 (target_type == TypeManager.int32_type) ||
566 (target_type == TypeManager.uint32_type) ||
567 (target_type == TypeManager.uint64_type) ||
568 (target_type == TypeManager.int64_type) ||
569 (target_type == TypeManager.float_type) ||
570 (target_type == TypeManager.double_type) ||
571 (target_type == TypeManager.decimal_type))
574 } else if (expr_type == TypeManager.float_type){
578 if (target_type == TypeManager.double_type)
582 if (ImplicitReferenceConversionExists (expr, target_type))
586 // Implicit Constant Expression Conversions
588 if (expr is IntConstant){
589 int value = ((IntConstant) expr).Value;
591 if (target_type == TypeManager.sbyte_type){
592 if (value >= SByte.MinValue && value <= SByte.MaxValue)
594 } else if (target_type == TypeManager.byte_type){
595 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
597 } else if (target_type == TypeManager.short_type){
598 if (value >= Int16.MinValue && value <= Int16.MaxValue)
600 } else if (target_type == TypeManager.ushort_type){
601 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
603 } else if (target_type == TypeManager.uint32_type){
606 } else if (target_type == TypeManager.uint64_type){
608 // we can optimize this case: a positive int32
609 // always fits on a uint64. But we need an opcode
616 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
620 if (expr is LongConstant && target_type == TypeManager.uint64_type){
622 // Try the implicit constant expression conversion
623 // from long to ulong, instead of a nice routine,
626 long v = ((LongConstant) expr).Value;
631 if ((target_type == TypeManager.enum_type ||
632 target_type.IsSubclassOf (TypeManager.enum_type)) &&
634 IntLiteral i = (IntLiteral) expr;
640 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
647 // Used internally by FindMostEncompassedType, this is used
648 // to avoid creating lots of objects in the tight loop inside
649 // FindMostEncompassedType
651 static EmptyExpression priv_fmet_param;
654 /// Finds "most encompassed type" according to the spec (13.4.2)
655 /// amongst the methods in the MethodGroupExpr
657 static Type FindMostEncompassedType (ArrayList types)
661 if (priv_fmet_param == null)
662 priv_fmet_param = new EmptyExpression ();
664 foreach (Type t in types){
665 priv_fmet_param.SetType (t);
672 if (ImplicitStandardConversionExists (priv_fmet_param, best))
680 // Used internally by FindMostEncompassingType, this is used
681 // to avoid creating lots of objects in the tight loop inside
682 // FindMostEncompassingType
684 static EmptyExpression priv_fmee_ret;
687 /// Finds "most encompassing type" according to the spec (13.4.2)
688 /// amongst the types in the given set
690 static Type FindMostEncompassingType (ArrayList types)
694 if (priv_fmee_ret == null)
695 priv_fmee_ret = new EmptyExpression ();
697 foreach (Type t in types){
698 priv_fmee_ret.SetType (best);
705 if (ImplicitStandardConversionExists (priv_fmee_ret, t))
713 // Used to avoid creating too many objects
715 static EmptyExpression priv_fms_expr;
718 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
719 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
720 /// for explicit and implicit conversion operators.
722 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
723 bool apply_explicit_conv_rules,
726 ArrayList src_types_set = new ArrayList ();
728 if (priv_fms_expr == null)
729 priv_fms_expr = new EmptyExpression ();
732 // If any operator converts from S then Sx = S
734 Type source_type = source.Type;
735 foreach (MethodBase mb in me.Methods){
736 ParameterData pd = Invocation.GetParameterData (mb);
737 Type param_type = pd.ParameterType (0);
739 if (param_type == source_type)
742 if (apply_explicit_conv_rules) {
745 // Find the set of applicable user-defined conversion operators, U. This set
747 // user-defined implicit or explicit conversion operators declared by
748 // the classes or structs in D that convert from a type encompassing
749 // or encompassed by S to a type encompassing or encompassed by T
751 priv_fms_expr.SetType (param_type);
752 if (ImplicitStandardConversionExists (priv_fms_expr, source_type))
753 src_types_set.Add (param_type);
755 if (ImplicitStandardConversionExists (source, param_type))
756 src_types_set.Add (param_type);
760 // Only if S is encompassed by param_type
762 if (ImplicitStandardConversionExists (source, param_type))
763 src_types_set.Add (param_type);
768 // Explicit Conv rules
770 if (apply_explicit_conv_rules) {
771 ArrayList candidate_set = new ArrayList ();
773 foreach (Type param_type in src_types_set){
774 if (ImplicitStandardConversionExists (source, param_type))
775 candidate_set.Add (param_type);
778 if (candidate_set.Count != 0)
779 return FindMostEncompassedType (candidate_set);
785 if (apply_explicit_conv_rules)
786 return FindMostEncompassingType (src_types_set);
788 return FindMostEncompassedType (src_types_set);
792 // Useful in avoiding proliferation of objects
794 static EmptyExpression priv_fmt_expr;
797 /// Finds the most specific target Tx according to section 13.4.4
799 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
800 bool apply_explicit_conv_rules,
803 ArrayList tgt_types_set = new ArrayList ();
805 if (priv_fmt_expr == null)
806 priv_fmt_expr = new EmptyExpression ();
809 // If any operator converts to T then Tx = T
811 foreach (MethodInfo mi in me.Methods){
812 Type ret_type = mi.ReturnType;
814 if (ret_type == target)
817 if (apply_explicit_conv_rules) {
820 // Find the set of applicable user-defined conversion operators, U.
822 // This set consists of the
823 // user-defined implicit or explicit conversion operators declared by
824 // the classes or structs in D that convert from a type encompassing
825 // or encompassed by S to a type encompassing or encompassed by T
827 priv_fms_expr.SetType (ret_type);
828 if (ImplicitStandardConversionExists (priv_fms_expr, target))
829 tgt_types_set.Add (ret_type);
831 priv_fms_expr.SetType (target);
832 if (ImplicitStandardConversionExists (priv_fms_expr, ret_type))
833 tgt_types_set.Add (ret_type);
837 // Only if T is encompassed by param_type
839 priv_fms_expr.SetType (ret_type);
840 if (ImplicitStandardConversionExists (priv_fms_expr, target))
841 tgt_types_set.Add (ret_type);
846 // Explicit conv rules
848 if (apply_explicit_conv_rules) {
849 ArrayList candidate_set = new ArrayList ();
851 foreach (Type ret_type in tgt_types_set){
852 priv_fmt_expr.SetType (ret_type);
854 if (ImplicitStandardConversionExists (priv_fmt_expr, target))
855 candidate_set.Add (ret_type);
858 if (candidate_set.Count != 0)
859 return FindMostEncompassingType (candidate_set);
863 // Okay, final case !
865 if (apply_explicit_conv_rules)
866 return FindMostEncompassedType (tgt_types_set);
868 return FindMostEncompassingType (tgt_types_set);
872 /// User-defined Implicit conversions
874 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
875 Type target, Location loc)
877 return UserDefinedConversion (ec, source, target, loc, false);
881 /// User-defined Explicit conversions
883 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
884 Type target, Location loc)
886 return UserDefinedConversion (ec, source, target, loc, true);
889 static DoubleHash explicit_conv = new DoubleHash (100);
890 static DoubleHash implicit_conv = new DoubleHash (100);
892 /// Computes the MethodGroup for the user-defined conversion
893 /// operators from source_type to target_type. `look_for_explicit'
894 /// controls whether we should also include the list of explicit
897 static MethodGroupExpr GetConversionOperators (EmitContext ec,
898 Type source_type, Type target_type,
899 Location loc, bool look_for_explicit)
901 Expression mg1 = null, mg2 = null;
902 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
905 op_name = "op_Implicit";
907 MethodGroupExpr union3;
909 if ((look_for_explicit ? explicit_conv : implicit_conv).Lookup (source_type, target_type, out r))
910 return (MethodGroupExpr) r;
912 mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
913 if (source_type.BaseType != null)
914 mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
917 union3 = (MethodGroupExpr) mg2;
918 else if (mg2 == null)
919 union3 = (MethodGroupExpr) mg1;
921 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
923 mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
926 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
928 union3 = (MethodGroupExpr) mg1;
931 if (target_type.BaseType != null)
932 mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
936 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
938 union3 = (MethodGroupExpr) mg1;
941 MethodGroupExpr union4 = null;
943 if (look_for_explicit) {
944 op_name = "op_Explicit";
946 mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
947 if (source_type.BaseType != null)
948 mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
950 mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
951 if (target_type.BaseType != null)
952 mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
954 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
955 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
957 union4 = Invocation.MakeUnionSet (union5, union6, loc);
960 MethodGroupExpr ret = Invocation.MakeUnionSet (union3, union4, loc);
961 (look_for_explicit ? explicit_conv : implicit_conv).Insert (source_type, target_type, ret);
966 /// User-defined conversions
968 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
969 Type target, Location loc,
970 bool look_for_explicit)
972 MethodGroupExpr union;
973 Type source_type = source.Type;
974 MethodBase method = null;
976 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
980 Type most_specific_source, most_specific_target;
982 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
983 if (most_specific_source == null)
986 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
987 if (most_specific_target == null)
993 foreach (MethodBase mb in union.Methods){
994 ParameterData pd = Invocation.GetParameterData (mb);
995 MethodInfo mi = (MethodInfo) mb;
997 if (pd.ParameterType (0) == most_specific_source &&
998 mi.ReturnType == most_specific_target) {
1004 if (method == null || count > 1)
1009 // This will do the conversion to the best match that we
1010 // found. Now we need to perform an implict standard conversion
1011 // if the best match was not the type that we were requested
1014 if (look_for_explicit)
1015 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1017 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1023 e = new UserCast ((MethodInfo) method, source, loc);
1024 if (e.Type != target){
1025 if (!look_for_explicit)
1026 e = ImplicitConversionStandard (ec, e, target, loc);
1028 e = ExplicitConversionStandard (ec, e, target, loc);
1035 /// Converts implicitly the resolved expression `expr' into the
1036 /// `target_type'. It returns a new expression that can be used
1037 /// in a context that expects a `target_type'.
1039 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1040 Type target_type, Location loc)
1044 if (target_type == null)
1045 throw new Exception ("Target type is null");
1047 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1051 e = ImplicitUserConversion (ec, expr, target_type, loc);
1060 /// Attempts to apply the `Standard Implicit
1061 /// Conversion' rules to the expression `expr' into
1062 /// the `target_type'. It returns a new expression
1063 /// that can be used in a context that expects a
1066 /// This is different from `ImplicitConversion' in that the
1067 /// user defined implicit conversions are excluded.
1069 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1070 Type target_type, Location loc)
1072 Type expr_type = expr.Type;
1075 if ((expr is NullLiteral) && target_type.IsGenericParameter)
1076 return TypeParameter_to_Null (expr, target_type, loc);
1078 if (expr.eclass == ExprClass.MethodGroup){
1079 if (!TypeManager.IsDelegateType (target_type)){
1080 Report.Error (428, loc,
1082 "Cannot convert method group to `{0}', since it is not a delegate",
1083 TypeManager.CSharpName (target_type)));
1087 return ImplicitDelegateCreation.Create (ec, (MethodGroupExpr) expr, target_type, loc);
1090 if (expr_type.Equals (target_type) && !(expr is NullLiteral))
1093 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1097 e = ImplicitReferenceConversion (expr, target_type);
1101 if ((target_type == TypeManager.enum_type ||
1102 target_type.IsSubclassOf (TypeManager.enum_type)) &&
1103 expr is IntLiteral){
1104 IntLiteral i = (IntLiteral) expr;
1107 return new EnumConstant ((Constant) expr, target_type);
1111 if (expr_type.IsPointer){
1112 if (target_type == TypeManager.void_ptr_type)
1113 return new EmptyCast (expr, target_type);
1116 // yep, comparing pointer types cant be done with
1117 // t1 == t2, we have to compare their element types.
1119 if (target_type.IsPointer){
1120 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1125 if (target_type.IsPointer) {
1126 if (expr is NullLiteral)
1127 return new EmptyCast (expr, target_type);
1129 if (expr_type == TypeManager.void_ptr_type)
1130 return new EmptyCast (expr, target_type);
1138 /// Attemps to perform an implict constant conversion of the IntConstant
1139 /// into a different data type using casts (See Implicit Constant
1140 /// Expression Conversions)
1142 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1144 int value = ic.Value;
1146 if (target_type == TypeManager.sbyte_type){
1147 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1148 return new SByteConstant ((sbyte) value);
1149 } else if (target_type == TypeManager.byte_type){
1150 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1151 return new ByteConstant ((byte) value);
1152 } else if (target_type == TypeManager.short_type){
1153 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1154 return new ShortConstant ((short) value);
1155 } else if (target_type == TypeManager.ushort_type){
1156 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1157 return new UShortConstant ((ushort) value);
1158 } else if (target_type == TypeManager.uint32_type){
1160 return new UIntConstant ((uint) value);
1161 } else if (target_type == TypeManager.uint64_type){
1163 // we can optimize this case: a positive int32
1164 // always fits on a uint64. But we need an opcode
1168 return new ULongConstant ((ulong) value);
1169 } else if (target_type == TypeManager.double_type)
1170 return new DoubleConstant ((double) value);
1171 else if (target_type == TypeManager.float_type)
1172 return new FloatConstant ((float) value);
1174 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1175 Type underlying = TypeManager.EnumToUnderlying (target_type);
1176 Constant e = (Constant) ic;
1179 // Possibly, we need to create a different 0 literal before passing
1182 if (underlying == TypeManager.int64_type)
1183 e = new LongLiteral (0);
1184 else if (underlying == TypeManager.uint64_type)
1185 e = new ULongLiteral (0);
1187 return new EnumConstant (e, target_type);
1192 static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
1194 string msg = "Cannot convert implicitly from `"+
1195 TypeManager.CSharpName (source) + "' to `" +
1196 TypeManager.CSharpName (target) + "'";
1198 Report.Error (29, loc, msg);
1202 /// Attemptes to implicityly convert `target' into `type', using
1203 /// ImplicitConversion. If there is no implicit conversion, then
1204 /// an error is signaled
1206 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1207 Type target_type, Location loc)
1211 int errors = Report.Errors;
1212 e = ImplicitConversion (ec, source, target_type, loc);
1213 if (Report.Errors > errors)
1218 if (source is DoubleLiteral && target_type == TypeManager.float_type){
1219 Report.Error (664, loc,
1220 "Double literal cannot be implicitly converted to " +
1221 "float type, use F suffix to create a float literal");
1224 if (source is Constant){
1225 Constant c = (Constant) source;
1227 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
1231 Error_CannotImplicitConversion (loc, source.Type, target_type);
1237 /// Performs the explicit numeric conversions
1239 static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
1241 Type expr_type = expr.Type;
1244 // If we have an enumeration, extract the underlying type,
1245 // use this during the comparison, but wrap around the original
1248 Type real_target_type = target_type;
1250 if (TypeManager.IsEnumType (real_target_type))
1251 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
1253 if (ImplicitStandardConversionExists (expr, real_target_type)){
1254 Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc);
1256 if (real_target_type != target_type)
1257 return new EmptyCast (ce, target_type);
1261 if (expr_type == TypeManager.sbyte_type){
1263 // From sbyte to byte, ushort, uint, ulong, char
1265 if (real_target_type == TypeManager.byte_type)
1266 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
1267 if (real_target_type == TypeManager.ushort_type)
1268 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
1269 if (real_target_type == TypeManager.uint32_type)
1270 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
1271 if (real_target_type == TypeManager.uint64_type)
1272 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
1273 if (real_target_type == TypeManager.char_type)
1274 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
1275 } else if (expr_type == TypeManager.byte_type){
1277 // From byte to sbyte and char
1279 if (real_target_type == TypeManager.sbyte_type)
1280 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
1281 if (real_target_type == TypeManager.char_type)
1282 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
1283 } else if (expr_type == TypeManager.short_type){
1285 // From short to sbyte, byte, ushort, uint, ulong, char
1287 if (real_target_type == TypeManager.sbyte_type)
1288 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1289 if (real_target_type == TypeManager.byte_type)
1290 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1291 if (real_target_type == TypeManager.ushort_type)
1292 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
1293 if (real_target_type == TypeManager.uint32_type)
1294 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
1295 if (real_target_type == TypeManager.uint64_type)
1296 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
1297 if (real_target_type == TypeManager.char_type)
1298 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
1299 } else if (expr_type == TypeManager.ushort_type){
1301 // From ushort to sbyte, byte, short, char
1303 if (real_target_type == TypeManager.sbyte_type)
1304 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
1305 if (real_target_type == TypeManager.byte_type)
1306 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1307 if (real_target_type == TypeManager.short_type)
1308 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
1309 if (real_target_type == TypeManager.char_type)
1310 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
1311 } else if (expr_type == TypeManager.int32_type){
1313 // From int to sbyte, byte, short, ushort, uint, ulong, char
1315 if (real_target_type == TypeManager.sbyte_type)
1316 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1317 if (real_target_type == TypeManager.byte_type)
1318 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1319 if (real_target_type == TypeManager.short_type)
1320 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1321 if (real_target_type == TypeManager.ushort_type)
1322 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1323 if (real_target_type == TypeManager.uint32_type)
1324 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
1325 if (real_target_type == TypeManager.uint64_type)
1326 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
1327 if (real_target_type == TypeManager.char_type)
1328 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
1329 } else if (expr_type == TypeManager.uint32_type){
1331 // From uint to sbyte, byte, short, ushort, int, char
1333 if (real_target_type == TypeManager.sbyte_type)
1334 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
1335 if (real_target_type == TypeManager.byte_type)
1336 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1337 if (real_target_type == TypeManager.short_type)
1338 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
1339 if (real_target_type == TypeManager.ushort_type)
1340 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1341 if (real_target_type == TypeManager.int32_type)
1342 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
1343 if (real_target_type == TypeManager.char_type)
1344 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
1345 } else if (expr_type == TypeManager.int64_type){
1347 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1349 if (real_target_type == TypeManager.sbyte_type)
1350 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1351 if (real_target_type == TypeManager.byte_type)
1352 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1353 if (real_target_type == TypeManager.short_type)
1354 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1355 if (real_target_type == TypeManager.ushort_type)
1356 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1357 if (real_target_type == TypeManager.int32_type)
1358 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1359 if (real_target_type == TypeManager.uint32_type)
1360 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
1361 if (real_target_type == TypeManager.uint64_type)
1362 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
1363 if (real_target_type == TypeManager.char_type)
1364 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
1365 } else if (expr_type == TypeManager.uint64_type){
1367 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1369 if (real_target_type == TypeManager.sbyte_type)
1370 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
1371 if (real_target_type == TypeManager.byte_type)
1372 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1373 if (real_target_type == TypeManager.short_type)
1374 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
1375 if (real_target_type == TypeManager.ushort_type)
1376 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1377 if (real_target_type == TypeManager.int32_type)
1378 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
1379 if (real_target_type == TypeManager.uint32_type)
1380 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
1381 if (real_target_type == TypeManager.int64_type)
1382 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
1383 if (real_target_type == TypeManager.char_type)
1384 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
1385 } else if (expr_type == TypeManager.char_type){
1387 // From char to sbyte, byte, short
1389 if (real_target_type == TypeManager.sbyte_type)
1390 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
1391 if (real_target_type == TypeManager.byte_type)
1392 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
1393 if (real_target_type == TypeManager.short_type)
1394 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
1395 } else if (expr_type == TypeManager.float_type){
1397 // From float to sbyte, byte, short,
1398 // ushort, int, uint, long, ulong, char
1401 if (real_target_type == TypeManager.sbyte_type)
1402 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1);
1403 if (real_target_type == TypeManager.byte_type)
1404 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1);
1405 if (real_target_type == TypeManager.short_type)
1406 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
1407 if (real_target_type == TypeManager.ushort_type)
1408 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
1409 if (real_target_type == TypeManager.int32_type)
1410 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4);
1411 if (real_target_type == TypeManager.uint32_type)
1412 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
1413 if (real_target_type == TypeManager.int64_type)
1414 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8);
1415 if (real_target_type == TypeManager.uint64_type)
1416 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
1417 if (real_target_type == TypeManager.char_type)
1418 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH);
1419 } else if (expr_type == TypeManager.double_type){
1421 // From double to byte, byte, short,
1422 // ushort, int, uint, long, ulong,
1423 // char, float or decimal
1425 if (real_target_type == TypeManager.sbyte_type)
1426 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
1427 if (real_target_type == TypeManager.byte_type)
1428 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1429 if (real_target_type == TypeManager.short_type)
1430 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1431 if (real_target_type == TypeManager.ushort_type)
1432 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
1433 if (real_target_type == TypeManager.int32_type)
1434 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1435 if (real_target_type == TypeManager.uint32_type)
1436 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
1437 if (real_target_type == TypeManager.int64_type)
1438 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1439 if (real_target_type == TypeManager.uint64_type)
1440 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
1441 if (real_target_type == TypeManager.char_type)
1442 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH);
1443 if (real_target_type == TypeManager.float_type)
1444 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
1447 // decimal is taken care of by the op_Explicit methods.
1453 /// Returns whether an explicit reference conversion can be performed
1454 /// from source_type to target_type
1456 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1458 bool target_is_type_param = target_type.IsGenericParameter;
1459 bool target_is_value_type = target_type.IsValueType;
1461 if (source_type == target_type)
1465 // From object to a generic parameter
1467 if (source_type == TypeManager.object_type && target_is_type_param)
1471 // From object to any reference type
1473 if (source_type == TypeManager.object_type && !target_is_value_type)
1477 // From any class S to any class-type T, provided S is a base class of T
1479 if (TypeManager.IsSubclassOf (target_type, source_type))
1483 // From any interface type S to any interface T provided S is not derived from T
1485 if (source_type.IsInterface && target_type.IsInterface){
1486 if (!TypeManager.IsSubclassOf (target_type, source_type))
1491 // From any class type S to any interface T, provided S is not sealed
1492 // and provided S does not implement T.
1494 if (target_type.IsInterface && !source_type.IsSealed &&
1495 !TypeManager.ImplementsInterface (source_type, target_type))
1499 // From any interface-type S to to any class type T, provided T is not
1500 // sealed, or provided T implements S.
1502 if (source_type.IsInterface &&
1503 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1507 // From an array type S with an element type Se to an array type T with an
1508 // element type Te provided all the following are true:
1509 // * S and T differe only in element type, in other words, S and T
1510 // have the same number of dimensions.
1511 // * Both Se and Te are reference types
1512 // * An explicit referenc conversions exist from Se to Te
1514 if (source_type.IsArray && target_type.IsArray) {
1515 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1517 Type source_element_type = TypeManager.GetElementType (source_type);
1518 Type target_element_type = TypeManager.GetElementType (target_type);
1520 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1521 if (ExplicitReferenceConversionExists (source_element_type,
1522 target_element_type))
1528 // From System.Array to any array-type
1529 if (source_type == TypeManager.array_type &&
1530 target_type.IsArray){
1535 // From System delegate to any delegate-type
1537 if (source_type == TypeManager.delegate_type &&
1538 TypeManager.IsDelegateType (target_type))
1542 // From ICloneable to Array or Delegate types
1544 if (source_type == TypeManager.icloneable_type &&
1545 (target_type == TypeManager.array_type ||
1546 target_type == TypeManager.delegate_type))
1553 /// Implements Explicit Reference conversions
1555 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1557 Type source_type = source.Type;
1558 bool target_is_type_param = target_type.IsGenericParameter;
1559 bool target_is_value_type = target_type.IsValueType;
1562 // From object to a generic parameter
1564 if (source_type == TypeManager.object_type && target_is_type_param)
1565 return new UnboxCast (source, target_type);
1568 // From object to any reference type
1570 if (source_type == TypeManager.object_type && !target_is_value_type)
1571 return new ClassCast (source, target_type);
1574 // Unboxing conversion.
1576 if (((source_type == TypeManager.enum_type &&
1577 !(source is EmptyCast)) ||
1578 source_type == TypeManager.value_type) && target_is_value_type)
1579 return new UnboxCast (source, target_type);
1582 // From any class S to any class-type T, provided S is a base class of T
1584 if (TypeManager.IsSubclassOf (target_type, source_type))
1585 return new ClassCast (source, target_type);
1588 // From any interface type S to any interface T provided S is not derived from T
1590 if (source_type.IsInterface && target_type.IsInterface){
1591 if (TypeManager.ImplementsInterface (source_type, target_type))
1594 return new ClassCast (source, target_type);
1598 // From any class type S to any interface T, provides S is not sealed
1599 // and provided S does not implement T.
1601 if (target_type.IsInterface && !source_type.IsSealed) {
1602 if (TypeManager.ImplementsInterface (source_type, target_type))
1605 return new ClassCast (source, target_type);
1610 // From any interface-type S to to any class type T, provided T is not
1611 // sealed, or provided T implements S.
1613 if (source_type.IsInterface) {
1614 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1615 if (target_type.IsClass)
1616 return new ClassCast (source, target_type);
1618 return new UnboxCast (source, target_type);
1624 // From an array type S with an element type Se to an array type T with an
1625 // element type Te provided all the following are true:
1626 // * S and T differe only in element type, in other words, S and T
1627 // have the same number of dimensions.
1628 // * Both Se and Te are reference types
1629 // * An explicit referenc conversions exist from Se to Te
1631 if (source_type.IsArray && target_type.IsArray) {
1632 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1634 Type source_element_type = TypeManager.GetElementType (source_type);
1635 Type target_element_type = TypeManager.GetElementType (target_type);
1637 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1638 if (ExplicitReferenceConversionExists (source_element_type,
1639 target_element_type))
1640 return new ClassCast (source, target_type);
1645 // From System.Array to any array-type
1646 if (source_type == TypeManager.array_type &&
1647 target_type.IsArray) {
1648 return new ClassCast (source, target_type);
1652 // From System delegate to any delegate-type
1654 if (source_type == TypeManager.delegate_type &&
1655 TypeManager.IsDelegateType (target_type))
1656 return new ClassCast (source, target_type);
1659 // From ICloneable to Array or Delegate types
1661 if (source_type == TypeManager.icloneable_type &&
1662 (target_type == TypeManager.array_type ||
1663 target_type == TypeManager.delegate_type))
1664 return new ClassCast (source, target_type);
1670 /// Performs an explicit conversion of the expression `expr' whose
1671 /// type is expr.Type to `target_type'.
1673 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1674 Type target_type, Location loc)
1676 Type expr_type = expr.Type;
1677 Type original_expr_type = expr_type;
1679 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
1680 if (target_type == TypeManager.enum_type ||
1681 target_type == TypeManager.object_type) {
1682 if (expr is EnumConstant)
1683 expr = ((EnumConstant) expr).Child;
1684 // We really need all these casts here .... :-(
1685 expr = new BoxedCast (new EmptyCast (expr, expr_type));
1686 return new EmptyCast (expr, target_type);
1687 } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
1688 target_type.IsSubclassOf (TypeManager.enum_type))
1689 return new UnboxCast (expr, target_type);
1692 // Notice that we have kept the expr_type unmodified, which is only
1694 if (expr is EnumConstant)
1695 expr = ((EnumConstant) expr).Child;
1697 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
1698 expr_type = expr.Type;
1701 int errors = Report.Errors;
1702 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1703 if (Report.Errors > errors)
1709 ne = ExplicitNumericConversion (ec, expr, target_type, loc);
1714 // Unboxing conversion.
1716 if (expr_type == TypeManager.object_type && target_type.IsValueType){
1717 if (expr is NullLiteral){
1719 // Skip the ExplicitReferenceConversion because we can not convert
1720 // from Null to a ValueType, and ExplicitReference wont check against
1721 // null literal explicitly
1725 return new UnboxCast (expr, target_type);
1729 ne = ExplicitReferenceConversion (expr, target_type);
1735 if (target_type.IsPointer){
1736 if (expr_type.IsPointer)
1737 return new EmptyCast (expr, target_type);
1739 if (expr_type == TypeManager.sbyte_type ||
1740 expr_type == TypeManager.byte_type ||
1741 expr_type == TypeManager.short_type ||
1742 expr_type == TypeManager.ushort_type ||
1743 expr_type == TypeManager.int32_type ||
1744 expr_type == TypeManager.uint32_type ||
1745 expr_type == TypeManager.uint64_type ||
1746 expr_type == TypeManager.int64_type)
1747 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1749 if (expr_type.IsPointer){
1750 Expression e = null;
1752 if (target_type == TypeManager.sbyte_type)
1753 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1754 else if (target_type == TypeManager.byte_type)
1755 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1756 else if (target_type == TypeManager.short_type)
1757 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1758 else if (target_type == TypeManager.ushort_type)
1759 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1760 else if (target_type == TypeManager.int32_type)
1761 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1762 else if (target_type == TypeManager.uint32_type)
1763 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1764 else if (target_type == TypeManager.uint64_type)
1765 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1766 else if (target_type == TypeManager.int64_type){
1767 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1773 ci = ImplicitConversionStandard (ec, e, target_type, loc);
1778 ce = ExplicitNumericConversion (ec, e, target_type, loc);
1782 // We should always be able to go from an uint32
1783 // implicitly or explicitly to the other integral
1786 throw new Exception ("Internal compiler error");
1791 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1795 if (expr is NullLiteral){
1796 Report.Error (37, loc, "Cannot convert null to value type `" +
1797 TypeManager.CSharpName (target_type) + "'");
1801 Error_CannotConvertType (loc, original_expr_type, target_type);
1806 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1808 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1809 Type target_type, Location l)
1811 int errors = Report.Errors;
1812 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1813 if (Report.Errors > errors)
1819 ne = ExplicitNumericConversion (ec, expr, target_type, l);
1823 ne = ExplicitReferenceConversion (expr, target_type);
1827 Error_CannotConvertType (l, expr.Type, target_type);