2006-04-27 Jonathan Chambers <jonathan.chambers@ansys.com>
[mcs.git] / mcs / convert.cs
blob5e79c32e7927201ded5deb2a5d62000231397402
1 //
2 // conversion.cs: various routines for implementing conversions.
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Ravi Pratap (ravi@ximian.com)
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 //
11 namespace Mono.CSharp {
12 using System;
13 using System.Collections;
14 using System.Diagnostics;
15 using System.Reflection;
16 using System.Reflection.Emit;
19 // A container class for all the conversion operations
21 public class Convert {
23 static EmptyExpression MyEmptyExpr;
24 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
26 Type expr_type = expr.Type;
28 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
29 // if we are a method group, emit a warning
31 expr.Emit (null);
34 if (expr_type == TypeManager.void_type)
35 return null;
38 // notice that it is possible to write "ValueType v = 1", the ValueType here
39 // is an abstract class, and not really a value type, so we apply the same rules.
41 if (target_type == TypeManager.object_type) {
43 // A pointer type cannot be converted to object
44 //
45 if (expr_type.IsPointer)
46 return null;
48 if (expr_type.IsValueType)
49 return new BoxedCast (expr, target_type);
50 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
51 if (expr_type == TypeManager.anonymous_method_type)
52 return null;
53 return new EmptyCast (expr, target_type);
56 return null;
57 } else if (target_type == TypeManager.value_type) {
58 if (expr_type.IsValueType)
59 return new BoxedCast (expr, target_type);
60 if (expr_type == TypeManager.null_type)
61 return new NullCast ((Constant)expr, target_type);
63 return null;
64 } else if (expr_type.IsSubclassOf (target_type)) {
66 // Special case: enumeration to System.Enum.
67 // System.Enum is not a value type, it is a class, so we need
68 // a boxing conversion
70 if (expr_type.IsEnum)
71 return new BoxedCast (expr, target_type);
73 return new EmptyCast (expr, target_type);
76 // This code is kind of mirrored inside ImplicitStandardConversionExists
77 // with the small distinction that we only probe there
79 // Always ensure that the code here and there is in sync
81 // from the null type to any reference-type.
82 if (expr_type == TypeManager.null_type){
83 if (target_type.IsPointer)
84 return new EmptyCast (NullPointer.Null, target_type);
86 if (!target_type.IsValueType) {
87 if (expr is Constant)
88 return new NullCast ((Constant)expr, target_type);
90 // I found only one case when it happens -- Foo () ? null : null;
91 Report.Warning (-100, 1, expr.Location, "The result of the expression is always `null'");
92 return new NullCast (new NullLiteral (expr.Location), target_type);
96 // from any class-type S to any interface-type T.
97 if (target_type.IsInterface) {
98 if (target_type != TypeManager.iconvertible_type &&
99 expr_type.IsValueType && (expr is Constant) &&
100 !(expr is IntLiteral || expr is BoolLiteral ||
101 expr is FloatLiteral || expr is DoubleLiteral ||
102 expr is LongLiteral || expr is CharLiteral ||
103 expr is StringLiteral || expr is DecimalLiteral ||
104 expr is UIntLiteral || expr is ULongLiteral)) {
105 return null;
108 if (TypeManager.ImplementsInterface (expr_type, target_type)){
109 if (expr_type.IsClass)
110 return new EmptyCast (expr, target_type);
111 else if (expr_type.IsValueType)
112 return new BoxedCast (expr, target_type);
113 else
114 return new EmptyCast (expr, target_type);
118 // from any interface type S to interface-type T.
119 if (expr_type.IsInterface && target_type.IsInterface) {
120 if (TypeManager.ImplementsInterface (expr_type, target_type))
121 return new EmptyCast (expr, target_type);
122 else
123 return null;
126 // from an array-type S to an array-type of type T
127 if (expr_type.IsArray && target_type.IsArray) {
128 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
130 Type expr_element_type = TypeManager.GetElementType (expr_type);
132 if (MyEmptyExpr == null)
133 MyEmptyExpr = new EmptyExpression ();
135 MyEmptyExpr.SetType (expr_element_type);
136 Type target_element_type = TypeManager.GetElementType (target_type);
138 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
139 if (ImplicitStandardConversionExists (MyEmptyExpr,
140 target_element_type))
141 return new EmptyCast (expr, target_type);
145 // from an array-type to System.Array
146 if (expr_type.IsArray && target_type == TypeManager.array_type)
147 return new EmptyCast (expr, target_type);
149 // from any delegate type to System.Delegate
150 if ((expr_type == TypeManager.delegate_type ||
151 expr_type.IsSubclassOf (TypeManager.delegate_type)) &&
152 target_type == TypeManager.delegate_type)
153 return new EmptyCast (expr, target_type);
155 // from any array-type or delegate type into System.ICloneable.
156 if (expr_type.IsArray ||
157 expr_type == TypeManager.delegate_type ||
158 expr_type.IsSubclassOf (TypeManager.delegate_type))
159 if (target_type == TypeManager.icloneable_type)
160 return new EmptyCast (expr, target_type);
162 return null;
166 // Tests whether an implicit reference conversion exists between expr_type
167 // and target_type
169 static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
171 if (target_type.IsValueType)
172 return false;
174 Type expr_type = expr.Type;
177 // This is the boxed case.
179 if (target_type == TypeManager.object_type) {
180 if (expr_type.IsClass || expr_type.IsValueType ||
181 expr_type.IsInterface || expr_type == TypeManager.enum_type)
182 if (target_type != TypeManager.anonymous_method_type)
183 return true;
185 return false;
186 } else if (expr_type.IsSubclassOf (target_type))
187 return true;
189 // Please remember that all code below actually comes
190 // from ImplicitReferenceConversion so make sure code remains in sync
192 // from any class-type S to any interface-type T.
193 if (target_type.IsInterface) {
194 if (target_type != TypeManager.iconvertible_type &&
195 expr_type.IsValueType && (expr is Constant) &&
196 !(expr is IntLiteral || expr is BoolLiteral ||
197 expr is FloatLiteral || expr is DoubleLiteral ||
198 expr is LongLiteral || expr is CharLiteral ||
199 expr is StringLiteral || expr is DecimalLiteral ||
200 expr is UIntLiteral || expr is ULongLiteral)) {
201 return false;
204 if (TypeManager.ImplementsInterface (expr_type, target_type))
205 return true;
208 // from any interface type S to interface-type T.
209 if (expr_type.IsInterface && target_type.IsInterface)
210 if (TypeManager.ImplementsInterface (expr_type, target_type))
211 return true;
213 // from an array-type S to an array-type of type T
214 if (expr_type.IsArray && target_type.IsArray) {
215 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
217 Type expr_element_type = expr_type.GetElementType ();
219 if (MyEmptyExpr == null)
220 MyEmptyExpr = new EmptyExpression ();
222 MyEmptyExpr.SetType (expr_element_type);
223 Type target_element_type = TypeManager.GetElementType (target_type);
225 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
226 if (ImplicitStandardConversionExists (MyEmptyExpr,
227 target_element_type))
228 return true;
232 // from an array-type to System.Array
233 if (expr_type.IsArray && (target_type == TypeManager.array_type))
234 return true;
236 // from any delegate type to System.Delegate
237 if ((expr_type == TypeManager.delegate_type ||
238 expr_type.IsSubclassOf (TypeManager.delegate_type)) &&
239 target_type == TypeManager.delegate_type)
240 if (target_type.IsAssignableFrom (expr_type))
241 return true;
243 // from any array-type or delegate type into System.ICloneable.
244 if (expr_type.IsArray ||
245 expr_type == TypeManager.delegate_type ||
246 expr_type.IsSubclassOf (TypeManager.delegate_type))
247 if (target_type == TypeManager.icloneable_type)
248 return true;
250 // from the null type to any reference-type.
251 if (expr_type == TypeManager.null_type){
252 if (target_type.IsPointer)
253 return true;
255 if (!target_type.IsValueType)
256 return true;
258 return false;
261 /// <summary>
262 /// Implicit Numeric Conversions.
264 /// expr is the expression to convert, returns a new expression of type
265 /// target_type or null if an implicit conversion is not possible.
266 /// </summary>
267 static public Expression ImplicitNumericConversion (Expression expr,
268 Type target_type)
270 Type expr_type = expr.Type;
273 // Attempt to do the implicit constant expression conversions
275 if (expr is Constant){
276 if (expr is IntConstant){
277 Expression e;
279 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
281 if (e != null)
282 return e;
283 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
285 // Try the implicit constant expression conversion
286 // from long to ulong, instead of a nice routine,
287 // we just inline it
289 long v = ((LongConstant) expr).Value;
290 if (v >= 0)
291 return new ULongConstant ((ulong) v, expr.Location);
295 Type real_target_type = target_type;
297 if (expr_type == TypeManager.sbyte_type){
299 // From sbyte to short, int, long, float, double, decimal
301 if (real_target_type == TypeManager.int32_type)
302 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
303 if (real_target_type == TypeManager.int64_type)
304 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
305 if (real_target_type == TypeManager.double_type)
306 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
307 if (real_target_type == TypeManager.float_type)
308 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
309 if (real_target_type == TypeManager.short_type)
310 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
311 if (real_target_type == TypeManager.decimal_type)
312 return new CastToDecimal (expr);
313 } else if (expr_type == TypeManager.byte_type){
315 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
317 if ((real_target_type == TypeManager.short_type) ||
318 (real_target_type == TypeManager.ushort_type) ||
319 (real_target_type == TypeManager.int32_type) ||
320 (real_target_type == TypeManager.uint32_type))
321 return new EmptyCast (expr, target_type);
323 if (real_target_type == TypeManager.uint64_type)
324 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
325 if (real_target_type == TypeManager.int64_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
327 if (real_target_type == TypeManager.float_type)
328 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
329 if (real_target_type == TypeManager.double_type)
330 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
331 if (real_target_type == TypeManager.decimal_type)
332 return new CastToDecimal (expr);
334 } else if (expr_type == TypeManager.short_type){
336 // From short to int, long, float, double, decimal
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 if (real_target_type == TypeManager.decimal_type)
347 return new CastToDecimal (expr);
349 } else if (expr_type == TypeManager.ushort_type){
351 // From ushort to int, uint, long, ulong, float, double, decimal
353 if (real_target_type == TypeManager.uint32_type)
354 return new EmptyCast (expr, target_type);
356 if (real_target_type == TypeManager.uint64_type)
357 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
358 if (real_target_type == TypeManager.int32_type)
359 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
360 if (real_target_type == TypeManager.int64_type)
361 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
362 if (real_target_type == TypeManager.double_type)
363 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
364 if (real_target_type == TypeManager.float_type)
365 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
366 if (real_target_type == TypeManager.decimal_type)
367 return new CastToDecimal (expr);
368 } else if (expr_type == TypeManager.int32_type){
370 // From int to long, float, double, decimal
372 if (real_target_type == TypeManager.int64_type)
373 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
374 if (real_target_type == TypeManager.double_type)
375 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
376 if (real_target_type == TypeManager.float_type)
377 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
378 if (real_target_type == TypeManager.decimal_type)
379 return new CastToDecimal (expr);
380 } else if (expr_type == TypeManager.uint32_type){
382 // From uint to long, ulong, float, double, decimal
384 if (real_target_type == TypeManager.int64_type)
385 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
386 if (real_target_type == TypeManager.uint64_type)
387 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
388 if (real_target_type == TypeManager.double_type)
389 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
390 OpCodes.Conv_R8);
391 if (real_target_type == TypeManager.float_type)
392 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
393 OpCodes.Conv_R4);
394 if (real_target_type == TypeManager.decimal_type)
395 return new CastToDecimal (expr);
396 } else if (expr_type == TypeManager.int64_type){
398 // From long/ulong to float, double
400 if (real_target_type == TypeManager.double_type)
401 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
402 if (real_target_type == TypeManager.float_type)
403 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
404 if (real_target_type == TypeManager.decimal_type)
405 return new CastToDecimal (expr);
406 } else if (expr_type == TypeManager.uint64_type){
408 // From ulong to float, double
410 if (real_target_type == TypeManager.double_type)
411 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
412 OpCodes.Conv_R8);
413 if (real_target_type == TypeManager.float_type)
414 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
415 OpCodes.Conv_R4);
416 if (real_target_type == TypeManager.decimal_type)
417 return new CastToDecimal (expr);
418 } else if (expr_type == TypeManager.char_type){
420 // From char to ushort, int, uint, long, ulong, float, double, decimal
422 if ((real_target_type == TypeManager.ushort_type) ||
423 (real_target_type == TypeManager.int32_type) ||
424 (real_target_type == TypeManager.uint32_type))
425 return new EmptyCast (expr, target_type);
426 if (real_target_type == TypeManager.uint64_type)
427 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
428 if (real_target_type == TypeManager.int64_type)
429 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
430 if (real_target_type == TypeManager.float_type)
431 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
432 if (real_target_type == TypeManager.double_type)
433 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
434 if (real_target_type == TypeManager.decimal_type)
435 return new CastToDecimal (expr);
436 } else if (expr_type == TypeManager.float_type){
438 // float to double
440 if (real_target_type == TypeManager.double_type)
441 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
444 return null;
447 /// <summary>
448 /// Same as ImplicitStandardConversionExists except that it also looks at
449 /// implicit user defined conversions - needed for overload resolution
450 /// </summary>
451 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
453 if (ImplicitStandardConversionExists (expr, target_type))
454 return true;
456 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
459 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
461 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
464 /// <summary>
465 /// Determines if a standard implicit conversion exists from
466 /// expr_type to target_type
468 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
469 /// </summary>
470 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
472 Type expr_type = expr.Type;
474 if (expr_type == TypeManager.void_type)
475 return false;
477 if (expr_type == target_type)
478 return true;
481 // First numeric conversions
483 if (expr_type == TypeManager.sbyte_type){
485 // From sbyte to short, int, long, float, double, decimal
487 if ((target_type == TypeManager.int32_type) ||
488 (target_type == TypeManager.int64_type) ||
489 (target_type == TypeManager.double_type) ||
490 (target_type == TypeManager.float_type) ||
491 (target_type == TypeManager.short_type) ||
492 (target_type == TypeManager.decimal_type))
493 return true;
495 } else if (expr_type == TypeManager.byte_type){
497 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
499 if ((target_type == TypeManager.short_type) ||
500 (target_type == TypeManager.ushort_type) ||
501 (target_type == TypeManager.int32_type) ||
502 (target_type == TypeManager.uint32_type) ||
503 (target_type == TypeManager.uint64_type) ||
504 (target_type == TypeManager.int64_type) ||
505 (target_type == TypeManager.float_type) ||
506 (target_type == TypeManager.double_type) ||
507 (target_type == TypeManager.decimal_type))
508 return true;
510 } else if (expr_type == TypeManager.short_type){
512 // From short to int, long, double, float, decimal
514 if ((target_type == TypeManager.int32_type) ||
515 (target_type == TypeManager.int64_type) ||
516 (target_type == TypeManager.double_type) ||
517 (target_type == TypeManager.float_type) ||
518 (target_type == TypeManager.decimal_type))
519 return true;
521 } else if (expr_type == TypeManager.ushort_type){
523 // From ushort to int, uint, long, ulong, double, float, decimal
525 if ((target_type == TypeManager.uint32_type) ||
526 (target_type == TypeManager.uint64_type) ||
527 (target_type == TypeManager.int32_type) ||
528 (target_type == TypeManager.int64_type) ||
529 (target_type == TypeManager.double_type) ||
530 (target_type == TypeManager.float_type) ||
531 (target_type == TypeManager.decimal_type))
532 return true;
534 } else if (expr_type == TypeManager.int32_type){
536 // From int to long, double, float, decimal
538 if ((target_type == TypeManager.int64_type) ||
539 (target_type == TypeManager.double_type) ||
540 (target_type == TypeManager.float_type) ||
541 (target_type == TypeManager.decimal_type))
542 return true;
544 } else if (expr_type == TypeManager.uint32_type){
546 // From uint to long, ulong, double, float, decimal
548 if ((target_type == TypeManager.int64_type) ||
549 (target_type == TypeManager.uint64_type) ||
550 (target_type == TypeManager.double_type) ||
551 (target_type == TypeManager.float_type) ||
552 (target_type == TypeManager.decimal_type))
553 return true;
555 } else if ((expr_type == TypeManager.uint64_type) ||
556 (expr_type == TypeManager.int64_type)) {
558 // From long/ulong to double, float, decimal
560 if ((target_type == TypeManager.double_type) ||
561 (target_type == TypeManager.float_type) ||
562 (target_type == TypeManager.decimal_type))
563 return true;
565 } else if (expr_type == TypeManager.char_type){
567 // From char to ushort, int, uint, ulong, long, float, double, decimal
569 if ((target_type == TypeManager.ushort_type) ||
570 (target_type == TypeManager.int32_type) ||
571 (target_type == TypeManager.uint32_type) ||
572 (target_type == TypeManager.uint64_type) ||
573 (target_type == TypeManager.int64_type) ||
574 (target_type == TypeManager.float_type) ||
575 (target_type == TypeManager.double_type) ||
576 (target_type == TypeManager.decimal_type))
577 return true;
579 } else if (expr_type == TypeManager.float_type){
581 // float to double
583 if (target_type == TypeManager.double_type)
584 return true;
587 if (expr.eclass == ExprClass.MethodGroup){
588 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
589 MethodGroupExpr mg = expr as MethodGroupExpr;
590 if (mg != null){
591 return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null;
596 if (ImplicitReferenceConversionExists (expr, target_type))
597 return true;
600 // Implicit Constant Expression Conversions
602 if (expr is IntConstant){
603 int value = ((IntConstant) expr).Value;
605 if (target_type == TypeManager.sbyte_type){
606 if (value >= SByte.MinValue && value <= SByte.MaxValue)
607 return true;
608 } else if (target_type == TypeManager.byte_type){
609 if (value >= 0 && value <= Byte.MaxValue)
610 return true;
611 } else if (target_type == TypeManager.short_type){
612 if (value >= Int16.MinValue && value <= Int16.MaxValue)
613 return true;
614 } else if (target_type == TypeManager.ushort_type){
615 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
616 return true;
617 } else if (target_type == TypeManager.uint32_type){
618 if (value >= 0)
619 return true;
620 } else if (target_type == TypeManager.uint64_type){
622 // we can optimize this case: a positive int32
623 // always fits on a uint64. But we need an opcode
624 // to do it.
626 if (value >= 0)
627 return true;
630 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
631 return true;
634 if (expr is LongConstant && target_type == TypeManager.uint64_type){
636 // Try the implicit constant expression conversion
637 // from long to ulong, instead of a nice routine,
638 // we just inline it
640 long v = ((LongConstant) expr).Value;
641 if (v >= 0)
642 return true;
645 if ((target_type == TypeManager.enum_type ||
646 target_type.IsSubclassOf (TypeManager.enum_type)) &&
647 expr is IntLiteral){
648 IntLiteral i = (IntLiteral) expr;
650 if (i.Value == 0)
651 return true;
655 // If `expr_type' implements `target_type' (which is an iface)
656 // see TryImplicitIntConversion
658 if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
659 return true;
661 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
662 return true;
664 if (expr_type == TypeManager.anonymous_method_type){
665 if (!TypeManager.IsDelegateType (target_type))
666 return false;
668 AnonymousMethod am = (AnonymousMethod) expr;
669 return am.ImplicitStandardConversionExists (target_type);
672 return false;
675 /// <summary>
676 /// Finds "most encompassed type" according to the spec (13.4.2)
677 /// amongst the methods in the MethodGroupExpr
678 /// </summary>
679 static Type FindMostEncompassedType (ArrayList types)
681 Type best = null;
683 if (types.Count == 0)
684 return null;
686 if (types.Count == 1)
687 return (Type) types [0];
689 EmptyExpression expr = EmptyExpression.Grab ();
691 foreach (Type t in types) {
692 if (best == null) {
693 best = t;
694 continue;
697 expr.SetType (t);
698 if (ImplicitStandardConversionExists (expr, best))
699 best = t;
702 expr.SetType (best);
703 foreach (Type t in types) {
704 if (best == t)
705 continue;
706 if (!ImplicitStandardConversionExists (expr, t)) {
707 best = null;
708 break;
712 EmptyExpression.Release (expr);
714 return best;
717 /// <summary>
718 /// Finds "most encompassing type" according to the spec (13.4.2)
719 /// amongst the types in the given set
720 /// </summary>
721 static Type FindMostEncompassingType (ArrayList types)
723 Type best = null;
725 if (types.Count == 0)
726 return null;
728 if (types.Count == 1)
729 return (Type) types [0];
731 EmptyExpression expr = EmptyExpression.Grab ();
733 foreach (Type t in types) {
734 if (best == null) {
735 best = t;
736 continue;
739 expr.SetType (best);
740 if (ImplicitStandardConversionExists (expr, t))
741 best = t;
744 foreach (Type t in types) {
745 if (best == t)
746 continue;
747 expr.SetType (t);
748 if (!ImplicitStandardConversionExists (expr, best)) {
749 best = null;
750 break;
754 EmptyExpression.Release (expr);
756 return best;
759 /// <summary>
760 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
761 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
762 /// for explicit and implicit conversion operators.
763 /// </summary>
764 static public Type FindMostSpecificSource (IList list,
765 Expression source, bool apply_explicit_conv_rules)
767 ArrayList src_types_set = new ArrayList ();
770 // If any operator converts from S then Sx = S
772 Type source_type = source.Type;
773 foreach (MethodBase mb in list){
774 ParameterData pd = TypeManager.GetParameterData (mb);
775 Type param_type = pd.ParameterType (0);
777 if (param_type == source_type)
778 return param_type;
780 src_types_set.Add (param_type);
784 // Explicit Conv rules
786 if (apply_explicit_conv_rules) {
787 ArrayList candidate_set = new ArrayList ();
789 foreach (Type param_type in src_types_set){
790 if (ImplicitStandardConversionExists (source, param_type))
791 candidate_set.Add (param_type);
794 if (candidate_set.Count != 0)
795 return FindMostEncompassedType (candidate_set);
799 // Final case
801 if (apply_explicit_conv_rules)
802 return FindMostEncompassingType (src_types_set);
803 else
804 return FindMostEncompassedType (src_types_set);
807 /// <summary>
808 /// Finds the most specific target Tx according to section 13.4.4
809 /// </summary>
810 static public Type FindMostSpecificTarget (IList list,
811 Type target, bool apply_explicit_conv_rules)
813 ArrayList tgt_types_set = new ArrayList ();
816 // If any operator converts to T then Tx = T
818 foreach (MethodInfo mi in list){
819 Type ret_type = mi.ReturnType;
820 if (ret_type == target)
821 return ret_type;
823 tgt_types_set.Add (ret_type);
827 // Explicit conv rules
829 if (apply_explicit_conv_rules) {
830 ArrayList candidate_set = new ArrayList ();
832 EmptyExpression expr = EmptyExpression.Grab ();
834 foreach (Type ret_type in tgt_types_set){
835 expr.SetType (ret_type);
837 if (ImplicitStandardConversionExists (expr, target))
838 candidate_set.Add (ret_type);
841 EmptyExpression.Release (expr);
843 if (candidate_set.Count != 0)
844 return FindMostEncompassingType (candidate_set);
848 // Okay, final case !
850 if (apply_explicit_conv_rules)
851 return FindMostEncompassedType (tgt_types_set);
852 else
853 return FindMostEncompassingType (tgt_types_set);
856 /// <summary>
857 /// User-defined Implicit conversions
858 /// </summary>
859 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
860 Type target, Location loc)
862 return UserDefinedConversion (ec, source, target, loc, false);
865 /// <summary>
866 /// User-defined Explicit conversions
867 /// </summary>
868 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
869 Type target, Location loc)
871 return UserDefinedConversion (ec, source, target, loc, true);
874 static void AddConversionOperators (ArrayList list,
875 Expression source, Type target_type,
876 bool look_for_explicit,
877 MethodGroupExpr mg)
879 if (mg == null)
880 return;
882 Type source_type = source.Type;
883 EmptyExpression expr = EmptyExpression.Grab ();
884 foreach (MethodInfo m in mg.Methods) {
885 ParameterData pd = TypeManager.GetParameterData (m);
886 Type return_type = m.ReturnType;
887 Type arg_type = pd.ParameterType (0);
889 if (source_type != arg_type) {
890 if (!ImplicitStandardConversionExists (source, arg_type)) {
891 if (!look_for_explicit)
892 continue;
893 expr.SetType (arg_type);
894 if (!ImplicitStandardConversionExists (expr, source_type))
895 continue;
899 if (target_type != return_type) {
900 expr.SetType (return_type);
901 if (!ImplicitStandardConversionExists (expr, target_type)) {
902 if (!look_for_explicit)
903 continue;
904 expr.SetType (target_type);
905 if (!ImplicitStandardConversionExists (expr, return_type))
906 continue;
910 list.Add (m);
913 EmptyExpression.Release (expr);
916 /// <summary>
917 /// Compute the user-defined conversion operator from source_type to target_type.
918 /// `look_for_explicit' controls whether we should also include the list of explicit operators
919 /// </summary>
920 static MethodInfo GetConversionOperator (EmitContext ec, Expression source, Type target_type, bool look_for_explicit)
922 ArrayList ops = new ArrayList (4);
924 Type source_type = source.Type;
926 if (source_type != TypeManager.decimal_type) {
927 AddConversionOperators (ops, source, target_type, look_for_explicit,
928 Expression.MethodLookup (ec, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
929 if (look_for_explicit) {
930 AddConversionOperators (ops, source, target_type, look_for_explicit,
931 Expression.MethodLookup (
932 ec, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
936 if (target_type != TypeManager.decimal_type) {
937 AddConversionOperators (ops, source, target_type, look_for_explicit,
938 Expression.MethodLookup (ec, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
939 if (look_for_explicit) {
940 AddConversionOperators (ops, source, target_type, look_for_explicit,
941 Expression.MethodLookup (
942 ec, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
946 if (ops.Count == 0)
947 return null;
949 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
950 if (most_specific_source == null)
951 return null;
953 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
954 if (most_specific_target == null)
955 return null;
957 MethodInfo method = null;
959 foreach (MethodInfo m in ops) {
960 if (m.ReturnType != most_specific_target)
961 continue;
962 if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source)
963 continue;
964 // Ambiguous: more than one conversion operator satisfies the signature.
965 if (method != null)
966 return null;
967 method = m;
970 return method;
973 static DoubleHash explicit_conv = new DoubleHash (100);
974 static DoubleHash implicit_conv = new DoubleHash (100);
976 /// <summary>
977 /// User-defined conversions
978 /// </summary>
979 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
980 Type target, Location loc,
981 bool look_for_explicit)
983 Type source_type = source.Type;
984 MethodInfo method = null;
986 object o;
987 DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv;
989 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
990 method = (MethodInfo) o;
991 } else {
992 method = GetConversionOperator (ec, source, target, look_for_explicit);
993 if (!(source is Constant))
994 hash.Insert (source_type, target, method);
997 if (method == null)
998 return null;
1000 Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0);
1003 // This will do the conversion to the best match that we
1004 // found. Now we need to perform an implict standard conversion
1005 // if the best match was not the type that we were requested
1006 // by target.
1008 if (look_for_explicit)
1009 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1010 else
1011 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1013 if (source == null)
1014 return null;
1016 Expression e;
1017 e = new UserCast (method, source, loc);
1018 if (e.Type != target){
1019 if (!look_for_explicit)
1020 e = ImplicitConversionStandard (ec, e, target, loc);
1021 else
1022 e = ExplicitConversionStandard (ec, e, target, loc);
1025 return e;
1028 /// <summary>
1029 /// Converts implicitly the resolved expression `expr' into the
1030 /// `target_type'. It returns a new expression that can be used
1031 /// in a context that expects a `target_type'.
1032 /// </summary>
1033 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1034 Type target_type, Location loc)
1036 Expression e;
1038 if (target_type == null)
1039 throw new Exception ("Target type is null");
1041 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1042 if (e != null)
1043 return e;
1045 e = ImplicitUserConversion (ec, expr, target_type, loc);
1046 if (e != null)
1047 return e;
1049 return null;
1053 /// <summary>
1054 /// Attempts to apply the `Standard Implicit
1055 /// Conversion' rules to the expression `expr' into
1056 /// the `target_type'. It returns a new expression
1057 /// that can be used in a context that expects a
1058 /// `target_type'.
1060 /// This is different from `ImplicitConversion' in that the
1061 /// user defined implicit conversions are excluded.
1062 /// </summary>
1063 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1064 Type target_type, Location loc)
1066 Type expr_type = expr.Type;
1067 Expression e;
1069 if (expr.eclass == ExprClass.MethodGroup){
1070 if (!TypeManager.IsDelegateType (target_type)){
1071 return null;
1075 // Only allow anonymous method conversions on post ISO_1
1077 if (RootContext.Version != LanguageVersion.ISO_1){
1078 MethodGroupExpr mg = expr as MethodGroupExpr;
1079 if (mg != null)
1080 return ImplicitDelegateCreation.Create (
1081 ec, mg, target_type, loc);
1085 if (expr_type == target_type && expr_type != TypeManager.null_type)
1086 return expr;
1088 e = ImplicitNumericConversion (expr, target_type);
1089 if (e != null)
1090 return e;
1092 e = ImplicitReferenceConversion (expr, target_type);
1093 if (e != null)
1094 return e;
1096 if (TypeManager.IsEnumType (target_type) && expr is IntLiteral){
1097 IntLiteral i = (IntLiteral) expr;
1099 if (i.Value == 0)
1100 return new EnumConstant ((Constant) expr, target_type);
1103 if (ec.InUnsafe) {
1104 if (expr_type.IsPointer){
1105 if (target_type == TypeManager.void_ptr_type)
1106 return new EmptyCast (expr, target_type);
1109 // yep, comparing pointer types cant be done with
1110 // t1 == t2, we have to compare their element types.
1112 if (target_type.IsPointer){
1113 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1114 return expr;
1116 //return null;
1120 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1121 return new EmptyCast (NullPointer.Null, target_type);
1124 if (expr_type == TypeManager.anonymous_method_type){
1125 if (!TypeManager.IsDelegateType (target_type)){
1126 Report.Error (1660, loc,
1127 "Cannot convert anonymous method block to type `{0}' because it is not a delegate type",
1128 TypeManager.CSharpName (target_type));
1129 return null;
1132 AnonymousMethod am = (AnonymousMethod) expr;
1133 int errors = Report.Errors;
1135 Expression conv = am.Compatible (ec, target_type);
1136 if (conv != null)
1137 return conv;
1140 // We return something instead of null, to avoid
1141 // the duplicate error, since am.Compatible would have
1142 // reported that already
1144 if (errors != Report.Errors)
1145 return new EmptyCast (expr, target_type);
1148 return null;
1151 /// <summary>
1152 /// Attempts to perform an implicit constant conversion of the IntConstant
1153 /// into a different data type using casts (See Implicit Constant
1154 /// Expression Conversions)
1155 /// </summary>
1156 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1158 int value = ic.Value;
1160 if (target_type == TypeManager.sbyte_type){
1161 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1162 return new SByteConstant ((sbyte) value, ic.Location);
1163 } else if (target_type == TypeManager.byte_type){
1164 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1165 return new ByteConstant ((byte) value, ic.Location);
1166 } else if (target_type == TypeManager.short_type){
1167 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1168 return new ShortConstant ((short) value, ic.Location);
1169 } else if (target_type == TypeManager.ushort_type){
1170 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1171 return new UShortConstant ((ushort) value, ic.Location);
1172 } else if (target_type == TypeManager.uint32_type){
1173 if (value >= 0)
1174 return new UIntConstant ((uint) value, ic.Location);
1175 } else if (target_type == TypeManager.uint64_type){
1177 // we can optimize this case: a positive int32
1178 // always fits on a uint64. But we need an opcode
1179 // to do it.
1181 if (value >= 0)
1182 return new ULongConstant ((ulong) value, ic.Location);
1183 } else if (target_type == TypeManager.double_type)
1184 return new DoubleConstant ((double) value, ic.Location);
1185 else if (target_type == TypeManager.float_type)
1186 return new FloatConstant ((float) value, ic.Location);
1188 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1189 Type underlying = TypeManager.EnumToUnderlying (target_type);
1190 Constant e = (Constant) ic;
1193 // Possibly, we need to create a different 0 literal before passing
1194 // to EnumConstant
1196 if (underlying == TypeManager.int64_type)
1197 e = new LongLiteral (0, ic.Location);
1198 else if (underlying == TypeManager.uint64_type)
1199 e = new ULongLiteral (0, ic.Location);
1201 return new EnumConstant (e, target_type);
1205 // If `target_type' is an interface and the type of `ic' implements the interface
1206 // e.g. target_type is IComparable, IConvertible, IFormattable
1208 if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
1209 return new BoxedCast (ic, target_type);
1211 return null;
1214 /// <summary>
1215 /// Attempts to implicitly convert `source' into `target_type', using
1216 /// ImplicitConversion. If there is no implicit conversion, then
1217 /// an error is signaled
1218 /// </summary>
1219 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1220 Type target_type, Location loc)
1222 Expression e = ImplicitConversion (ec, source, target_type, loc);
1223 if (e != null)
1224 return e;
1226 source.Error_ValueCannotBeConverted (loc, target_type, false);
1227 return null;
1230 /// <summary>
1231 /// Performs the explicit numeric conversions
1232 /// </summary>
1233 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1235 Type expr_type = expr.Type;
1236 Type real_target_type = target_type;
1238 if (expr_type == TypeManager.sbyte_type){
1240 // From sbyte to byte, ushort, uint, ulong, char
1242 if (real_target_type == TypeManager.byte_type)
1243 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1244 if (real_target_type == TypeManager.ushort_type)
1245 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1246 if (real_target_type == TypeManager.uint32_type)
1247 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1248 if (real_target_type == TypeManager.uint64_type)
1249 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1250 if (real_target_type == TypeManager.char_type)
1251 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1252 } else if (expr_type == TypeManager.byte_type){
1254 // From byte to sbyte and char
1256 if (real_target_type == TypeManager.sbyte_type)
1257 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1258 if (real_target_type == TypeManager.char_type)
1259 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1260 } else if (expr_type == TypeManager.short_type){
1262 // From short to sbyte, byte, ushort, uint, ulong, char
1264 if (real_target_type == TypeManager.sbyte_type)
1265 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1266 if (real_target_type == TypeManager.byte_type)
1267 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1268 if (real_target_type == TypeManager.ushort_type)
1269 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1270 if (real_target_type == TypeManager.uint32_type)
1271 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1272 if (real_target_type == TypeManager.uint64_type)
1273 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1274 if (real_target_type == TypeManager.char_type)
1275 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1276 } else if (expr_type == TypeManager.ushort_type){
1278 // From ushort to sbyte, byte, short, char
1280 if (real_target_type == TypeManager.sbyte_type)
1281 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1282 if (real_target_type == TypeManager.byte_type)
1283 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1284 if (real_target_type == TypeManager.short_type)
1285 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1286 if (real_target_type == TypeManager.char_type)
1287 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1288 } else if (expr_type == TypeManager.int32_type){
1290 // From int to sbyte, byte, short, ushort, uint, ulong, char
1292 if (real_target_type == TypeManager.sbyte_type)
1293 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1294 if (real_target_type == TypeManager.byte_type)
1295 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1296 if (real_target_type == TypeManager.short_type)
1297 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1298 if (real_target_type == TypeManager.ushort_type)
1299 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1300 if (real_target_type == TypeManager.uint32_type)
1301 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1302 if (real_target_type == TypeManager.uint64_type)
1303 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1304 if (real_target_type == TypeManager.char_type)
1305 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1306 } else if (expr_type == TypeManager.uint32_type){
1308 // From uint to sbyte, byte, short, ushort, int, char
1310 if (real_target_type == TypeManager.sbyte_type)
1311 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1312 if (real_target_type == TypeManager.byte_type)
1313 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1314 if (real_target_type == TypeManager.short_type)
1315 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1316 if (real_target_type == TypeManager.ushort_type)
1317 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1318 if (real_target_type == TypeManager.int32_type)
1319 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1320 if (real_target_type == TypeManager.char_type)
1321 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1322 } else if (expr_type == TypeManager.int64_type){
1324 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1326 if (real_target_type == TypeManager.sbyte_type)
1327 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1328 if (real_target_type == TypeManager.byte_type)
1329 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1330 if (real_target_type == TypeManager.short_type)
1331 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1332 if (real_target_type == TypeManager.ushort_type)
1333 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1334 if (real_target_type == TypeManager.int32_type)
1335 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1336 if (real_target_type == TypeManager.uint32_type)
1337 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1338 if (real_target_type == TypeManager.uint64_type)
1339 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1340 if (real_target_type == TypeManager.char_type)
1341 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1342 } else if (expr_type == TypeManager.uint64_type){
1344 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1346 if (real_target_type == TypeManager.sbyte_type)
1347 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1348 if (real_target_type == TypeManager.byte_type)
1349 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1350 if (real_target_type == TypeManager.short_type)
1351 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1352 if (real_target_type == TypeManager.ushort_type)
1353 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1354 if (real_target_type == TypeManager.int32_type)
1355 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1356 if (real_target_type == TypeManager.uint32_type)
1357 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1358 if (real_target_type == TypeManager.int64_type)
1359 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1360 if (real_target_type == TypeManager.char_type)
1361 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1362 } else if (expr_type == TypeManager.char_type){
1364 // From char to sbyte, byte, short
1366 if (real_target_type == TypeManager.sbyte_type)
1367 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1368 if (real_target_type == TypeManager.byte_type)
1369 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1370 if (real_target_type == TypeManager.short_type)
1371 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1372 } else if (expr_type == TypeManager.float_type){
1374 // From float to sbyte, byte, short,
1375 // ushort, int, uint, long, ulong, char
1376 // or decimal
1378 if (real_target_type == TypeManager.sbyte_type)
1379 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1380 if (real_target_type == TypeManager.byte_type)
1381 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1382 if (real_target_type == TypeManager.short_type)
1383 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1384 if (real_target_type == TypeManager.ushort_type)
1385 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1386 if (real_target_type == TypeManager.int32_type)
1387 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1388 if (real_target_type == TypeManager.uint32_type)
1389 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1390 if (real_target_type == TypeManager.int64_type)
1391 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1392 if (real_target_type == TypeManager.uint64_type)
1393 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1394 if (real_target_type == TypeManager.char_type)
1395 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1396 if (real_target_type == TypeManager.decimal_type)
1397 return new CastToDecimal (expr, true);
1398 } else if (expr_type == TypeManager.double_type){
1400 // From double to sbyte, byte, short,
1401 // ushort, int, uint, long, ulong,
1402 // char, float or decimal
1404 if (real_target_type == TypeManager.sbyte_type)
1405 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1406 if (real_target_type == TypeManager.byte_type)
1407 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1408 if (real_target_type == TypeManager.short_type)
1409 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1410 if (real_target_type == TypeManager.ushort_type)
1411 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1412 if (real_target_type == TypeManager.int32_type)
1413 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1414 if (real_target_type == TypeManager.uint32_type)
1415 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1416 if (real_target_type == TypeManager.int64_type)
1417 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1418 if (real_target_type == TypeManager.uint64_type)
1419 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1420 if (real_target_type == TypeManager.char_type)
1421 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1422 if (real_target_type == TypeManager.float_type)
1423 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1424 if (real_target_type == TypeManager.decimal_type)
1425 return new CastToDecimal (expr, true);
1426 } else if (expr_type == TypeManager.decimal_type) {
1427 return new CastFromDecimal (expr, target_type).Resolve ();
1429 return null;
1432 /// <summary>
1433 /// Returns whether an explicit reference conversion can be performed
1434 /// from source_type to target_type
1435 /// </summary>
1436 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1438 bool target_is_value_type = target_type.IsValueType;
1440 if (source_type == target_type)
1441 return true;
1444 // From object to any reference type
1446 if (source_type == TypeManager.object_type && !target_is_value_type)
1447 return true;
1450 // From any class S to any class-type T, provided S is a base class of T
1452 if (target_type.IsSubclassOf (source_type))
1453 return true;
1456 // From any interface type S to any interface T provided S is not derived from T
1458 if (source_type.IsInterface && target_type.IsInterface){
1459 if (!target_type.IsSubclassOf (source_type))
1460 return true;
1464 // From any class type S to any interface T, provided S is not sealed
1465 // and provided S does not implement T.
1467 if (target_type.IsInterface && !source_type.IsSealed &&
1468 !TypeManager.ImplementsInterface (source_type, target_type))
1469 return true;
1472 // From any interface-type S to to any class type T, provided T is not
1473 // sealed, or provided T implements S.
1475 if (source_type.IsInterface &&
1476 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1477 return true;
1480 // From an array type S with an element type Se to an array type T with an
1481 // element type Te provided all the following are true:
1482 // * S and T differe only in element type, in other words, S and T
1483 // have the same number of dimensions.
1484 // * Both Se and Te are reference types
1485 // * An explicit referenc conversions exist from Se to Te
1487 if (source_type.IsArray && target_type.IsArray) {
1488 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1490 Type source_element_type = TypeManager.GetElementType (source_type);
1491 Type target_element_type = TypeManager.GetElementType (target_type);
1493 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1494 if (ExplicitReferenceConversionExists (source_element_type,
1495 target_element_type))
1496 return true;
1501 // From System.Array to any array-type
1502 if (source_type == TypeManager.array_type &&
1503 target_type.IsArray){
1504 return true;
1508 // From System delegate to any delegate-type
1510 if (source_type == TypeManager.delegate_type &&
1511 target_type.IsSubclassOf (TypeManager.delegate_type))
1512 return true;
1515 // From ICloneable to Array or Delegate types
1517 if (source_type == TypeManager.icloneable_type &&
1518 (target_type == TypeManager.array_type ||
1519 target_type == TypeManager.delegate_type))
1520 return true;
1522 return false;
1525 /// <summary>
1526 /// Implements Explicit Reference conversions
1527 /// </summary>
1528 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1530 Type source_type = source.Type;
1531 bool target_is_value_type = target_type.IsValueType;
1534 // From object to any reference type
1536 if (source_type == TypeManager.object_type && !target_is_value_type)
1537 return new ClassCast (source, target_type);
1540 // Unboxing conversion.
1542 if (((source_type == TypeManager.enum_type &&
1543 !(source is EmptyCast)) ||
1544 source_type == TypeManager.value_type) && target_is_value_type)
1545 return new UnboxCast (source, target_type);
1548 // From any class S to any class-type T, provided S is a base class of T
1550 if (target_type.IsSubclassOf (source_type))
1551 return new ClassCast (source, target_type);
1554 // From any interface type S to any interface T provided S is not derived from T
1556 if (source_type.IsInterface && target_type.IsInterface){
1557 if (TypeManager.ImplementsInterface (source_type, target_type))
1558 return null;
1559 else
1560 return new ClassCast (source, target_type);
1564 // From any class type S to any interface T, provides S is not sealed
1565 // and provided S does not implement T.
1567 if (target_type.IsInterface && !source_type.IsSealed) {
1568 if (TypeManager.ImplementsInterface (source_type, target_type))
1569 return null;
1570 else
1571 return new ClassCast (source, target_type);
1576 // From any interface-type S to to any class type T, provided T is not
1577 // sealed, or provided T implements S.
1579 if (source_type.IsInterface) {
1580 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1581 if (target_type.IsClass)
1582 return new ClassCast (source, target_type);
1583 else
1584 return new UnboxCast (source, target_type);
1587 return null;
1590 // From an array type S with an element type Se to an array type T with an
1591 // element type Te provided all the following are true:
1592 // * S and T differe only in element type, in other words, S and T
1593 // have the same number of dimensions.
1594 // * Both Se and Te are reference types
1595 // * An explicit referenc conversions exist from Se to Te
1597 if (source_type.IsArray && target_type.IsArray) {
1598 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1600 Type source_element_type = TypeManager.GetElementType (source_type);
1601 Type target_element_type = TypeManager.GetElementType (target_type);
1603 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1604 if (ExplicitReferenceConversionExists (source_element_type,
1605 target_element_type))
1606 return new ClassCast (source, target_type);
1611 // From System.Array to any array-type
1612 if (source_type == TypeManager.array_type &&
1613 target_type.IsArray) {
1614 return new ClassCast (source, target_type);
1618 // From System delegate to any delegate-type
1620 if (source_type == TypeManager.delegate_type &&
1621 TypeManager.IsDelegateType (target_type))
1622 return new ClassCast (source, target_type);
1625 // From ICloneable to Array or Delegate types
1627 if (source_type == TypeManager.icloneable_type &&
1628 (target_type == TypeManager.array_type ||
1629 target_type == TypeManager.delegate_type))
1630 return new ClassCast (source, target_type);
1632 return null;
1635 /// <summary>
1636 /// Performs an explicit conversion of the expression `expr' whose
1637 /// type is expr.Type to `target_type'.
1638 /// </summary>
1639 static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
1640 Type target_type, Location loc)
1642 Type expr_type = expr.Type;
1644 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1645 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1646 if (ne != null)
1647 return ne;
1650 // Unboxing conversions; only object types can be convertible to enum
1652 if (expr_type == TypeManager.object_type && target_type.IsValueType || expr_type == TypeManager.enum_type)
1653 return new UnboxCast (expr, target_type);
1655 if (TypeManager.IsEnumType (expr_type)) {
1656 if (expr is EnumConstant)
1657 return ExplicitConversionCore (ec, ((EnumConstant) expr).Child, target_type, loc);
1659 return ExplicitConversionCore (ec, new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)), target_type, loc);
1662 if (TypeManager.IsEnumType (target_type)){
1663 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.EnumToUnderlying (target_type), loc);
1664 if (ce != null)
1665 return new EmptyCast (ce, target_type);
1668 ne = ExplicitNumericConversion (expr, target_type);
1669 if (ne != null)
1670 return ne;
1673 // Skip the ExplicitReferenceConversion because we can not convert
1674 // from Null to a ValueType, and ExplicitReference wont check against
1675 // null literal explicitly
1677 if (expr_type != TypeManager.null_type){
1678 ne = ExplicitReferenceConversion (expr, target_type);
1679 if (ne != null)
1680 return ne;
1683 if (ec.InUnsafe){
1684 ne = ExplicitUnsafe (expr, target_type);
1685 if (ne != null)
1686 return ne;
1689 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1690 if (ne != null)
1691 return ne;
1693 return null;
1696 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1698 Type expr_type = expr.Type;
1700 if (target_type.IsPointer){
1701 if (expr_type.IsPointer)
1702 return new EmptyCast (expr, target_type);
1704 if (expr_type == TypeManager.sbyte_type ||
1705 expr_type == TypeManager.short_type ||
1706 expr_type == TypeManager.int32_type ||
1707 expr_type == TypeManager.int64_type)
1708 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1710 if (expr_type == TypeManager.ushort_type ||
1711 expr_type == TypeManager.uint32_type ||
1712 expr_type == TypeManager.uint64_type ||
1713 expr_type == TypeManager.byte_type)
1714 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1717 if (expr_type.IsPointer){
1718 if (target_type == TypeManager.sbyte_type)
1719 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1720 else if (target_type == TypeManager.byte_type)
1721 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1722 else if (target_type == TypeManager.short_type)
1723 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1724 else if (target_type == TypeManager.ushort_type)
1725 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1726 else if (target_type == TypeManager.int32_type)
1727 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1728 else if (target_type == TypeManager.uint32_type)
1729 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1730 else if (target_type == TypeManager.uint64_type)
1731 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1732 else if (target_type == TypeManager.int64_type){
1733 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1736 return null;
1739 /// <summary>
1740 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1741 /// </summary>
1742 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1743 Type target_type, Location l)
1745 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1746 if (ne != null)
1747 return ne;
1749 ne = ExplicitNumericConversion (expr, target_type);
1750 if (ne != null)
1751 return ne;
1753 ne = ExplicitReferenceConversion (expr, target_type);
1754 if (ne != null)
1755 return ne;
1757 if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1758 return new EmptyCast (expr, target_type);
1760 expr.Error_ValueCannotBeConverted (l, target_type, true);
1761 return null;
1764 /// <summary>
1765 /// Performs an explicit conversion of the expression `expr' whose
1766 /// type is expr.Type to `target_type'.
1767 /// </summary>
1768 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1769 Type target_type, Location loc)
1771 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1772 if (e != null)
1773 return e;
1775 expr.Error_ValueCannotBeConverted (loc, target_type, true);
1776 return null;