2006-04-27 Jonathan Chambers <jonathan.chambers@ansys.com>
[mcs.git] / gmcs / convert.cs
blob4a5c6a0a4ced44fa5e4dd0ff41e13077cf2ccd10
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 Expression TypeParameter_to_Null (Type target_type, Location loc)
25 if (!TypeParameter_to_Null (target_type)) {
26 Report.Error (403, loc, "Cannot convert null to the type " +
27 "parameter `{0}' becaues it could be a value " +
28 "type. Consider using `default ({0})' instead.",
29 target_type.ToString ());
30 return null;
33 Constant expr = new Nullable.NullableLiteral (target_type, loc);
34 return new NullCast (expr, target_type);
37 static bool TypeParameter_to_Null (Type target_type)
39 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
40 if (gc == null)
41 return false;
43 if (gc.HasReferenceTypeConstraint)
44 return true;
45 if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
46 return true;
48 return false;
51 static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
53 ArrayList list = new ArrayList ();
54 list.Add (gc.EffectiveBaseClass);
55 foreach (Type t in gc.InterfaceConstraints) {
56 if (!t.IsGenericParameter)
57 continue;
59 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
60 if (new_gc != null)
61 list.Add (TypeParam_EffectiveBaseType (new_gc));
63 return FindMostEncompassedType (list);
66 static Expression ImplicitTypeParameterConversion (Expression expr,
67 Type target_type)
69 Type expr_type = expr.Type;
71 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
73 if (gc == null) {
74 if (target_type == TypeManager.object_type)
75 return new BoxedCast (expr, target_type);
77 return null;
80 // We're converting from a type parameter which is known to be a reference type.
81 Type base_type = TypeParam_EffectiveBaseType (gc);
83 if (TypeManager.IsSubclassOf (base_type, target_type))
84 return new ClassCast (expr, target_type);
86 if (target_type.IsInterface) {
87 if (TypeManager.ImplementsInterface (base_type, target_type))
88 return new ClassCast (expr, target_type);
90 foreach (Type t in gc.InterfaceConstraints) {
91 if (TypeManager.IsSubclassOf (t, target_type))
92 return new ClassCast (expr, target_type);
93 if (TypeManager.ImplementsInterface (t, target_type))
94 return new ClassCast (expr, target_type);
98 foreach (Type t in gc.InterfaceConstraints) {
99 if (!t.IsGenericParameter)
100 continue;
101 if (TypeManager.IsSubclassOf (t, target_type))
102 return new ClassCast (expr, target_type);
103 if (TypeManager.ImplementsInterface (t, target_type))
104 return new ClassCast (expr, target_type);
107 return null;
110 static bool ExplicitTypeParameterConversionExists (Type source_type, Type target_type)
112 if (target_type.IsInterface)
113 return true;
115 if (target_type.IsGenericParameter) {
116 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
117 if (gc == null)
118 return false;
120 foreach (Type iface in gc.InterfaceConstraints) {
121 if (!iface.IsGenericParameter)
122 continue;
124 if (TypeManager.IsSubclassOf (source_type, iface))
125 return true;
129 return false;
132 static Expression ExplicitTypeParameterConversion (Expression source, Type target_type)
134 Type source_type = source.Type;
136 if (target_type.IsInterface)
137 return new ClassCast (source, target_type);
139 if (target_type.IsGenericParameter) {
140 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
141 if (gc == null)
142 return null;
144 foreach (Type iface in gc.InterfaceConstraints) {
145 if (!iface.IsGenericParameter)
146 continue;
148 if (TypeManager.IsSubclassOf (source_type, iface))
149 return new ClassCast (source, target_type);
153 return null;
156 static EmptyExpression MyEmptyExpr;
157 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
159 Type expr_type = expr.Type;
161 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
162 // if we are a method group, emit a warning
164 expr.Emit (null);
167 if (expr_type == TypeManager.void_type)
168 return null;
170 if (expr_type.IsGenericParameter)
171 return ImplicitTypeParameterConversion (expr, target_type);
174 // notice that it is possible to write "ValueType v = 1", the ValueType here
175 // is an abstract class, and not really a value type, so we apply the same rules.
177 if (target_type == TypeManager.object_type) {
179 // A pointer type cannot be converted to object
181 if (expr_type.IsPointer)
182 return null;
184 if (TypeManager.IsValueType (expr_type))
185 return new BoxedCast (expr, target_type);
186 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
187 if (expr_type == TypeManager.anonymous_method_type)
188 return null;
189 return new EmptyCast (expr, target_type);
192 return null;
193 } else if (target_type == TypeManager.value_type) {
194 if (TypeManager.IsValueType (expr_type))
195 return new BoxedCast (expr, target_type);
196 if (expr_type == TypeManager.null_type)
197 return new NullCast ((Constant)expr, target_type);
199 return null;
200 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
202 // Special case: enumeration to System.Enum.
203 // System.Enum is not a value type, it is a class, so we need
204 // a boxing conversion
206 if (expr_type.IsEnum || expr_type.IsGenericParameter)
207 return new BoxedCast (expr, target_type);
209 return new EmptyCast (expr, target_type);
212 // This code is kind of mirrored inside ImplicitStandardConversionExists
213 // with the small distinction that we only probe there
215 // Always ensure that the code here and there is in sync
217 // from the null type to any reference-type.
218 if (expr_type == TypeManager.null_type){
219 if (target_type.IsPointer)
220 return new EmptyCast (NullPointer.Null, target_type);
222 if (!target_type.IsValueType) {
223 if (expr is Constant)
224 return new NullCast ((Constant)expr, target_type);
226 // I found only one case when it happens -- Foo () ? null : null;
227 Report.Warning (-100, 1, expr.Location, "The result of the expression is always `null'");
228 return new NullCast (new NullLiteral (expr.Location), target_type);
232 // from any class-type S to any interface-type T.
233 if (target_type.IsInterface) {
234 if (target_type != TypeManager.iconvertible_type &&
235 expr_type.IsValueType && (expr is Constant) &&
236 !(expr is IntLiteral || expr is BoolLiteral ||
237 expr is FloatLiteral || expr is DoubleLiteral ||
238 expr is LongLiteral || expr is CharLiteral ||
239 expr is StringLiteral || expr is DecimalLiteral ||
240 expr is UIntLiteral || expr is ULongLiteral)) {
241 return null;
244 if (TypeManager.ImplementsInterface (expr_type, target_type)){
245 if (expr_type.IsGenericParameter || TypeManager.IsValueType (expr_type))
246 return new BoxedCast (expr, target_type);
247 else
248 return new EmptyCast (expr, target_type);
252 // from any interface type S to interface-type T.
253 if (expr_type.IsInterface && target_type.IsInterface) {
254 if (TypeManager.ImplementsInterface (expr_type, target_type))
255 return new EmptyCast (expr, target_type);
256 else
257 return null;
260 // from an array-type S to an array-type of type T
261 if (expr_type.IsArray && target_type.IsArray) {
262 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
264 Type expr_element_type = TypeManager.GetElementType (expr_type);
266 if (MyEmptyExpr == null)
267 MyEmptyExpr = new EmptyExpression ();
269 MyEmptyExpr.SetType (expr_element_type);
270 Type target_element_type = TypeManager.GetElementType (target_type);
272 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
273 if (ImplicitStandardConversionExists (MyEmptyExpr,
274 target_element_type))
275 return new EmptyCast (expr, target_type);
279 // from an array-type to System.Array
280 if (expr_type.IsArray && target_type == TypeManager.array_type)
281 return new EmptyCast (expr, target_type);
283 // from an array-type of type T to IEnumerable<T>
284 if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
285 return new EmptyCast (expr, target_type);
287 // from any delegate type to System.Delegate
288 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
289 target_type == TypeManager.delegate_type)
290 return new EmptyCast (expr, target_type);
292 // from any array-type or delegate type into System.ICloneable.
293 if (expr_type.IsArray ||
294 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
295 if (target_type == TypeManager.icloneable_type)
296 return new EmptyCast (expr, target_type);
298 // from a generic type definition to a generic instance.
299 if (TypeManager.IsEqual (expr_type, target_type))
300 return new EmptyCast (expr, target_type);
302 return null;
306 // Tests whether an implicit reference conversion exists between expr_type
307 // and target_type
309 public static bool ImplicitReferenceConversionExists (Expression expr, Type target_type)
311 if (target_type.IsValueType)
312 return false;
314 Type expr_type = expr.Type;
316 if (expr_type.IsGenericParameter)
317 return ImplicitTypeParameterConversion (expr, target_type) != null;
320 // This is the boxed case.
322 if (target_type == TypeManager.object_type) {
323 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
324 expr_type.IsInterface || expr_type == TypeManager.enum_type)
325 if (target_type != TypeManager.anonymous_method_type)
326 return true;
328 return false;
329 } else if (TypeManager.IsSubclassOf (expr_type, target_type))
330 return true;
332 // Please remember that all code below actually comes
333 // from ImplicitReferenceConversion so make sure code remains in sync
335 // from any class-type S to any interface-type T.
336 if (target_type.IsInterface) {
337 if (target_type != TypeManager.iconvertible_type &&
338 expr_type.IsValueType && (expr is Constant) &&
339 !(expr is IntLiteral || expr is BoolLiteral ||
340 expr is FloatLiteral || expr is DoubleLiteral ||
341 expr is LongLiteral || expr is CharLiteral ||
342 expr is StringLiteral || expr is DecimalLiteral ||
343 expr is UIntLiteral || expr is ULongLiteral)) {
344 return false;
347 if (TypeManager.ImplementsInterface (expr_type, target_type))
348 return true;
351 // from any interface type S to interface-type T.
352 if (expr_type.IsInterface && target_type.IsInterface)
353 if (TypeManager.ImplementsInterface (expr_type, target_type))
354 return true;
356 // from an array-type S to an array-type of type T
357 if (expr_type.IsArray && target_type.IsArray) {
358 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
360 Type expr_element_type = expr_type.GetElementType ();
362 if (MyEmptyExpr == null)
363 MyEmptyExpr = new EmptyExpression ();
365 MyEmptyExpr.SetType (expr_element_type);
366 Type target_element_type = TypeManager.GetElementType (target_type);
368 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
369 if (ImplicitStandardConversionExists (MyEmptyExpr,
370 target_element_type))
371 return true;
375 // from an array-type to System.Array
376 if (expr_type.IsArray && (target_type == TypeManager.array_type))
377 return true;
379 // from an array-type of type T to IEnumerable<T>
380 if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
381 return true;
383 // from any delegate type to System.Delegate
384 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
385 target_type == TypeManager.delegate_type)
386 if (target_type.IsAssignableFrom (expr_type))
387 return true;
389 // from any array-type or delegate type into System.ICloneable.
390 if (expr_type.IsArray ||
391 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
392 if (target_type == TypeManager.icloneable_type)
393 return true;
395 // from the null type to any reference-type.
396 if (expr_type == TypeManager.null_type){
397 if (target_type.IsPointer)
398 return true;
400 if (!target_type.IsValueType)
401 return true;
404 // from a generic type definition to a generic instance.
405 if (TypeManager.IsEqual (expr_type, target_type))
406 return true;
408 return false;
411 /// <summary>
412 /// Implicit Numeric Conversions.
414 /// expr is the expression to convert, returns a new expression of type
415 /// target_type or null if an implicit conversion is not possible.
416 /// </summary>
417 static public Expression ImplicitNumericConversion (Expression expr,
418 Type target_type)
420 Type expr_type = expr.Type;
423 // Attempt to do the implicit constant expression conversions
425 if (expr is Constant){
426 if (expr is IntConstant){
427 Expression e;
429 e = TryImplicitIntConversion (target_type, (IntConstant) expr);
431 if (e != null)
432 return e;
433 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
435 // Try the implicit constant expression conversion
436 // from long to ulong, instead of a nice routine,
437 // we just inline it
439 long v = ((LongConstant) expr).Value;
440 if (v >= 0)
441 return new ULongConstant ((ulong) v, expr.Location);
445 Type real_target_type = target_type;
447 if (expr_type == TypeManager.sbyte_type){
449 // From sbyte to short, int, long, float, double, decimal
451 if (real_target_type == TypeManager.int32_type)
452 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
453 if (real_target_type == TypeManager.int64_type)
454 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
455 if (real_target_type == TypeManager.double_type)
456 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
457 if (real_target_type == TypeManager.float_type)
458 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
459 if (real_target_type == TypeManager.short_type)
460 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
461 if (real_target_type == TypeManager.decimal_type)
462 return new CastToDecimal (expr);
463 } else if (expr_type == TypeManager.byte_type){
465 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
467 if ((real_target_type == TypeManager.short_type) ||
468 (real_target_type == TypeManager.ushort_type) ||
469 (real_target_type == TypeManager.int32_type) ||
470 (real_target_type == TypeManager.uint32_type))
471 return new EmptyCast (expr, target_type);
473 if (real_target_type == TypeManager.uint64_type)
474 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
475 if (real_target_type == TypeManager.int64_type)
476 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
477 if (real_target_type == TypeManager.float_type)
478 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
479 if (real_target_type == TypeManager.double_type)
480 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
481 if (real_target_type == TypeManager.decimal_type)
482 return new CastToDecimal (expr);
484 } else if (expr_type == TypeManager.short_type){
486 // From short to int, long, float, double, decimal
488 if (real_target_type == TypeManager.int32_type)
489 return new EmptyCast (expr, target_type);
490 if (real_target_type == TypeManager.int64_type)
491 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
492 if (real_target_type == TypeManager.double_type)
493 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
494 if (real_target_type == TypeManager.float_type)
495 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
496 if (real_target_type == TypeManager.decimal_type)
497 return new CastToDecimal (expr);
499 } else if (expr_type == TypeManager.ushort_type){
501 // From ushort to int, uint, long, ulong, float, double, decimal
503 if (real_target_type == TypeManager.uint32_type)
504 return new EmptyCast (expr, target_type);
506 if (real_target_type == TypeManager.uint64_type)
507 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
508 if (real_target_type == TypeManager.int32_type)
509 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
510 if (real_target_type == TypeManager.int64_type)
511 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
512 if (real_target_type == TypeManager.double_type)
513 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
514 if (real_target_type == TypeManager.float_type)
515 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
516 if (real_target_type == TypeManager.decimal_type)
517 return new CastToDecimal (expr);
518 } else if (expr_type == TypeManager.int32_type){
520 // From int to long, float, double, decimal
522 if (real_target_type == TypeManager.int64_type)
523 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
524 if (real_target_type == TypeManager.double_type)
525 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
526 if (real_target_type == TypeManager.float_type)
527 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
528 if (real_target_type == TypeManager.decimal_type)
529 return new CastToDecimal (expr);
530 } else if (expr_type == TypeManager.uint32_type){
532 // From uint to long, ulong, float, double, decimal
534 if (real_target_type == TypeManager.int64_type)
535 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
536 if (real_target_type == TypeManager.uint64_type)
537 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
538 if (real_target_type == TypeManager.double_type)
539 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
540 OpCodes.Conv_R8);
541 if (real_target_type == TypeManager.float_type)
542 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
543 OpCodes.Conv_R4);
544 if (real_target_type == TypeManager.decimal_type)
545 return new CastToDecimal (expr);
546 } else if (expr_type == TypeManager.int64_type){
548 // From long/ulong to float, double
550 if (real_target_type == TypeManager.double_type)
551 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
552 if (real_target_type == TypeManager.float_type)
553 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
554 if (real_target_type == TypeManager.decimal_type)
555 return new CastToDecimal (expr);
556 } else if (expr_type == TypeManager.uint64_type){
558 // From ulong to float, double
560 if (real_target_type == TypeManager.double_type)
561 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
562 OpCodes.Conv_R8);
563 if (real_target_type == TypeManager.float_type)
564 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
565 OpCodes.Conv_R4);
566 if (real_target_type == TypeManager.decimal_type)
567 return new CastToDecimal (expr);
568 } else if (expr_type == TypeManager.char_type){
570 // From char to ushort, int, uint, long, ulong, float, double, decimal
572 if ((real_target_type == TypeManager.ushort_type) ||
573 (real_target_type == TypeManager.int32_type) ||
574 (real_target_type == TypeManager.uint32_type))
575 return new EmptyCast (expr, target_type);
576 if (real_target_type == TypeManager.uint64_type)
577 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
578 if (real_target_type == TypeManager.int64_type)
579 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
580 if (real_target_type == TypeManager.float_type)
581 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
582 if (real_target_type == TypeManager.double_type)
583 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
584 if (real_target_type == TypeManager.decimal_type)
585 return new CastToDecimal (expr);
586 } else if (expr_type == TypeManager.float_type){
588 // float to double
590 if (real_target_type == TypeManager.double_type)
591 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
594 return null;
597 /// <summary>
598 /// Same as ImplicitStandardConversionExists except that it also looks at
599 /// implicit user defined conversions - needed for overload resolution
600 /// </summary>
601 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
603 if (expr is NullLiteral) {
604 if (target_type.IsGenericParameter)
605 return TypeParameter_to_Null (target_type);
607 if (TypeManager.IsNullableType (target_type))
608 return true;
611 if (ImplicitStandardConversionExists (expr, target_type))
612 return true;
614 return ImplicitUserConversion (ec, expr, target_type, Location.Null) != null;
617 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
619 return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
622 /// <summary>
623 /// Determines if a standard implicit conversion exists from
624 /// expr_type to target_type
626 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
627 /// </summary>
628 public static bool ImplicitStandardConversionExists (Expression expr, Type target_type)
630 Type expr_type = expr.Type;
632 if (expr_type == TypeManager.void_type)
633 return false;
635 //Console.WriteLine ("Expr is {0}", expr);
636 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
637 if (expr_type.Equals (target_type))
638 return true;
641 // First numeric conversions
643 if (expr_type == TypeManager.sbyte_type){
645 // From sbyte to short, int, long, float, double, decimal
647 if ((target_type == TypeManager.int32_type) ||
648 (target_type == TypeManager.int64_type) ||
649 (target_type == TypeManager.double_type) ||
650 (target_type == TypeManager.float_type) ||
651 (target_type == TypeManager.short_type) ||
652 (target_type == TypeManager.decimal_type))
653 return true;
655 } else if (expr_type == TypeManager.byte_type){
657 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
659 if ((target_type == TypeManager.short_type) ||
660 (target_type == TypeManager.ushort_type) ||
661 (target_type == TypeManager.int32_type) ||
662 (target_type == TypeManager.uint32_type) ||
663 (target_type == TypeManager.uint64_type) ||
664 (target_type == TypeManager.int64_type) ||
665 (target_type == TypeManager.float_type) ||
666 (target_type == TypeManager.double_type) ||
667 (target_type == TypeManager.decimal_type))
668 return true;
670 } else if (expr_type == TypeManager.short_type){
672 // From short to int, long, double, float, decimal
674 if ((target_type == TypeManager.int32_type) ||
675 (target_type == TypeManager.int64_type) ||
676 (target_type == TypeManager.double_type) ||
677 (target_type == TypeManager.float_type) ||
678 (target_type == TypeManager.decimal_type))
679 return true;
681 } else if (expr_type == TypeManager.ushort_type){
683 // From ushort to int, uint, long, ulong, double, float, decimal
685 if ((target_type == TypeManager.uint32_type) ||
686 (target_type == TypeManager.uint64_type) ||
687 (target_type == TypeManager.int32_type) ||
688 (target_type == TypeManager.int64_type) ||
689 (target_type == TypeManager.double_type) ||
690 (target_type == TypeManager.float_type) ||
691 (target_type == TypeManager.decimal_type))
692 return true;
694 } else if (expr_type == TypeManager.int32_type){
696 // From int to long, double, float, decimal
698 if ((target_type == TypeManager.int64_type) ||
699 (target_type == TypeManager.double_type) ||
700 (target_type == TypeManager.float_type) ||
701 (target_type == TypeManager.decimal_type))
702 return true;
704 } else if (expr_type == TypeManager.uint32_type){
706 // From uint to long, ulong, double, float, decimal
708 if ((target_type == TypeManager.int64_type) ||
709 (target_type == TypeManager.uint64_type) ||
710 (target_type == TypeManager.double_type) ||
711 (target_type == TypeManager.float_type) ||
712 (target_type == TypeManager.decimal_type))
713 return true;
715 } else if ((expr_type == TypeManager.uint64_type) ||
716 (expr_type == TypeManager.int64_type)) {
718 // From long/ulong to double, float, decimal
720 if ((target_type == TypeManager.double_type) ||
721 (target_type == TypeManager.float_type) ||
722 (target_type == TypeManager.decimal_type))
723 return true;
725 } else if (expr_type == TypeManager.char_type){
727 // From char to ushort, int, uint, ulong, long, float, double, decimal
729 if ((target_type == TypeManager.ushort_type) ||
730 (target_type == TypeManager.int32_type) ||
731 (target_type == TypeManager.uint32_type) ||
732 (target_type == TypeManager.uint64_type) ||
733 (target_type == TypeManager.int64_type) ||
734 (target_type == TypeManager.float_type) ||
735 (target_type == TypeManager.double_type) ||
736 (target_type == TypeManager.decimal_type))
737 return true;
739 } else if (expr_type == TypeManager.float_type){
741 // float to double
743 if (target_type == TypeManager.double_type)
744 return true;
747 if (expr.eclass == ExprClass.MethodGroup){
748 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
749 MethodGroupExpr mg = expr as MethodGroupExpr;
750 if (mg != null){
751 return DelegateCreation.ImplicitStandardConversionExists (mg, target_type) != null;
756 if (ImplicitReferenceConversionExists (expr, target_type))
757 return true;
760 // Implicit Constant Expression Conversions
762 if (expr is IntConstant){
763 int value = ((IntConstant) expr).Value;
765 if (target_type == TypeManager.sbyte_type){
766 if (value >= SByte.MinValue && value <= SByte.MaxValue)
767 return true;
768 } else if (target_type == TypeManager.byte_type){
769 if (value >= 0 && value <= Byte.MaxValue)
770 return true;
771 } else if (target_type == TypeManager.short_type){
772 if (value >= Int16.MinValue && value <= Int16.MaxValue)
773 return true;
774 } else if (target_type == TypeManager.ushort_type){
775 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
776 return true;
777 } else if (target_type == TypeManager.uint32_type){
778 if (value >= 0)
779 return true;
780 } else if (target_type == TypeManager.uint64_type){
782 // we can optimize this case: a positive int32
783 // always fits on a uint64. But we need an opcode
784 // to do it.
786 if (value >= 0)
787 return true;
790 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
791 return true;
794 if (expr is LongConstant && target_type == TypeManager.uint64_type){
796 // Try the implicit constant expression conversion
797 // from long to ulong, instead of a nice routine,
798 // we just inline it
800 long v = ((LongConstant) expr).Value;
801 if (v >= 0)
802 return true;
805 if ((target_type == TypeManager.enum_type ||
806 target_type.IsSubclassOf (TypeManager.enum_type)) &&
807 expr is IntLiteral){
808 IntLiteral i = (IntLiteral) expr;
810 if (i.Value == 0)
811 return true;
815 // If `expr_type' implements `target_type' (which is an iface)
816 // see TryImplicitIntConversion
818 if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
819 return true;
821 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
822 return true;
824 if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
825 return true;
827 if (expr_type == TypeManager.anonymous_method_type){
828 if (!TypeManager.IsDelegateType (target_type))
829 return false;
831 AnonymousMethod am = (AnonymousMethod) expr;
832 return am.ImplicitStandardConversionExists (target_type);
835 return false;
838 /// <summary>
839 /// Finds "most encompassed type" according to the spec (13.4.2)
840 /// amongst the methods in the MethodGroupExpr
841 /// </summary>
842 static Type FindMostEncompassedType (ArrayList types)
844 Type best = null;
846 if (types.Count == 0)
847 return null;
849 if (types.Count == 1)
850 return (Type) types [0];
852 EmptyExpression expr = EmptyExpression.Grab ();
854 foreach (Type t in types) {
855 if (best == null) {
856 best = t;
857 continue;
860 expr.SetType (t);
861 if (ImplicitStandardConversionExists (expr, best))
862 best = t;
865 expr.SetType (best);
866 foreach (Type t in types) {
867 if (best == t)
868 continue;
869 if (!ImplicitStandardConversionExists (expr, t)) {
870 best = null;
871 break;
875 EmptyExpression.Release (expr);
877 return best;
880 /// <summary>
881 /// Finds "most encompassing type" according to the spec (13.4.2)
882 /// amongst the types in the given set
883 /// </summary>
884 static Type FindMostEncompassingType (ArrayList types)
886 Type best = null;
888 if (types.Count == 0)
889 return null;
891 if (types.Count == 1)
892 return (Type) types [0];
894 EmptyExpression expr = EmptyExpression.Grab ();
896 foreach (Type t in types) {
897 if (best == null) {
898 best = t;
899 continue;
902 expr.SetType (best);
903 if (ImplicitStandardConversionExists (expr, t))
904 best = t;
907 foreach (Type t in types) {
908 if (best == t)
909 continue;
910 expr.SetType (t);
911 if (!ImplicitStandardConversionExists (expr, best)) {
912 best = null;
913 break;
917 EmptyExpression.Release (expr);
919 return best;
922 /// <summary>
923 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
924 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
925 /// for explicit and implicit conversion operators.
926 /// </summary>
927 static public Type FindMostSpecificSource (IList list,
928 Expression source, bool apply_explicit_conv_rules)
930 ArrayList src_types_set = new ArrayList ();
933 // If any operator converts from S then Sx = S
935 Type source_type = source.Type;
936 foreach (MethodBase mb in list){
937 ParameterData pd = TypeManager.GetParameterData (mb);
938 Type param_type = pd.ParameterType (0);
940 if (param_type == source_type)
941 return param_type;
943 src_types_set.Add (param_type);
947 // Explicit Conv rules
949 if (apply_explicit_conv_rules) {
950 ArrayList candidate_set = new ArrayList ();
952 foreach (Type param_type in src_types_set){
953 if (ImplicitStandardConversionExists (source, param_type))
954 candidate_set.Add (param_type);
957 if (candidate_set.Count != 0)
958 return FindMostEncompassedType (candidate_set);
962 // Final case
964 if (apply_explicit_conv_rules)
965 return FindMostEncompassingType (src_types_set);
966 else
967 return FindMostEncompassedType (src_types_set);
970 /// <summary>
971 /// Finds the most specific target Tx according to section 13.4.4
972 /// </summary>
973 static public Type FindMostSpecificTarget (IList list,
974 Type target, bool apply_explicit_conv_rules)
976 ArrayList tgt_types_set = new ArrayList ();
979 // If any operator converts to T then Tx = T
981 foreach (MethodInfo mi in list){
982 Type ret_type = mi.ReturnType;
983 if (ret_type == target)
984 return ret_type;
986 tgt_types_set.Add (ret_type);
990 // Explicit conv rules
992 if (apply_explicit_conv_rules) {
993 ArrayList candidate_set = new ArrayList ();
995 EmptyExpression expr = EmptyExpression.Grab ();
997 foreach (Type ret_type in tgt_types_set){
998 expr.SetType (ret_type);
1000 if (ImplicitStandardConversionExists (expr, target))
1001 candidate_set.Add (ret_type);
1004 EmptyExpression.Release (expr);
1006 if (candidate_set.Count != 0)
1007 return FindMostEncompassingType (candidate_set);
1011 // Okay, final case !
1013 if (apply_explicit_conv_rules)
1014 return FindMostEncompassedType (tgt_types_set);
1015 else
1016 return FindMostEncompassingType (tgt_types_set);
1019 /// <summary>
1020 /// User-defined Implicit conversions
1021 /// </summary>
1022 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1023 Type target, Location loc)
1025 return UserDefinedConversion (ec, source, target, loc, false);
1028 /// <summary>
1029 /// User-defined Explicit conversions
1030 /// </summary>
1031 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1032 Type target, Location loc)
1034 return UserDefinedConversion (ec, source, target, loc, true);
1037 static void AddConversionOperators (ArrayList list,
1038 Expression source, Type target_type,
1039 bool look_for_explicit,
1040 MethodGroupExpr mg)
1042 if (mg == null)
1043 return;
1045 Type source_type = source.Type;
1046 EmptyExpression expr = EmptyExpression.Grab ();
1047 foreach (MethodInfo m in mg.Methods) {
1048 ParameterData pd = TypeManager.GetParameterData (m);
1049 Type return_type = m.ReturnType;
1050 Type arg_type = pd.ParameterType (0);
1052 if (source_type != arg_type) {
1053 if (!ImplicitStandardConversionExists (source, arg_type)) {
1054 if (!look_for_explicit)
1055 continue;
1056 expr.SetType (arg_type);
1057 if (!ImplicitStandardConversionExists (expr, source_type))
1058 continue;
1062 if (target_type != return_type) {
1063 expr.SetType (return_type);
1064 if (!ImplicitStandardConversionExists (expr, target_type)) {
1065 if (!look_for_explicit)
1066 continue;
1067 expr.SetType (target_type);
1068 if (!ImplicitStandardConversionExists (expr, return_type))
1069 continue;
1073 list.Add (m);
1076 EmptyExpression.Release (expr);
1079 /// <summary>
1080 /// Compute the user-defined conversion operator from source_type to target_type.
1081 /// `look_for_explicit' controls whether we should also include the list of explicit operators
1082 /// </summary>
1083 static MethodInfo GetConversionOperator (EmitContext ec, Expression source, Type target_type, bool look_for_explicit)
1085 ArrayList ops = new ArrayList (4);
1087 Type source_type = source.Type;
1089 if (source_type != TypeManager.decimal_type) {
1090 AddConversionOperators (ops, source, target_type, look_for_explicit,
1091 Expression.MethodLookup (ec, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1092 if (look_for_explicit) {
1093 AddConversionOperators (ops, source, target_type, look_for_explicit,
1094 Expression.MethodLookup (
1095 ec, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1099 if (target_type != TypeManager.decimal_type) {
1100 AddConversionOperators (ops, source, target_type, look_for_explicit,
1101 Expression.MethodLookup (ec, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1102 if (look_for_explicit) {
1103 AddConversionOperators (ops, source, target_type, look_for_explicit,
1104 Expression.MethodLookup (
1105 ec, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1109 if (ops.Count == 0)
1110 return null;
1112 Type most_specific_source = FindMostSpecificSource (ops, source, look_for_explicit);
1113 if (most_specific_source == null)
1114 return null;
1116 Type most_specific_target = FindMostSpecificTarget (ops, target_type, look_for_explicit);
1117 if (most_specific_target == null)
1118 return null;
1120 MethodInfo method = null;
1122 foreach (MethodInfo m in ops) {
1123 if (m.ReturnType != most_specific_target)
1124 continue;
1125 if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source)
1126 continue;
1127 // Ambiguous: more than one conversion operator satisfies the signature.
1128 if (method != null)
1129 return null;
1130 method = m;
1133 return method;
1136 static DoubleHash explicit_conv = new DoubleHash (100);
1137 static DoubleHash implicit_conv = new DoubleHash (100);
1139 /// <summary>
1140 /// User-defined conversions
1141 /// </summary>
1142 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1143 Type target, Location loc,
1144 bool look_for_explicit)
1146 Type source_type = source.Type;
1147 MethodInfo method = null;
1149 if (TypeManager.IsNullableType (source_type) && TypeManager.IsNullableType (target))
1150 return new Nullable.LiftedConversion (
1151 source, target, true, look_for_explicit, loc).Resolve (ec);
1153 object o;
1154 DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv;
1156 if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1157 method = (MethodInfo) o;
1158 } else {
1159 method = GetConversionOperator (ec, source, target, look_for_explicit);
1160 if (!(source is Constant))
1161 hash.Insert (source_type, target, method);
1164 if (method == null)
1165 return null;
1167 Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0);
1170 // This will do the conversion to the best match that we
1171 // found. Now we need to perform an implict standard conversion
1172 // if the best match was not the type that we were requested
1173 // by target.
1175 if (look_for_explicit)
1176 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1177 else
1178 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1180 if (source == null)
1181 return null;
1183 Expression e;
1184 e = new UserCast (method, source, loc);
1185 if (e.Type != target){
1186 if (!look_for_explicit)
1187 e = ImplicitConversionStandard (ec, e, target, loc);
1188 else
1189 e = ExplicitConversionStandard (ec, e, target, loc);
1192 return e;
1195 /// <summary>
1196 /// Converts implicitly the resolved expression `expr' into the
1197 /// `target_type'. It returns a new expression that can be used
1198 /// in a context that expects a `target_type'.
1199 /// </summary>
1200 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1201 Type target_type, Location loc)
1203 Expression e;
1205 if (target_type == null)
1206 throw new Exception ("Target type is null");
1208 e = ImplicitConversionStandard (ec, expr, target_type, loc);
1209 if (e != null)
1210 return e;
1212 e = ImplicitUserConversion (ec, expr, target_type, loc);
1213 if (e != null)
1214 return e;
1216 return null;
1220 /// <summary>
1221 /// Attempts to apply the `Standard Implicit
1222 /// Conversion' rules to the expression `expr' into
1223 /// the `target_type'. It returns a new expression
1224 /// that can be used in a context that expects a
1225 /// `target_type'.
1227 /// This is different from `ImplicitConversion' in that the
1228 /// user defined implicit conversions are excluded.
1229 /// </summary>
1230 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1231 Type target_type, Location loc)
1233 Type expr_type = expr.Type;
1234 Expression e;
1236 if (expr is NullLiteral) {
1237 if (target_type.IsGenericParameter)
1238 return TypeParameter_to_Null (target_type, loc);
1240 if (TypeManager.IsNullableType (target_type))
1241 return new Nullable.NullableLiteral (target_type, loc);
1244 if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
1245 return new Nullable.LiftedConversion (
1246 expr, target_type, false, false, loc).Resolve (ec);
1248 if (expr.eclass == ExprClass.MethodGroup){
1249 if (!TypeManager.IsDelegateType (target_type)){
1250 return null;
1254 // Only allow anonymous method conversions on post ISO_1
1256 if (RootContext.Version != LanguageVersion.ISO_1){
1257 MethodGroupExpr mg = expr as MethodGroupExpr;
1258 if (mg != null)
1259 return ImplicitDelegateCreation.Create (
1260 ec, mg, target_type, loc);
1264 if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
1265 return expr;
1267 e = ImplicitNumericConversion (expr, target_type);
1268 if (e != null)
1269 return e;
1271 e = ImplicitReferenceConversion (expr, target_type);
1272 if (e != null)
1273 return e;
1275 if (TypeManager.IsEnumType (target_type) && expr is IntLiteral){
1276 IntLiteral i = (IntLiteral) expr;
1278 if (i.Value == 0)
1279 return new EnumConstant ((Constant) expr, target_type);
1282 if (ec.InUnsafe) {
1283 if (expr_type.IsPointer){
1284 if (target_type == TypeManager.void_ptr_type)
1285 return new EmptyCast (expr, target_type);
1288 // yep, comparing pointer types cant be done with
1289 // t1 == t2, we have to compare their element types.
1291 if (target_type.IsPointer){
1292 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1293 return expr;
1295 //return null;
1299 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1300 return new EmptyCast (NullPointer.Null, target_type);
1303 if (expr_type == TypeManager.anonymous_method_type){
1304 if (!TypeManager.IsDelegateType (target_type)){
1305 Report.Error (1660, loc,
1306 "Cannot convert anonymous method block to type `{0}' because it is not a delegate type",
1307 TypeManager.CSharpName (target_type));
1308 return null;
1311 AnonymousMethod am = (AnonymousMethod) expr;
1312 int errors = Report.Errors;
1314 Expression conv = am.Compatible (ec, target_type);
1315 if (conv != null)
1316 return conv;
1319 // We return something instead of null, to avoid
1320 // the duplicate error, since am.Compatible would have
1321 // reported that already
1323 if (errors != Report.Errors)
1324 return new EmptyCast (expr, target_type);
1327 return null;
1330 /// <summary>
1331 /// Attempts to perform an implicit constant conversion of the IntConstant
1332 /// into a different data type using casts (See Implicit Constant
1333 /// Expression Conversions)
1334 /// </summary>
1335 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1337 int value = ic.Value;
1339 if (target_type == TypeManager.sbyte_type){
1340 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1341 return new SByteConstant ((sbyte) value, ic.Location);
1342 } else if (target_type == TypeManager.byte_type){
1343 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1344 return new ByteConstant ((byte) value, ic.Location);
1345 } else if (target_type == TypeManager.short_type){
1346 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1347 return new ShortConstant ((short) value, ic.Location);
1348 } else if (target_type == TypeManager.ushort_type){
1349 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1350 return new UShortConstant ((ushort) value, ic.Location);
1351 } else if (target_type == TypeManager.uint32_type){
1352 if (value >= 0)
1353 return new UIntConstant ((uint) value, ic.Location);
1354 } else if (target_type == TypeManager.uint64_type){
1356 // we can optimize this case: a positive int32
1357 // always fits on a uint64. But we need an opcode
1358 // to do it.
1360 if (value >= 0)
1361 return new ULongConstant ((ulong) value, ic.Location);
1362 } else if (target_type == TypeManager.double_type)
1363 return new DoubleConstant ((double) value, ic.Location);
1364 else if (target_type == TypeManager.float_type)
1365 return new FloatConstant ((float) value, ic.Location);
1367 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1368 Type underlying = TypeManager.EnumToUnderlying (target_type);
1369 Constant e = (Constant) ic;
1372 // Possibly, we need to create a different 0 literal before passing
1373 // to EnumConstant
1375 if (underlying == TypeManager.int64_type)
1376 e = new LongLiteral (0, ic.Location);
1377 else if (underlying == TypeManager.uint64_type)
1378 e = new ULongLiteral (0, ic.Location);
1380 return new EnumConstant (e, target_type);
1384 // If `target_type' is an interface and the type of `ic' implements the interface
1385 // e.g. target_type is IComparable, IConvertible, IFormattable
1387 if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
1388 return new BoxedCast (ic, target_type);
1390 return null;
1393 /// <summary>
1394 /// Attempts to implicitly convert `source' into `target_type', using
1395 /// ImplicitConversion. If there is no implicit conversion, then
1396 /// an error is signaled
1397 /// </summary>
1398 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1399 Type target_type, Location loc)
1401 Expression e = ImplicitConversion (ec, source, target_type, loc);
1402 if (e != null)
1403 return e;
1405 source.Error_ValueCannotBeConverted (loc, target_type, false);
1406 return null;
1409 /// <summary>
1410 /// Performs the explicit numeric conversions
1411 /// </summary>
1412 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1414 Type expr_type = expr.Type;
1415 Type real_target_type = target_type;
1417 if (expr_type == TypeManager.sbyte_type){
1419 // From sbyte to byte, ushort, uint, ulong, char
1421 if (real_target_type == TypeManager.byte_type)
1422 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1423 if (real_target_type == TypeManager.ushort_type)
1424 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1425 if (real_target_type == TypeManager.uint32_type)
1426 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1427 if (real_target_type == TypeManager.uint64_type)
1428 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1429 if (real_target_type == TypeManager.char_type)
1430 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1431 } else if (expr_type == TypeManager.byte_type){
1433 // From byte to sbyte and char
1435 if (real_target_type == TypeManager.sbyte_type)
1436 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1437 if (real_target_type == TypeManager.char_type)
1438 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1439 } else if (expr_type == TypeManager.short_type){
1441 // From short to sbyte, byte, ushort, uint, ulong, char
1443 if (real_target_type == TypeManager.sbyte_type)
1444 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1445 if (real_target_type == TypeManager.byte_type)
1446 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1447 if (real_target_type == TypeManager.ushort_type)
1448 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1449 if (real_target_type == TypeManager.uint32_type)
1450 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1451 if (real_target_type == TypeManager.uint64_type)
1452 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1453 if (real_target_type == TypeManager.char_type)
1454 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1455 } else if (expr_type == TypeManager.ushort_type){
1457 // From ushort to sbyte, byte, short, char
1459 if (real_target_type == TypeManager.sbyte_type)
1460 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1461 if (real_target_type == TypeManager.byte_type)
1462 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1463 if (real_target_type == TypeManager.short_type)
1464 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1465 if (real_target_type == TypeManager.char_type)
1466 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1467 } else if (expr_type == TypeManager.int32_type){
1469 // From int to sbyte, byte, short, ushort, uint, ulong, char
1471 if (real_target_type == TypeManager.sbyte_type)
1472 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1473 if (real_target_type == TypeManager.byte_type)
1474 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1475 if (real_target_type == TypeManager.short_type)
1476 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1477 if (real_target_type == TypeManager.ushort_type)
1478 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1479 if (real_target_type == TypeManager.uint32_type)
1480 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1481 if (real_target_type == TypeManager.uint64_type)
1482 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1483 if (real_target_type == TypeManager.char_type)
1484 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1485 } else if (expr_type == TypeManager.uint32_type){
1487 // From uint to sbyte, byte, short, ushort, int, char
1489 if (real_target_type == TypeManager.sbyte_type)
1490 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1491 if (real_target_type == TypeManager.byte_type)
1492 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1493 if (real_target_type == TypeManager.short_type)
1494 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1495 if (real_target_type == TypeManager.ushort_type)
1496 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1497 if (real_target_type == TypeManager.int32_type)
1498 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1499 if (real_target_type == TypeManager.char_type)
1500 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1501 } else if (expr_type == TypeManager.int64_type){
1503 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1505 if (real_target_type == TypeManager.sbyte_type)
1506 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1507 if (real_target_type == TypeManager.byte_type)
1508 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1509 if (real_target_type == TypeManager.short_type)
1510 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1511 if (real_target_type == TypeManager.ushort_type)
1512 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1513 if (real_target_type == TypeManager.int32_type)
1514 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1515 if (real_target_type == TypeManager.uint32_type)
1516 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1517 if (real_target_type == TypeManager.uint64_type)
1518 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1519 if (real_target_type == TypeManager.char_type)
1520 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1521 } else if (expr_type == TypeManager.uint64_type){
1523 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1525 if (real_target_type == TypeManager.sbyte_type)
1526 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1527 if (real_target_type == TypeManager.byte_type)
1528 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1529 if (real_target_type == TypeManager.short_type)
1530 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1531 if (real_target_type == TypeManager.ushort_type)
1532 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1533 if (real_target_type == TypeManager.int32_type)
1534 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1535 if (real_target_type == TypeManager.uint32_type)
1536 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1537 if (real_target_type == TypeManager.int64_type)
1538 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1539 if (real_target_type == TypeManager.char_type)
1540 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1541 } else if (expr_type == TypeManager.char_type){
1543 // From char to sbyte, byte, short
1545 if (real_target_type == TypeManager.sbyte_type)
1546 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1547 if (real_target_type == TypeManager.byte_type)
1548 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1549 if (real_target_type == TypeManager.short_type)
1550 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1551 } else if (expr_type == TypeManager.float_type){
1553 // From float to sbyte, byte, short,
1554 // ushort, int, uint, long, ulong, char
1555 // or decimal
1557 if (real_target_type == TypeManager.sbyte_type)
1558 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1559 if (real_target_type == TypeManager.byte_type)
1560 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1561 if (real_target_type == TypeManager.short_type)
1562 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1563 if (real_target_type == TypeManager.ushort_type)
1564 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1565 if (real_target_type == TypeManager.int32_type)
1566 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1567 if (real_target_type == TypeManager.uint32_type)
1568 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1569 if (real_target_type == TypeManager.int64_type)
1570 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1571 if (real_target_type == TypeManager.uint64_type)
1572 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1573 if (real_target_type == TypeManager.char_type)
1574 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1575 if (real_target_type == TypeManager.decimal_type)
1576 return new CastToDecimal (expr, true);
1577 } else if (expr_type == TypeManager.double_type){
1579 // From double to sbyte, byte, short,
1580 // ushort, int, uint, long, ulong,
1581 // char, float or decimal
1583 if (real_target_type == TypeManager.sbyte_type)
1584 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1585 if (real_target_type == TypeManager.byte_type)
1586 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1587 if (real_target_type == TypeManager.short_type)
1588 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1589 if (real_target_type == TypeManager.ushort_type)
1590 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1591 if (real_target_type == TypeManager.int32_type)
1592 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1593 if (real_target_type == TypeManager.uint32_type)
1594 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1595 if (real_target_type == TypeManager.int64_type)
1596 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1597 if (real_target_type == TypeManager.uint64_type)
1598 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1599 if (real_target_type == TypeManager.char_type)
1600 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1601 if (real_target_type == TypeManager.float_type)
1602 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1603 if (real_target_type == TypeManager.decimal_type)
1604 return new CastToDecimal (expr, true);
1605 } else if (expr_type == TypeManager.decimal_type) {
1606 return new CastFromDecimal (expr, target_type).Resolve ();
1608 return null;
1611 /// <summary>
1612 /// Returns whether an explicit reference conversion can be performed
1613 /// from source_type to target_type
1614 /// </summary>
1615 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1617 bool target_is_type_param = target_type.IsGenericParameter;
1618 bool target_is_value_type = target_type.IsValueType;
1620 if (source_type == target_type)
1621 return true;
1624 // From generic parameter to any type
1626 if (source_type.IsGenericParameter)
1627 return ExplicitTypeParameterConversionExists (source_type, target_type);
1630 // From object to a generic parameter
1632 if (source_type == TypeManager.object_type && target_is_type_param)
1633 return true;
1636 // From object to any reference type
1638 if (source_type == TypeManager.object_type && !target_is_value_type)
1639 return true;
1642 // From any class S to any class-type T, provided S is a base class of T
1644 if (TypeManager.IsSubclassOf (target_type, source_type))
1645 return true;
1648 // From any interface type S to any interface T provided S is not derived from T
1650 if (source_type.IsInterface && target_type.IsInterface){
1651 if (!TypeManager.IsSubclassOf (target_type, source_type))
1652 return true;
1656 // From any class type S to any interface T, provided S is not sealed
1657 // and provided S does not implement T.
1659 if (target_type.IsInterface && !source_type.IsSealed &&
1660 !TypeManager.ImplementsInterface (source_type, target_type))
1661 return true;
1664 // From any interface-type S to to any class type T, provided T is not
1665 // sealed, or provided T implements S.
1667 if (source_type.IsInterface &&
1668 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1669 return true;
1672 // From an array type S with an element type Se to an array type T with an
1673 // element type Te provided all the following are true:
1674 // * S and T differe only in element type, in other words, S and T
1675 // have the same number of dimensions.
1676 // * Both Se and Te are reference types
1677 // * An explicit referenc conversions exist from Se to Te
1679 if (source_type.IsArray && target_type.IsArray) {
1680 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1682 Type source_element_type = TypeManager.GetElementType (source_type);
1683 Type target_element_type = TypeManager.GetElementType (target_type);
1685 if (source_element_type.IsGenericParameter ||
1686 (!source_element_type.IsValueType && !target_element_type.IsValueType))
1687 if (ExplicitReferenceConversionExists (source_element_type,
1688 target_element_type))
1689 return true;
1694 // From System.Array to any array-type
1695 if (source_type == TypeManager.array_type &&
1696 target_type.IsArray){
1697 return true;
1701 // From System delegate to any delegate-type
1703 if (source_type == TypeManager.delegate_type &&
1704 TypeManager.IsDelegateType (target_type))
1705 return true;
1708 // From ICloneable to Array or Delegate types
1710 if (source_type == TypeManager.icloneable_type &&
1711 (target_type == TypeManager.array_type ||
1712 target_type == TypeManager.delegate_type))
1713 return true;
1715 return false;
1718 /// <summary>
1719 /// Implements Explicit Reference conversions
1720 /// </summary>
1721 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1723 Type source_type = source.Type;
1724 bool target_is_type_param = target_type.IsGenericParameter;
1725 bool target_is_value_type = target_type.IsValueType;
1728 // From object to a generic parameter
1730 if (source_type == TypeManager.object_type && target_is_type_param)
1731 return new UnboxCast (source, target_type);
1734 // Explicit type parameter conversion.
1737 if (source_type.IsGenericParameter)
1738 return ExplicitTypeParameterConversion (source, target_type);
1741 // From object to any reference type
1743 if (source_type == TypeManager.object_type && !target_is_value_type)
1744 return new ClassCast (source, target_type);
1747 // Unboxing conversion.
1749 if (((source_type == TypeManager.enum_type &&
1750 !(source is EmptyCast)) ||
1751 source_type == TypeManager.value_type) && target_is_value_type)
1752 return new UnboxCast (source, target_type);
1755 // From any class S to any class-type T, provided S is a base class of T
1757 if (TypeManager.IsSubclassOf (target_type, source_type))
1758 return new ClassCast (source, target_type);
1761 // From any interface type S to any interface T provided S is not derived from T
1763 if (source_type.IsInterface && target_type.IsInterface){
1764 if (TypeManager.ImplementsInterface (source_type, target_type))
1765 return null;
1766 else
1767 return new ClassCast (source, target_type);
1771 // From any class type S to any interface T, provides S is not sealed
1772 // and provided S does not implement T.
1774 if (target_type.IsInterface && !source_type.IsSealed) {
1775 if (TypeManager.ImplementsInterface (source_type, target_type))
1776 return null;
1777 else
1778 return new ClassCast (source, target_type);
1783 // From any interface-type S to to any class type T, provided T is not
1784 // sealed, or provided T implements S.
1786 if (source_type.IsInterface) {
1787 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1788 if (target_type.IsClass)
1789 return new ClassCast (source, target_type);
1790 else
1791 return new UnboxCast (source, target_type);
1794 return null;
1797 // From an array type S with an element type Se to an array type T with an
1798 // element type Te provided all the following are true:
1799 // * S and T differe only in element type, in other words, S and T
1800 // have the same number of dimensions.
1801 // * Both Se and Te are reference types
1802 // * An explicit referenc conversions exist from Se to Te
1804 if (source_type.IsArray && target_type.IsArray) {
1805 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1807 Type source_element_type = TypeManager.GetElementType (source_type);
1808 Type target_element_type = TypeManager.GetElementType (target_type);
1810 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1811 if (ExplicitReferenceConversionExists (source_element_type,
1812 target_element_type))
1813 return new ClassCast (source, target_type);
1818 // From System.Array to any array-type
1819 if (source_type == TypeManager.array_type &&
1820 target_type.IsArray) {
1821 return new ClassCast (source, target_type);
1825 // From System delegate to any delegate-type
1827 if (source_type == TypeManager.delegate_type &&
1828 TypeManager.IsDelegateType (target_type))
1829 return new ClassCast (source, target_type);
1832 // From ICloneable to Array or Delegate types
1834 if (source_type == TypeManager.icloneable_type &&
1835 (target_type == TypeManager.array_type ||
1836 target_type == TypeManager.delegate_type))
1837 return new ClassCast (source, target_type);
1839 return null;
1842 /// <summary>
1843 /// Performs an explicit conversion of the expression `expr' whose
1844 /// type is expr.Type to `target_type'.
1845 /// </summary>
1846 static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
1847 Type target_type, Location loc)
1849 Type expr_type = expr.Type;
1851 // Explicit conversion includes implicit conversion and it used for enum underlying types too
1852 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1853 if (ne != null)
1854 return ne;
1857 // Unboxing conversions; only object types can be convertible to enum
1859 if (expr_type == TypeManager.object_type && target_type.IsValueType || expr_type == TypeManager.enum_type)
1860 return new UnboxCast (expr, target_type);
1862 if (TypeManager.IsEnumType (expr_type)) {
1863 if (expr is EnumConstant)
1864 return ExplicitConversionCore (ec, ((EnumConstant) expr).Child, target_type, loc);
1866 return ExplicitConversionCore (ec, new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)), target_type, loc);
1869 if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
1870 return new Nullable.LiftedConversion (
1871 expr, target_type, false, true, loc).Resolve (ec);
1873 if (TypeManager.IsEnumType (target_type)){
1874 Expression ce = ExplicitConversionCore (ec, expr, TypeManager.EnumToUnderlying (target_type), loc);
1875 if (ce != null)
1876 return new EmptyCast (ce, target_type);
1879 ne = ExplicitNumericConversion (expr, target_type);
1880 if (ne != null)
1881 return ne;
1884 // Skip the ExplicitReferenceConversion because we can not convert
1885 // from Null to a ValueType, and ExplicitReference wont check against
1886 // null literal explicitly
1888 if (expr_type != TypeManager.null_type){
1889 ne = ExplicitReferenceConversion (expr, target_type);
1890 if (ne != null)
1891 return ne;
1894 if (ec.InUnsafe){
1895 ne = ExplicitUnsafe (expr, target_type);
1896 if (ne != null)
1897 return ne;
1900 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1901 if (ne != null)
1902 return ne;
1904 return null;
1907 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1909 Type expr_type = expr.Type;
1911 if (target_type.IsPointer){
1912 if (expr_type.IsPointer)
1913 return new EmptyCast (expr, target_type);
1915 if (expr_type == TypeManager.sbyte_type ||
1916 expr_type == TypeManager.short_type ||
1917 expr_type == TypeManager.int32_type ||
1918 expr_type == TypeManager.int64_type)
1919 return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1921 if (expr_type == TypeManager.ushort_type ||
1922 expr_type == TypeManager.uint32_type ||
1923 expr_type == TypeManager.uint64_type ||
1924 expr_type == TypeManager.byte_type)
1925 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1928 if (expr_type.IsPointer){
1929 if (target_type == TypeManager.sbyte_type)
1930 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1931 else if (target_type == TypeManager.byte_type)
1932 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1933 else if (target_type == TypeManager.short_type)
1934 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1935 else if (target_type == TypeManager.ushort_type)
1936 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1937 else if (target_type == TypeManager.int32_type)
1938 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1939 else if (target_type == TypeManager.uint32_type)
1940 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1941 else if (target_type == TypeManager.uint64_type)
1942 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1943 else if (target_type == TypeManager.int64_type){
1944 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1947 return null;
1950 /// <summary>
1951 /// Same as ExplicitConversion, only it doesn't include user defined conversions
1952 /// </summary>
1953 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1954 Type target_type, Location l)
1956 int errors = Report.Errors;
1957 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1958 if (Report.Errors > errors)
1959 return null;
1961 if (ne != null)
1962 return ne;
1964 if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type))
1965 return new Nullable.LiftedConversion (
1966 expr, target_type, false, true, l).Resolve (ec);
1968 ne = ExplicitNumericConversion (expr, target_type);
1969 if (ne != null)
1970 return ne;
1972 ne = ExplicitReferenceConversion (expr, target_type);
1973 if (ne != null)
1974 return ne;
1976 if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1977 return new EmptyCast (expr, target_type);
1979 expr.Error_ValueCannotBeConverted (l, target_type, true);
1980 return null;
1983 /// <summary>
1984 /// Performs an explicit conversion of the expression `expr' whose
1985 /// type is expr.Type to `target_type'.
1986 /// </summary>
1987 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1988 Type target_type, Location loc)
1990 Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1991 if (e != null)
1992 return e;
1994 expr.Error_ValueCannotBeConverted (loc, target_type, true);
1995 return null;