2005-06-27 Geoff Norton <gnorton@customerdna.com>
[mono-project.git] / mcs / bmcs / convert.cs
blob62502bca0ba8fea95c2f54c7a29b080f9f00bce1
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 // This is used to prettify the code: a null argument is allowed
24 // for ImplicitStandardConversion as long as it is known that
25 // no anonymous method will play a role.
27 // FIXME: renamed from `const' to `static' to allow bootstraping from older
28 // versions of the compiler that could not cope with this construct.
30 public static EmitContext ConstantEC = null;
32 static public void Error_CannotConvertType (Location loc, Type source, Type target)
34 Report.Error (30, loc, "Cannot convert type '" +
35 TypeManager.CSharpName (source) + "' to '" +
36 TypeManager.CSharpName (target) + "'");
39 static Expression TypeParameter_to_Null (Expression expr, Type target_type,
40 Location loc)
42 if (!TypeParameter_to_Null (target_type)) {
43 Report.Error (403, loc, "Cannot convert null to the type " +
44 "parameter `{0}' becaues it could be a value " +
45 "type. Consider using `default ({0})' instead.",
46 target_type);
47 return null;
50 return new NullCast (expr, target_type);
53 static bool TypeParameter_to_Null (Type target_type)
55 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
56 if (gc == null)
57 return false;
59 if (gc.HasReferenceTypeConstraint)
60 return true;
61 if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
62 return true;
64 return false;
67 static Type TypeParam_EffectiveBaseType (EmitContext ec, Type t)
69 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
70 if (gc == null)
71 return TypeManager.object_type;
73 return TypeParam_EffectiveBaseType (ec, gc);
76 static Type TypeParam_EffectiveBaseType (EmitContext ec, GenericConstraints gc)
78 ArrayList list = new ArrayList ();
79 list.Add (gc.EffectiveBaseClass);
80 foreach (Type t in gc.InterfaceConstraints) {
81 if (!t.IsGenericParameter)
82 continue;
84 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
85 if (new_gc != null)
86 list.Add (TypeParam_EffectiveBaseType (ec, new_gc));
88 return FindMostEncompassedType (ec, list);
91 static Expression TypeParameterConversion (Expression expr, bool is_reference, Type target_type)
93 if (is_reference)
94 return new EmptyCast (expr, target_type);
95 else
96 return new BoxedCast (expr, target_type);
99 static Expression ImplicitTypeParameterConversion (EmitContext ec, Expression expr,
100 Type target_type)
102 Type expr_type = expr.Type;
104 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
106 if (gc == null) {
107 if (target_type == TypeManager.object_type)
108 return new BoxedCast (expr);
110 return null;
113 // We're converting from a type parameter which is known to be a reference type.
114 bool is_reference = gc.IsReferenceType;
115 Type base_type = TypeParam_EffectiveBaseType (ec, gc);
117 if (TypeManager.IsSubclassOf (base_type, target_type))
118 return TypeParameterConversion (expr, is_reference, target_type);
120 if (target_type.IsInterface) {
121 if (TypeManager.ImplementsInterface (base_type, target_type))
122 return TypeParameterConversion (expr, is_reference, target_type);
124 foreach (Type t in gc.InterfaceConstraints) {
125 if (TypeManager.IsSubclassOf (t, target_type))
126 return TypeParameterConversion (expr, is_reference, target_type);
130 foreach (Type t in gc.InterfaceConstraints) {
131 if (!t.IsGenericParameter)
132 continue;
133 if (TypeManager.IsSubclassOf (t, target_type))
134 return TypeParameterConversion (expr, is_reference, target_type);
137 return null;
140 static EmptyExpression MyEmptyExpr;
141 static public Expression WideningReferenceConversion (EmitContext ec, Expression expr, Type target_type)
143 Type expr_type = expr.Type;
145 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
146 // if we are a method group, emit a warning
148 expr.Emit (null);
151 if (expr_type == TypeManager.void_type)
152 return null;
154 if (expr_type.IsGenericParameter)
155 return ImplicitTypeParameterConversion (ec, expr, target_type);
158 // notice that it is possible to write "ValueType v = 1", the ValueType here
159 // is an abstract class, and not really a value type, so we apply the same rules.
161 if (target_type == TypeManager.object_type) {
163 // A pointer type cannot be converted to object
165 if (expr_type.IsPointer)
166 return null;
168 if (TypeManager.IsValueType (expr_type))
169 return new BoxedCast (expr);
170 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
171 if (expr_type == TypeManager.anonymous_method_type)
172 return null;
173 return new EmptyCast (expr, target_type);
176 return null;
177 } else if (target_type == TypeManager.value_type) {
178 if (TypeManager.IsValueType (expr_type))
179 return new BoxedCast (expr);
180 if (expr_type == TypeManager.null_type)
181 return new NullCast (expr, target_type);
183 return null;
184 } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
186 // Special case: enumeration to System.Enum.
187 // System.Enum is not a value type, it is a class, so we need
188 // a boxing conversion
190 if (expr_type.IsEnum || expr_type.IsGenericParameter)
191 return new BoxedCast (expr);
193 return new EmptyCast (expr, target_type);
196 // This code is kind of mirrored inside WideningStandardConversionExists
197 // with the small distinction that we only probe there
199 // Always ensure that the code here and there is in sync
201 // from the null type to any reference-type.
202 if (expr_type == TypeManager.null_type){
203 if (target_type.IsPointer)
204 return new EmptyCast (expr, target_type);
206 if (!target_type.IsValueType)
207 return new NullCast (expr, target_type);
209 // VB.NET specific: Convert Nothing to value types
211 Expression e = NothingToPrimitiveTypes (expr, target_type);
212 if (e != null)
213 return e;
215 return new NullCast (expr, target_type);
218 // from any class-type S to any interface-type T.
219 if (target_type.IsInterface) {
220 if (target_type != TypeManager.iconvertible_type &&
221 expr_type.IsValueType && (expr is Constant) &&
222 !(expr is IntLiteral || expr is BoolLiteral ||
223 expr is FloatLiteral || expr is DoubleLiteral ||
224 expr is LongLiteral || expr is CharLiteral ||
225 expr is StringLiteral || expr is DecimalLiteral ||
226 expr is UIntLiteral || expr is ULongLiteral)) {
227 return null;
230 if (TypeManager.ImplementsInterface (expr_type, target_type)){
231 if (expr_type.IsGenericParameter || TypeManager.IsValueType (expr_type))
232 return new BoxedCast (expr, target_type);
233 else
234 return new EmptyCast (expr, target_type);
238 // from any interface type S to interface-type T.
239 if (expr_type.IsInterface && target_type.IsInterface) {
240 if (TypeManager.ImplementsInterface (expr_type, target_type))
241 return new EmptyCast (expr, target_type);
242 else
243 return null;
246 // from an array-type S to an array-type of type T
247 if (expr_type.IsArray && target_type.IsArray) {
248 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
250 Type expr_element_type = TypeManager.GetElementType (expr_type);
252 if (MyEmptyExpr == null)
253 MyEmptyExpr = new EmptyExpression ();
255 MyEmptyExpr.SetType (expr_element_type);
256 Type target_element_type = TypeManager.GetElementType (target_type);
258 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
259 if (WideningStandardConversionExists (ConstantEC, MyEmptyExpr,
260 target_element_type))
261 return new EmptyCast (expr, target_type);
265 // from an array-type to System.Array
266 if (expr_type.IsArray && target_type == TypeManager.array_type)
267 return new EmptyCast (expr, target_type);
269 // from an array-type of type T to IEnumerable<T>
270 if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
271 return new EmptyCast (expr, target_type);
273 // from any delegate type to System.Delegate
274 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
275 target_type == TypeManager.delegate_type)
276 return new EmptyCast (expr, target_type);
278 // from any array-type or delegate type into System.ICloneable.
279 if (expr_type.IsArray ||
280 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
281 if (target_type == TypeManager.icloneable_type)
282 return new EmptyCast (expr, target_type);
284 // from a generic type definition to a generic instance.
285 if (TypeManager.IsEqual (expr_type, target_type))
286 return new EmptyCast (expr, target_type);
288 return null;
292 // Tests whether an implicit reference conversion exists between expr_type
293 // and target_type
295 public static bool WideningReferenceConversionExists (EmitContext ec, Expression expr, Type target_type)
297 Type expr_type = expr.Type;
299 if (expr_type.IsGenericParameter)
300 return ImplicitTypeParameterConversion (ec, expr, target_type) != null;
303 // This is the boxed case.
305 if (target_type == TypeManager.object_type) {
306 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
307 expr_type.IsInterface || expr_type == TypeManager.enum_type)
308 if (target_type != TypeManager.anonymous_method_type)
309 return true;
311 return false;
312 } else if (TypeManager.IsSubclassOf (expr_type, target_type))
313 return true;
315 // Please remember that all code below actually comes
316 // from WideningReferenceConversion so make sure code remains in sync
318 // from any class-type S to any interface-type T.
319 if (target_type.IsInterface) {
320 if (target_type != TypeManager.iconvertible_type &&
321 expr_type.IsValueType && (expr is Constant) &&
322 !(expr is IntLiteral || expr is BoolLiteral ||
323 expr is FloatLiteral || expr is DoubleLiteral ||
324 expr is LongLiteral || expr is CharLiteral ||
325 expr is StringLiteral || expr is DecimalLiteral ||
326 expr is UIntLiteral || expr is ULongLiteral)) {
327 return false;
330 if (TypeManager.ImplementsInterface (expr_type, target_type))
331 return true;
334 // from any interface type S to interface-type T.
335 if (expr_type.IsInterface && target_type.IsInterface)
336 if (TypeManager.ImplementsInterface (expr_type, target_type))
337 return true;
339 // from an array-type S to an array-type of type T
340 if (expr_type.IsArray && target_type.IsArray) {
341 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
343 Type expr_element_type = expr_type.GetElementType ();
345 if (MyEmptyExpr == null)
346 MyEmptyExpr = new EmptyExpression ();
348 MyEmptyExpr.SetType (expr_element_type);
349 Type target_element_type = TypeManager.GetElementType (target_type);
351 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
352 if (WideningStandardConversionExists (ConstantEC, MyEmptyExpr,
353 target_element_type))
354 return true;
358 // from an array-type to System.Array
359 if (expr_type.IsArray && (target_type == TypeManager.array_type))
360 return true;
362 // from an array-type of type T to IEnumerable<T>
363 if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
364 return true;
366 // from any delegate type to System.Delegate
367 if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
368 target_type == TypeManager.delegate_type)
369 if (target_type.IsAssignableFrom (expr_type))
370 return true;
372 // from any array-type or delegate type into System.ICloneable.
373 if (expr_type.IsArray ||
374 expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
375 if (target_type == TypeManager.icloneable_type)
376 return true;
378 // from the null type to any reference-type.
379 if (expr_type == TypeManager.null_type){
380 if (target_type.IsPointer)
381 return true;
383 if (!target_type.IsValueType)
384 return true;
387 // from a generic type definition to a generic instance.
388 if (TypeManager.IsEqual (expr_type, target_type))
389 return true;
391 return false;
394 /// <summary>
395 /// Implicit Numeric Conversions.
397 /// expr is the expression to convert, returns a new expression of type
398 /// target_type or null if an implicit conversion is not possible.
399 /// </summary>
400 static public Expression WideningNumericConversion (EmitContext ec, Expression expr,
401 Type target_type, Location loc)
403 Type expr_type = expr.Type;
406 // Attempt to do the implicit constant expression conversions
408 if (expr is Constant){
409 Expression e;
411 e = WideningConstantConversions (target_type, (Constant) expr);
412 if (e != null)
413 return e;
415 if (expr is IntConstant){
416 e = TryWideningIntConversion (target_type, (IntConstant) expr);
418 if (e != null)
419 return e;
423 Type real_target_type = target_type;
425 // VB.NET specific: Convert an enum to it's
426 // underlying numeric type or any type that
427 // it's underlyinmg type has widening
428 // conversion to.
430 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
431 if (target_type == TypeManager.enum_type ||
432 target_type == TypeManager.object_type) {
433 if (expr is EnumConstant)
434 expr = ((EnumConstant) expr).Child;
435 // We really need all these casts here .... :-(
436 expr = new BoxedCast (new EmptyCast (expr, expr_type));
437 return new EmptyCast (expr, target_type);
441 // Notice that we have kept the expr_type unmodified, which is only
442 // used later on to
443 if (expr is EnumConstant)
444 expr = ((EnumConstant) expr).Child;
445 else
446 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
447 expr_type = expr.Type;
449 if (expr_type == target_type)
450 return expr;
453 if (expr_type == TypeManager.sbyte_type){
455 // From sbyte to short, int, long, float, double.
457 if (real_target_type == TypeManager.int32_type)
458 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
459 if (real_target_type == TypeManager.int64_type)
460 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
461 if (real_target_type == TypeManager.double_type)
462 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
463 if (real_target_type == TypeManager.float_type)
464 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
465 if (real_target_type == TypeManager.short_type)
466 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
467 } else if (expr_type == TypeManager.byte_type){
469 // From byte to short, ushort, int, uint, long, ulong, float, double
471 if ((real_target_type == TypeManager.short_type) ||
472 (real_target_type == TypeManager.ushort_type) ||
473 (real_target_type == TypeManager.int32_type) ||
474 (real_target_type == TypeManager.uint32_type))
475 return new EmptyCast (expr, target_type);
477 if (real_target_type == TypeManager.uint64_type)
478 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
479 if (real_target_type == TypeManager.int64_type)
480 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
481 if (real_target_type == TypeManager.float_type)
482 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
483 if (real_target_type == TypeManager.double_type)
484 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
485 if (real_target_type == TypeManager.decimal_type)
486 return new ImplicitNew (ec, "System", "Decimal", loc, expr);
487 } else if (expr_type == TypeManager.short_type){
489 // From short to int, long, float, double
491 if (real_target_type == TypeManager.int32_type)
492 return new EmptyCast (expr, target_type);
493 if (real_target_type == TypeManager.int64_type)
494 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
495 if (real_target_type == TypeManager.double_type)
496 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
497 if (real_target_type == TypeManager.float_type)
498 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
499 if (real_target_type == TypeManager.decimal_type)
500 return new ImplicitNew (ec, "System", "Decimal", loc, expr);
501 } else if (expr_type == TypeManager.ushort_type){
503 // From ushort to int, uint, long, ulong, float, double
505 if (real_target_type == TypeManager.uint32_type)
506 return new EmptyCast (expr, target_type);
508 if (real_target_type == TypeManager.uint64_type)
509 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
510 if (real_target_type == TypeManager.int32_type)
511 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
512 if (real_target_type == TypeManager.int64_type)
513 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
514 if (real_target_type == TypeManager.double_type)
515 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
516 if (real_target_type == TypeManager.float_type)
517 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
518 } else if (expr_type == TypeManager.int32_type){
520 // From int to long, float, double
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 ImplicitNew (ec, "System", "Decimal", loc, expr);
530 } else if (expr_type == TypeManager.uint32_type){
532 // From uint to long, ulong, float, double
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 } else if (expr_type == TypeManager.uint64_type){
546 // From ulong to float, double
548 if (real_target_type == TypeManager.double_type)
549 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
550 OpCodes.Conv_R8);
551 if (real_target_type == TypeManager.float_type)
552 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
553 OpCodes.Conv_R4);
554 } else if (expr_type == TypeManager.int64_type){
556 // From long/ulong to float, double
558 if (real_target_type == TypeManager.double_type)
559 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
560 if (real_target_type == TypeManager.float_type)
561 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
562 if (real_target_type == TypeManager.decimal_type)
563 return new ImplicitNew (ec, "System", "Decimal", loc, expr);
564 } else if (expr_type == TypeManager.float_type){
566 // float to double
568 if (real_target_type == TypeManager.double_type)
569 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
570 } else if (expr_type == TypeManager.decimal_type){
572 // From decimal to float, double
574 if (real_target_type == TypeManager.double_type)
575 return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.convert_to_double_decimal, expr);
576 if (real_target_type == TypeManager.float_type)
577 return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.convert_to_single_decimal, expr);
580 return null;
584 /// <summary>
585 /// Same as WideningStandardConversionExists except that it also looks at
586 /// implicit user defined conversions - needed for overload resolution
587 /// </summary>
588 public static bool WideningConversionExists (EmitContext ec, Expression expr, Type target_type)
590 if (expr is NullLiteral) {
591 if (target_type.IsGenericParameter)
592 return TypeParameter_to_Null (target_type);
594 if (TypeManager.IsNullableType (target_type))
595 return true;
598 if (WideningStandardConversionExists (ec, expr, target_type))
599 return true;
602 // VB.NET has no notion of User defined conversions
605 // Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
607 // if (dummy != null)
608 // return true;
610 return false;
614 // VB.NET has no notion of User defined conversions
617 // public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
618 // {
619 // Expression dummy = ImplicitUserConversion (
620 // ec, new EmptyExpression (source), target, Location.Null);
621 // return dummy != null;
622 // }
624 /// <summary>
625 /// Determines if a standard implicit conversion exists from
626 /// expr_type to target_type
628 /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
629 /// </summary>
630 public static bool WideningStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
632 Type expr_type = expr.Type;
634 if (expr_type == TypeManager.void_type)
635 return false;
637 //Console.WriteLine ("Expr is {0}", expr);
638 //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
639 if (expr_type.Equals (target_type))
640 return true;
643 // First numeric conversions
645 if (expr_type == TypeManager.sbyte_type){
647 // From sbyte to short, int, long, float, double.
649 if ((target_type == TypeManager.int32_type) ||
650 (target_type == TypeManager.int64_type) ||
651 (target_type == TypeManager.double_type) ||
652 (target_type == TypeManager.float_type) ||
653 (target_type == TypeManager.short_type) ||
654 (target_type == TypeManager.decimal_type))
655 return true;
657 } else if (expr_type == TypeManager.byte_type){
659 // From byte to short, ushort, int, uint, long, ulong, float, double
661 if ((target_type == TypeManager.short_type) ||
662 (target_type == TypeManager.ushort_type) ||
663 (target_type == TypeManager.int32_type) ||
664 (target_type == TypeManager.uint32_type) ||
665 (target_type == TypeManager.uint64_type) ||
666 (target_type == TypeManager.int64_type) ||
667 (target_type == TypeManager.float_type) ||
668 (target_type == TypeManager.double_type) ||
669 (target_type == TypeManager.decimal_type))
670 return true;
672 } else if (expr_type == TypeManager.short_type){
674 // From short to int, long, float, double
676 if ((target_type == TypeManager.int32_type) ||
677 (target_type == TypeManager.int64_type) ||
678 (target_type == TypeManager.double_type) ||
679 (target_type == TypeManager.float_type) ||
680 (target_type == TypeManager.decimal_type))
681 return true;
683 } else if (expr_type == TypeManager.ushort_type){
685 // From ushort to int, uint, long, ulong, float, double
687 if ((target_type == TypeManager.uint32_type) ||
688 (target_type == TypeManager.uint64_type) ||
689 (target_type == TypeManager.int32_type) ||
690 (target_type == TypeManager.int64_type) ||
691 (target_type == TypeManager.double_type) ||
692 (target_type == TypeManager.float_type) ||
693 (target_type == TypeManager.decimal_type))
694 return true;
696 } else if (expr_type == TypeManager.int32_type){
698 // From int to long, float, double
700 if ((target_type == TypeManager.int64_type) ||
701 (target_type == TypeManager.double_type) ||
702 (target_type == TypeManager.float_type) ||
703 (target_type == TypeManager.decimal_type))
704 return true;
706 } else if (expr_type == TypeManager.uint32_type){
708 // From uint to long, ulong, float, double
710 if ((target_type == TypeManager.int64_type) ||
711 (target_type == TypeManager.uint64_type) ||
712 (target_type == TypeManager.double_type) ||
713 (target_type == TypeManager.float_type) ||
714 (target_type == TypeManager.decimal_type))
715 return true;
717 } else if ((expr_type == TypeManager.uint64_type) ||
718 (expr_type == TypeManager.int64_type)) {
720 // From long/ulong to float, double
722 if ((target_type == TypeManager.double_type) ||
723 (target_type == TypeManager.float_type) ||
724 (target_type == TypeManager.decimal_type))
725 return true;
727 } else if (expr_type == TypeManager.char_type){
729 // From char to ushort, int, uint, long, ulong, float, double
731 if ((target_type == TypeManager.ushort_type) ||
732 (target_type == TypeManager.int32_type) ||
733 (target_type == TypeManager.uint32_type) ||
734 (target_type == TypeManager.uint64_type) ||
735 (target_type == TypeManager.int64_type) ||
736 (target_type == TypeManager.float_type) ||
737 (target_type == TypeManager.double_type) ||
738 (target_type == TypeManager.decimal_type))
739 return true;
741 } else if (expr_type == TypeManager.float_type){
743 // float to double
745 if (target_type == TypeManager.double_type)
746 return true;
749 if (expr.eclass == ExprClass.MethodGroup){
750 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
751 MethodGroupExpr mg = expr as MethodGroupExpr;
752 if (mg != null){
754 // This should not happen frequently, so we can create an object
755 // to test compatibility
757 Expression c = ImplicitDelegateCreation.Create (ec, mg, target_type, Location.Null);
758 return c != null;
763 if (WideningReferenceConversionExists (ec, expr, target_type))
764 return true;
767 // Implicit Constant Expression Conversions
769 if (expr is IntConstant){
770 int value = ((IntConstant) expr).Value;
772 if (target_type == TypeManager.sbyte_type){
773 if (value >= SByte.MinValue && value <= SByte.MaxValue)
774 return true;
775 } else if (target_type == TypeManager.byte_type){
776 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
777 return true;
778 } else if (target_type == TypeManager.short_type){
779 if (value >= Int16.MinValue && value <= Int16.MaxValue)
780 return true;
781 } else if (target_type == TypeManager.ushort_type){
782 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
783 return true;
784 } else if (target_type == TypeManager.uint32_type){
785 if (value >= 0)
786 return true;
787 } else if (target_type == TypeManager.uint64_type){
789 // we can optimize this case: a positive int32
790 // always fits on a uint64. But we need an opcode
791 // to do it.
793 if (value >= 0)
794 return true;
797 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
798 return true;
801 if (expr is LongConstant && target_type == TypeManager.uint64_type){
803 // Try the implicit constant expression conversion
804 // from long to ulong, instead of a nice routine,
805 // we just inline it
807 long v = ((LongConstant) expr).Value;
808 if (v > 0)
809 return true;
812 if ((target_type == TypeManager.enum_type ||
813 target_type.IsSubclassOf (TypeManager.enum_type)) &&
814 expr is IntLiteral){
815 IntLiteral i = (IntLiteral) expr;
817 if (i.Value == 0)
818 return true;
822 // If `expr_type' implements `target_type' (which is an iface)
823 // see TryWideningIntConversion
825 if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
826 return true;
828 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
829 return true;
831 if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
832 return true;
834 if (expr_type == TypeManager.anonymous_method_type){
835 if (!TypeManager.IsDelegateType (target_type))
836 return false;
838 AnonymousMethod am = (AnonymousMethod) expr;
840 Expression conv = am.Compatible (ec, target_type, true);
841 if (conv != null)
842 return true;
845 return false;
849 // Used internally by FindMostEncompassedType, this is used
850 // to avoid creating lots of objects in the tight loop inside
851 // FindMostEncompassedType
853 static EmptyExpression priv_fmet_param;
855 /// <summary>
856 /// Finds "most encompassed type" according to the spec (13.4.2)
857 /// amongst the methods in the MethodGroupExpr
858 /// </summary>
859 static Type FindMostEncompassedType (EmitContext ec, ArrayList types)
861 Type best = null;
863 if (priv_fmet_param == null)
864 priv_fmet_param = new EmptyExpression ();
866 foreach (Type t in types){
867 priv_fmet_param.SetType (t);
869 if (best == null) {
870 best = t;
871 continue;
874 if (WideningStandardConversionExists (ec, priv_fmet_param, best))
875 best = t;
878 return best;
882 // Used internally by FindMostEncompassingType, this is used
883 // to avoid creating lots of objects in the tight loop inside
884 // FindMostEncompassingType
886 static EmptyExpression priv_fmee_ret;
888 /// <summary>
889 /// Finds "most encompassing type" according to the spec (13.4.2)
890 /// amongst the types in the given set
891 /// </summary>
892 static Type FindMostEncompassingType (EmitContext ec, ArrayList types)
894 Type best = null;
896 if (priv_fmee_ret == null)
897 priv_fmee_ret = new EmptyExpression ();
899 foreach (Type t in types){
900 priv_fmee_ret.SetType (best);
902 if (best == null) {
903 best = t;
904 continue;
907 if (WideningStandardConversionExists (ec, priv_fmee_ret, t))
908 best = t;
911 return best;
915 // Used to avoid creating too many objects
917 static EmptyExpression priv_fms_expr;
919 /// <summary>
920 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
921 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
922 /// for explicit and implicit conversion operators.
923 /// </summary>
924 static public Type FindMostSpecificSource (EmitContext ec, MethodGroupExpr me,
925 Expression source, bool apply_explicit_conv_rules,
926 Location loc)
928 ArrayList src_types_set = new ArrayList ();
930 if (priv_fms_expr == null)
931 priv_fms_expr = new EmptyExpression ();
934 // If any operator converts from S then Sx = S
936 Type source_type = source.Type;
937 foreach (MethodBase mb in me.Methods){
938 ParameterData pd = Invocation.GetParameterData (mb);
939 Type param_type = pd.ParameterType (0);
941 if (param_type == source_type)
942 return param_type;
944 if (apply_explicit_conv_rules) {
946 // From the spec :
947 // Find the set of applicable user-defined conversion operators, U. This set
948 // consists of the
949 // user-defined implicit or explicit conversion operators declared by
950 // the classes or structs in D that convert from a type encompassing
951 // or encompassed by S to a type encompassing or encompassed by T
953 priv_fms_expr.SetType (param_type);
954 if (WideningStandardConversionExists (ec, priv_fms_expr, source_type))
955 src_types_set.Add (param_type);
956 else {
957 if (WideningStandardConversionExists (ec, source, param_type))
958 src_types_set.Add (param_type);
960 } else {
962 // Only if S is encompassed by param_type
964 if (WideningStandardConversionExists (ec, source, param_type))
965 src_types_set.Add (param_type);
970 // Explicit Conv rules
972 if (apply_explicit_conv_rules) {
973 ArrayList candidate_set = new ArrayList ();
975 foreach (Type param_type in src_types_set){
976 if (WideningStandardConversionExists (ec, source, param_type))
977 candidate_set.Add (param_type);
980 if (candidate_set.Count != 0)
981 return FindMostEncompassedType (ec, candidate_set);
985 // Final case
987 if (apply_explicit_conv_rules)
988 return FindMostEncompassingType (ec, src_types_set);
989 else
990 return FindMostEncompassedType (ec, src_types_set);
994 // Useful in avoiding proliferation of objects
996 static EmptyExpression priv_fmt_expr;
998 /// <summary>
999 /// Finds the most specific target Tx according to section 13.4.4
1000 /// </summary>
1001 static public Type FindMostSpecificTarget (EmitContext ec, MethodGroupExpr me,
1002 Type target, bool apply_explicit_conv_rules,
1003 Location loc)
1005 ArrayList tgt_types_set = new ArrayList ();
1007 if (priv_fmt_expr == null)
1008 priv_fmt_expr = new EmptyExpression ();
1011 // If any operator converts to T then Tx = T
1013 foreach (MethodInfo mi in me.Methods){
1014 Type ret_type = mi.ReturnType;
1016 if (ret_type == target)
1017 return ret_type;
1019 if (apply_explicit_conv_rules) {
1021 // From the spec :
1022 // Find the set of applicable user-defined conversion operators, U.
1024 // This set consists of the
1025 // user-defined implicit or explicit conversion operators declared by
1026 // the classes or structs in D that convert from a type encompassing
1027 // or encompassed by S to a type encompassing or encompassed by T
1029 priv_fms_expr.SetType (ret_type);
1030 if (WideningStandardConversionExists (ec, priv_fms_expr, target))
1031 tgt_types_set.Add (ret_type);
1032 else {
1033 priv_fms_expr.SetType (target);
1034 if (WideningStandardConversionExists (ec, priv_fms_expr, ret_type))
1035 tgt_types_set.Add (ret_type);
1037 } else {
1039 // Only if T is encompassed by param_type
1041 priv_fms_expr.SetType (ret_type);
1042 if (WideningStandardConversionExists (ec, priv_fms_expr, target))
1043 tgt_types_set.Add (ret_type);
1048 // Explicit conv rules
1050 if (apply_explicit_conv_rules) {
1051 ArrayList candidate_set = new ArrayList ();
1053 foreach (Type ret_type in tgt_types_set){
1054 priv_fmt_expr.SetType (ret_type);
1056 if (WideningStandardConversionExists (ec, priv_fmt_expr, target))
1057 candidate_set.Add (ret_type);
1060 if (candidate_set.Count != 0)
1061 return FindMostEncompassingType (ec, candidate_set);
1065 // Okay, final case !
1067 if (apply_explicit_conv_rules)
1068 return FindMostEncompassedType (ec, tgt_types_set);
1069 else
1070 return FindMostEncompassingType (ec, tgt_types_set);
1073 /// <summary>
1074 /// User-defined Implicit conversions
1075 /// </summary>
1078 // VB.NET has no notion of User defined conversions
1081 // static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1082 // Type target, Location loc)
1083 // {
1084 // return UserDefinedConversion (ec, source, target, loc, false);
1085 // }
1087 /// <summary>
1088 /// User-defined Explicit conversions
1089 /// </summary>
1092 // VB.NET has no notion of User defined conversions
1095 // static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1096 // Type target, Location loc)
1097 // {
1098 // return UserDefinedConversion (ec, source, target, loc, true);
1099 // }
1101 static DoubleHash explicit_conv = new DoubleHash (100);
1102 static DoubleHash implicit_conv = new DoubleHash (100);
1103 /// <summary>
1104 /// Computes the MethodGroup for the user-defined conversion
1105 /// operators from source_type to target_type. `look_for_explicit'
1106 /// controls whether we should also include the list of explicit
1107 /// operators
1108 /// </summary>
1109 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1110 Type source_type, Type target_type,
1111 Location loc, bool look_for_explicit)
1113 Expression mg1 = null, mg2 = null;
1114 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1115 string op_name;
1117 op_name = "op_Implicit";
1119 MethodGroupExpr union3;
1120 object r;
1121 if ((look_for_explicit ? explicit_conv : implicit_conv).Lookup (source_type, target_type, out r))
1122 return (MethodGroupExpr) r;
1124 mg1 = Expression.MethodLookup (ec, source_type, op_name, loc);
1125 if (source_type.BaseType != null)
1126 mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1128 if (mg1 == null)
1129 union3 = (MethodGroupExpr) mg2;
1130 else if (mg2 == null)
1131 union3 = (MethodGroupExpr) mg1;
1132 else
1133 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1135 mg1 = Expression.MethodLookup (ec, target_type, op_name, loc);
1136 if (mg1 != null){
1137 if (union3 != null)
1138 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1139 else
1140 union3 = (MethodGroupExpr) mg1;
1143 if (target_type.BaseType != null)
1144 mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1146 if (mg1 != null){
1147 if (union3 != null)
1148 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1149 else
1150 union3 = (MethodGroupExpr) mg1;
1153 MethodGroupExpr union4 = null;
1155 if (look_for_explicit) {
1156 op_name = "op_Explicit";
1158 mg5 = Expression.MemberLookup (ec, source_type, op_name, loc);
1159 if (source_type.BaseType != null)
1160 mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc);
1162 mg7 = Expression.MemberLookup (ec, target_type, op_name, loc);
1163 if (target_type.BaseType != null)
1164 mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc);
1166 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1167 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1169 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1172 MethodGroupExpr ret = Invocation.MakeUnionSet (union3, union4, loc);
1173 (look_for_explicit ? explicit_conv : implicit_conv).Insert (source_type, target_type, ret);
1174 return ret;
1177 /// <summary>
1178 /// User-defined conversions
1179 /// </summary>
1182 // VB.NET has no notion of User defined conversions. This method is not used.
1184 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1185 Type target, Location loc,
1186 bool look_for_explicit)
1188 MethodGroupExpr union;
1189 Type source_type = source.Type;
1190 MethodBase method = null;
1192 if (TypeManager.IsNullableType (source_type) && TypeManager.IsNullableType (target))
1193 return new Nullable.LiftedConversion (
1194 source, target, true, look_for_explicit, loc).Resolve (ec);
1196 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1197 if (union == null)
1198 return null;
1200 Type most_specific_source, most_specific_target;
1202 most_specific_source = FindMostSpecificSource (ec, union, source, look_for_explicit, loc);
1203 if (most_specific_source == null)
1204 return null;
1206 most_specific_target = FindMostSpecificTarget (ec, union, target, look_for_explicit, loc);
1207 if (most_specific_target == null)
1208 return null;
1210 int count = 0;
1213 foreach (MethodBase mb in union.Methods){
1214 ParameterData pd = Invocation.GetParameterData (mb);
1215 MethodInfo mi = (MethodInfo) mb;
1217 if (pd.ParameterType (0) == most_specific_source &&
1218 mi.ReturnType == most_specific_target) {
1219 method = mb;
1220 count++;
1224 if (method == null || count > 1)
1225 return null;
1229 // This will do the conversion to the best match that we
1230 // found. Now we need to perform an implict standard conversion
1231 // if the best match was not the type that we were requested
1232 // by target.
1234 if (look_for_explicit)
1235 source = WideningAndNarrowingConversionStandard (ec, source, most_specific_source, loc);
1236 else
1237 source = WideningConversionStandard (ec, source, most_specific_source, loc);
1239 if (source == null)
1240 return null;
1242 Expression e;
1243 e = new UserCast ((MethodInfo) method, source, loc);
1244 if (e.Type != target){
1245 if (!look_for_explicit)
1246 e = WideningConversionStandard (ec, e, target, loc);
1247 else
1248 e = WideningAndNarrowingConversionStandard (ec, e, target, loc);
1251 return e;
1254 /// <summary>
1255 /// Converts implicitly the resolved expression `expr' into the
1256 /// `target_type'. It returns a new expression that can be used
1257 /// in a context that expects a `target_type'.
1258 /// </summary>
1259 static public Expression WideningConversion (EmitContext ec, Expression expr,
1260 Type target_type, Location loc)
1262 Expression e;
1264 if (target_type == null)
1265 throw new Exception ("Target type is null");
1267 e = WideningConversionStandard (ec, expr, target_type, loc);
1268 if (e != null)
1269 return e;
1272 // VB.NET has no notion of User defined conversions
1275 // e = ImplicitUserConversion (ec, expr, target_type, loc);
1276 // if (e != null)
1277 // return e;
1279 return null;
1283 /// <summary>
1284 /// Attempts to apply the `Standard Implicit
1285 /// Conversion' rules to the expression `expr' into
1286 /// the `target_type'. It returns a new expression
1287 /// that can be used in a context that expects a
1288 /// `target_type'.
1290 /// This is different from `WideningConversion' in that the
1291 /// user defined implicit conversions are excluded.
1292 /// </summary>
1293 static public Expression WideningConversionStandard (EmitContext ec, Expression expr,
1294 Type target_type, Location loc)
1296 Type expr_type = expr.Type;
1297 Expression e;
1299 if (expr is NullLiteral) {
1300 if (target_type.IsGenericParameter)
1301 return TypeParameter_to_Null (expr, target_type, loc);
1303 if (TypeManager.IsNullableType (target_type))
1304 return new Nullable.NullableLiteral (target_type, loc);
1307 if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
1308 return new Nullable.LiftedConversion (
1309 expr, target_type, false, false, loc).Resolve (ec);
1311 if (expr.eclass == ExprClass.MethodGroup){
1312 if (!TypeManager.IsDelegateType (target_type)){
1313 return null;
1317 // Only allow anonymous method conversions on post ISO_1
1319 if (RootContext.Version != LanguageVersion.ISO_1){
1320 MethodGroupExpr mg = expr as MethodGroupExpr;
1321 if (mg != null)
1322 return ImplicitDelegateCreation.Create (ec, mg, target_type, loc);
1326 if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
1327 return expr;
1329 e = WideningNumericConversion (ec, expr, target_type, loc);
1330 if (e != null)
1331 return e;
1333 e = WideningReferenceConversion (ec, expr, target_type);
1334 if (e != null)
1335 return e;
1337 if ((target_type == TypeManager.enum_type ||
1338 target_type.IsSubclassOf (TypeManager.enum_type)) &&
1339 expr is IntLiteral){
1340 IntLiteral i = (IntLiteral) expr;
1342 if (i.Value == 0)
1343 return new EnumConstant ((Constant) expr, target_type);
1346 if (ec.InUnsafe) {
1347 if (expr_type.IsPointer){
1348 if (target_type == TypeManager.void_ptr_type)
1349 return new EmptyCast (expr, target_type);
1352 // yep, comparing pointer types cant be done with
1353 // t1 == t2, we have to compare their element types.
1355 if (target_type.IsPointer){
1356 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1357 return expr;
1361 if (target_type.IsPointer) {
1362 if (expr_type == TypeManager.null_type)
1363 return new EmptyCast (expr, target_type);
1365 if (expr_type == TypeManager.void_ptr_type)
1366 return new EmptyCast (expr, target_type);
1370 if (expr_type == TypeManager.anonymous_method_type){
1371 if (!TypeManager.IsDelegateType (target_type)){
1372 Report.Error (1660, loc,
1373 "Cannot convert anonymous method to `{0}', since it is not a delegate",
1374 TypeManager.CSharpName (target_type));
1375 return null;
1378 AnonymousMethod am = (AnonymousMethod) expr;
1379 int errors = Report.Errors;
1381 Expression conv = am.Compatible (ec, target_type, false);
1382 if (conv != null)
1383 return conv;
1386 // We return something instead of null, to avoid
1387 // the duplicate error, since am.Compatible would have
1388 // reported that already
1390 if (errors != Report.Errors)
1391 return new EmptyCast (expr, target_type);
1395 // VB.NET specific conversions
1398 e = WideningStringConversions (ec, expr, target_type, loc);
1399 if (e != null)
1400 return e;
1403 return null;
1406 /// <summary>
1407 /// Attempts to perform an implicit constant conversion of the IntConstant
1408 /// into a different data type using casts (See Implicit Constant
1409 /// Expression Conversions)
1410 /// </summary>
1411 static public Expression TryWideningIntConversion (Type target_type, IntConstant ic)
1413 int value = ic.Value;
1415 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1416 Type underlying = TypeManager.EnumToUnderlying (target_type);
1417 Constant e = (Constant) ic;
1420 // Possibly, we need to create a different 0 literal before passing
1421 // to EnumConstant
1423 if (underlying == TypeManager.int64_type)
1424 e = new LongLiteral (0);
1425 else if (underlying == TypeManager.uint64_type)
1426 e = new ULongLiteral (0);
1428 return new EnumConstant (e, target_type);
1432 // If `target_type' is an interface and the type of `ic' implements the interface
1433 // e.g. target_type is IComparable, IConvertible, IFormattable
1435 if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
1436 return new BoxedCast (ic);
1438 return null;
1441 /// <summary>
1442 /// Attempts to perform an implicit constant conversion of the IntConstant
1443 /// into a different data type using casts (See Implicit Constant
1444 /// Expression Conversions)
1445 /// </summary>
1446 static public Expression WideningConstantConversions (Type target_type, Constant const_expr)
1448 Constant ret_expr;
1450 Type const_expr_type = const_expr.Type;
1451 Location loc = const_expr.Location;
1453 if (target_type == TypeManager.byte_type){
1454 if (const_expr_type == TypeManager.short_type ||
1455 const_expr_type == TypeManager.int32_type ||
1456 const_expr_type == TypeManager.int64_type)
1457 return const_expr.ToByte (loc);
1460 if (target_type == TypeManager.short_type){
1461 if (const_expr_type == TypeManager.int32_type ||
1462 const_expr_type == TypeManager.int64_type)
1463 return const_expr.ToShort (loc);
1466 if (target_type == TypeManager.int32_type){
1467 if (const_expr_type == TypeManager.int64_type)
1468 return const_expr.ToInt (loc);
1471 if (target_type == TypeManager.float_type) {
1472 if (const_expr_type == TypeManager.double_type)
1473 return const_expr.ToDouble (loc);
1476 return null;
1479 static public Constant NothingToPrimitiveTypes (Expression expr, Type target_type)
1481 NullLiteral null_literal = (NullLiteral) expr;
1482 Location loc = null_literal.Location;
1483 Type real_target_type = target_type ;
1484 Constant retval = null;
1486 if (null_literal == null)
1487 throw new Exception ("FIXME: I was expecting that I would always get only NullLiterals");
1489 if (target_type.IsSubclassOf(TypeManager.enum_type))
1490 real_target_type = TypeManager.EnumToUnderlying (target_type);
1492 if (real_target_type == TypeManager.bool_type)
1493 retval = null_literal.ToBoolean (loc);
1494 else if (real_target_type == TypeManager.byte_type)
1495 retval = null_literal.ToByte (loc);
1496 else if (real_target_type == TypeManager.short_type)
1497 retval = null_literal.ToShort (loc);
1498 else if (real_target_type == TypeManager.int32_type)
1499 retval = null_literal.ToInt (loc);
1500 else if (real_target_type == TypeManager.int64_type)
1501 retval = null_literal.ToLong (loc);
1502 else if (real_target_type == TypeManager.decimal_type)
1503 retval = null_literal.ToDecimal (loc);
1504 else if (real_target_type == TypeManager.float_type)
1505 retval = null_literal.ToLong (loc);
1506 else if (real_target_type == TypeManager.double_type)
1507 retval = null_literal.ToDouble (loc);
1508 else if (real_target_type == TypeManager.char_type)
1509 retval = null_literal.ToChar (loc);
1510 else if (real_target_type == TypeManager.string_type)
1511 retval = new StringConstant (null);
1513 if (real_target_type != target_type && retval != null)
1514 retval = new EnumConstant (retval, target_type);
1516 return retval;
1519 static public void Error_CannotWideningConversion (Location loc, Type source, Type target)
1521 if (source.Name == target.Name){
1522 Report.ExtraInformation (loc,
1523 String.Format (
1524 "The type {0} has two conflicting definitons, one comes from {0} and the other from {1}",
1525 source.Assembly.FullName, target.Assembly.FullName));
1528 Report.Error (29, loc, "Cannot convert implicitly from {0} to `{1}'",
1529 source == TypeManager.anonymous_method_type ?
1530 "anonymous method" : "`" + TypeManager.CSharpName (source) + "'",
1531 TypeManager.CSharpName (target));
1534 /// <summary>
1535 /// Attempts to implicitly convert `source' into `target_type', using
1536 /// WideningConversion. If there is no implicit conversion, then
1537 /// an error is signaled
1538 /// </summary>
1539 static public Expression WideningConversionRequired (EmitContext ec, Expression source,
1540 Type target_type, Location loc)
1542 Expression e;
1544 int errors = Report.Errors;
1545 e = WideningConversion (ec, source, target_type, loc);
1546 if (Report.Errors > errors)
1547 return null;
1548 if (e != null)
1549 return e;
1551 if (source is DoubleLiteral) {
1552 if (target_type == TypeManager.float_type) {
1553 Error_664 (loc, "float", "f");
1554 return null;
1556 if (target_type == TypeManager.decimal_type) {
1557 Error_664 (loc, "decimal", "m");
1558 return null;
1562 if (source is Constant){
1563 Constant c = (Constant) source;
1565 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
1566 return null;
1569 Error_CannotWideningConversion (loc, source.Type, target_type);
1571 return null;
1574 static void Error_664 (Location loc, string type, string suffix) {
1575 Report.Error (664, loc,
1576 "Literal of type double cannot be implicitly converted to type '{0}'. Add suffix '{1}' to create a literal of this type",
1577 type, suffix);
1580 /// <summary>
1581 /// Performs the explicit numeric conversions
1582 /// </summary>
1584 /// <summary>
1585 /// Performs the explicit numeric conversions
1586 /// </summary>
1587 static Expression NarrowingNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
1589 Type expr_type = expr.Type;
1592 // If we have an enumeration, extract the underlying type,
1593 // use this during the comparison, but wrap around the original
1594 // target_type
1596 Type real_target_type = target_type;
1598 if (TypeManager.IsEnumType (real_target_type))
1599 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
1601 if (WideningStandardConversionExists (ec, expr, real_target_type)){
1602 Expression ce = WideningConversionStandard (ec, expr, real_target_type, loc);
1604 if (real_target_type != target_type)
1605 return new EmptyCast (ce, target_type);
1606 return ce;
1609 if (expr_type == TypeManager.sbyte_type){
1611 // From sbyte to byte, ushort, uint, ulong, char
1613 if (real_target_type == TypeManager.byte_type)
1614 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
1615 if (real_target_type == TypeManager.ushort_type)
1616 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
1617 if (real_target_type == TypeManager.uint32_type)
1618 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
1619 if (real_target_type == TypeManager.uint64_type)
1620 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
1621 if (real_target_type == TypeManager.char_type)
1622 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
1623 } else if (expr_type == TypeManager.byte_type){
1625 // From byte to sbyte and char
1627 if (real_target_type == TypeManager.sbyte_type)
1628 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
1629 } else if (expr_type == TypeManager.short_type){
1631 // From short to byte
1633 if (real_target_type == TypeManager.sbyte_type)
1634 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1635 if (real_target_type == TypeManager.byte_type)
1636 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1637 if (real_target_type == TypeManager.ushort_type)
1638 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
1639 if (real_target_type == TypeManager.uint32_type)
1640 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
1641 if (real_target_type == TypeManager.uint64_type)
1642 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
1643 } else if (expr_type == TypeManager.ushort_type){
1645 // From ushort to sbyte, byte, short, char
1647 if (real_target_type == TypeManager.sbyte_type)
1648 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
1649 if (real_target_type == TypeManager.byte_type)
1650 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1651 if (real_target_type == TypeManager.short_type)
1652 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
1653 if (real_target_type == TypeManager.char_type)
1654 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
1655 } else if (expr_type == TypeManager.int32_type){
1657 // From int to byte, short
1659 if (real_target_type == TypeManager.sbyte_type)
1660 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1661 if (real_target_type == TypeManager.byte_type)
1662 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1663 if (real_target_type == TypeManager.short_type)
1664 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1665 if (real_target_type == TypeManager.ushort_type)
1666 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1667 if (real_target_type == TypeManager.uint32_type)
1668 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
1669 if (real_target_type == TypeManager.uint64_type)
1670 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
1671 } else if (expr_type == TypeManager.uint32_type){
1673 // From uint to sbyte, byte, short, ushort, int, char
1675 if (real_target_type == TypeManager.sbyte_type)
1676 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
1677 if (real_target_type == TypeManager.byte_type)
1678 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1679 if (real_target_type == TypeManager.short_type)
1680 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
1681 if (real_target_type == TypeManager.ushort_type)
1682 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1683 if (real_target_type == TypeManager.int32_type)
1684 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
1685 if (real_target_type == TypeManager.char_type)
1686 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
1687 } else if (expr_type == TypeManager.int64_type){
1689 // From long to byte, short, int
1691 if (real_target_type == TypeManager.sbyte_type)
1692 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1693 if (real_target_type == TypeManager.byte_type)
1694 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1695 if (real_target_type == TypeManager.short_type)
1696 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1697 if (real_target_type == TypeManager.ushort_type)
1698 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1699 if (real_target_type == TypeManager.int32_type)
1700 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1701 if (real_target_type == TypeManager.uint32_type)
1702 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
1703 if (real_target_type == TypeManager.uint64_type)
1704 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
1705 } else if (expr_type == TypeManager.uint64_type){
1707 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1709 if (real_target_type == TypeManager.sbyte_type)
1710 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
1711 if (real_target_type == TypeManager.byte_type)
1712 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1713 if (real_target_type == TypeManager.short_type)
1714 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
1715 if (real_target_type == TypeManager.ushort_type)
1716 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1717 if (real_target_type == TypeManager.int32_type)
1718 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
1719 if (real_target_type == TypeManager.uint32_type)
1720 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
1721 if (real_target_type == TypeManager.int64_type)
1722 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
1723 if (real_target_type == TypeManager.char_type)
1724 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
1725 } else if (expr_type == TypeManager.float_type){
1727 // From float to byte, short, int, long, decimal
1729 if (real_target_type == TypeManager.sbyte_type)
1730 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1);
1731 if (real_target_type == TypeManager.byte_type)
1732 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1733 if (real_target_type == TypeManager.short_type)
1734 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1735 if (real_target_type == TypeManager.ushort_type)
1736 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2);
1737 if (real_target_type == TypeManager.int32_type)
1738 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1739 if (real_target_type == TypeManager.uint32_type)
1740 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4);
1741 if (real_target_type == TypeManager.int64_type)
1742 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1743 if (real_target_type == TypeManager.uint64_type)
1744 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8);
1745 if (real_target_type == TypeManager.decimal_type)
1746 return new ImplicitNew (ec, "System", "Decimal", loc, expr);
1747 } else if (expr_type == TypeManager.double_type){
1749 // From double to byte, short, int, long, float, decimal
1751 if (real_target_type == TypeManager.sbyte_type)
1752 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1);
1753 if (real_target_type == TypeManager.byte_type)
1754 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
1755 if (real_target_type == TypeManager.short_type)
1756 return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
1757 if (real_target_type == TypeManager.ushort_type)
1758 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2);
1759 if (real_target_type == TypeManager.int32_type)
1760 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
1761 if (real_target_type == TypeManager.uint32_type)
1762 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4);
1763 if (real_target_type == TypeManager.int64_type)
1764 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
1765 if (real_target_type == TypeManager.uint64_type)
1766 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8);
1768 if (real_target_type == TypeManager.float_type)
1769 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
1770 if (real_target_type == TypeManager.decimal_type)
1771 return new ImplicitNew (ec, "System", "Decimal", loc, expr);
1772 } else if (expr_type == TypeManager.decimal_type){
1774 // From decimal to byte, short, int, long
1776 if (real_target_type == TypeManager.byte_type)
1777 return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.convert_to_byte_decimal, expr);
1778 if (real_target_type == TypeManager.short_type)
1779 return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.convert_to_int16_decimal, expr);
1780 if (real_target_type == TypeManager.int32_type)
1781 return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.convert_to_int32_decimal, expr);
1782 if (real_target_type == TypeManager.int64_type)
1783 return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.convert_to_int64_decimal, expr);
1786 return null;
1789 /// <summary>
1790 /// VB.NET specific: Convert to and from boolean
1791 /// </summary>
1793 static public Expression BooleanConversions (EmitContext ec, Expression expr,
1794 Type target_type, Location loc)
1796 Type expr_type = expr.Type;
1797 Type real_target_type = target_type;
1799 if (expr_type == TypeManager.bool_type) {
1802 // From boolean to byte, short, int,
1803 // long, float, double, decimal
1806 if (real_target_type == TypeManager.byte_type)
1807 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_U1);
1808 if (real_target_type == TypeManager.short_type)
1809 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I2);
1810 if (real_target_type == TypeManager.int32_type)
1811 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I4);
1812 if (real_target_type == TypeManager.int64_type)
1813 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I8);
1814 if (real_target_type == TypeManager.float_type)
1815 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_R4);
1816 if (real_target_type == TypeManager.double_type)
1817 return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_R8);
1818 if (real_target_type == TypeManager.decimal_type) {
1819 return new HelperMethodInvocation (ec, expr.Location, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_boolean, expr);
1821 } if (real_target_type == TypeManager.bool_type) {
1824 // From byte, short, int, long, float,
1825 // double, decimal to boolean
1828 if (expr_type == TypeManager.byte_type ||
1829 expr_type == TypeManager.short_type ||
1830 expr_type == TypeManager.int32_type ||
1831 expr_type == TypeManager.int64_type ||
1832 expr_type == TypeManager.float_type ||
1833 expr_type == TypeManager.double_type)
1834 return new NumericToBooleanCast (expr, expr_type);
1835 if (expr_type == TypeManager.decimal_type) {
1836 return new HelperMethodInvocation (ec, expr.Location, TypeManager.bool_type, TypeManager.convert_to_boolean_decimal, expr);
1840 return null;
1843 /// <summary>
1844 /// VB.NET specific: Widening conversions to string
1845 /// </summary>
1847 static public Expression WideningStringConversions (EmitContext ec, Expression expr,
1848 Type target_type, Location loc)
1851 Type expr_type = expr.Type;
1852 Type real_target_type = target_type;
1854 if (real_target_type == TypeManager.string_type) {
1856 // From char to string
1858 if (expr_type == TypeManager.char_type)
1859 return new HelperMethodInvocation (ec, expr.Location, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_char, expr);
1862 if(expr_type.IsArray && (expr_type.GetElementType() == TypeManager.char_type)) {
1864 // From char array to string
1866 return new ImplicitNew (ec, "System", "String", loc, expr);
1869 return null;
1872 /// <summary>
1873 /// VB.NET specific: Narrowing conversions involving strings
1874 /// </summary>
1876 static public Expression NarrowingStringConversions (EmitContext ec, Expression expr,
1877 Type target_type, Location loc)
1879 Type expr_type = expr.Type;
1880 Type real_target_type = target_type;
1882 // FIXME: Need to take care of Constants
1884 if (expr_type == TypeManager.string_type) {
1887 // From string to chararray, bool,
1888 // byte, short, char, int, long,
1889 // float, double, decimal and date
1892 // if (real_target_type.IsArray && (real_target_type.GetElementType() == TypeManager.char_type))
1893 // return new HelperMethodInvocation (ec, loc, TypeManager.char_array_type, TypeManager.msvbcs_char_array_type_from_string, loc, expr);
1894 if (real_target_type == TypeManager.bool_type)
1895 return new HelperMethodInvocation (ec, loc, TypeManager.bool_type, TypeManager.msvbcs_booleantype_from_string, expr);
1896 if (real_target_type == TypeManager.byte_type)
1897 return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.msvbcs_bytetype_from_string, expr);
1898 if (real_target_type == TypeManager.short_type)
1899 return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.msvbcs_shorttype_from_string, expr);
1900 if (real_target_type == TypeManager.char_type)
1901 return new HelperMethodInvocation (ec, loc, TypeManager.char_type, TypeManager.msvbcs_chartype_from_string, expr);
1902 if (real_target_type == TypeManager.int32_type)
1903 return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.msvbcs_integertype_from_string, expr);
1904 if (real_target_type == TypeManager.int64_type)
1905 return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.msvbcs_longtype_from_string, expr);
1906 if (real_target_type == TypeManager.float_type)
1907 return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.msvbcs_singletype_from_string, expr);
1908 if (real_target_type == TypeManager.double_type)
1909 return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.msvbcs_doubletype_from_string, expr);
1910 if (real_target_type == TypeManager.decimal_type)
1911 return new HelperMethodInvocation (ec, loc, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_string, expr);
1912 if (real_target_type == TypeManager.date_type)
1913 return new HelperMethodInvocation (ec, loc, TypeManager.date_type, TypeManager.msvbcs_datetype_from_string, expr);
1914 } if (real_target_type == TypeManager.string_type) {
1917 // From bool, byte, short, char, int,
1918 // long, float, double, decimal and
1919 // date to string
1922 if (expr_type == TypeManager.bool_type)
1923 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_boolean, expr);
1924 if (expr_type == TypeManager.byte_type)
1925 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_byte, expr);
1926 if (expr_type == TypeManager.short_type)
1927 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_short, expr);
1928 if (expr_type == TypeManager.int32_type)
1929 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_integer, expr);
1930 if (expr_type == TypeManager.int64_type)
1931 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_long, expr);
1932 if (expr_type == TypeManager.float_type)
1933 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_single, expr);
1934 if (expr_type == TypeManager.double_type)
1935 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_double, expr);
1936 if (expr_type == TypeManager.decimal_type)
1937 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_decimal, expr);
1938 if (expr_type == TypeManager.date_type)
1939 return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_date, expr);
1942 return null;
1946 /// <summary>
1947 /// VB.NET specific: Conversions from Object to Primitive Types
1948 /// </summary>
1950 static public Expression ObjectTypeToPrimitiveTypes (EmitContext ec, Expression expr,
1951 Type target_type, Location loc)
1953 Type expr_type = expr.Type;
1954 Type real_target_type = target_type;
1955 MethodInfo helper_method = null;
1956 Expression retexpr;
1958 if (expr_type != TypeManager.object_type)
1959 return null;
1961 if (target_type.IsSubclassOf (TypeManager.enum_type))
1962 real_target_type = TypeManager.EnumToUnderlying (target_type);
1965 if (real_target_type == TypeManager.bool_type)
1966 helper_method = TypeManager.msvbcs_booleantype_fromobject_object;
1967 if (real_target_type == TypeManager.byte_type)
1968 helper_method = TypeManager.msvbcs_bytetype_fromobject_object;
1969 if (real_target_type == TypeManager.short_type)
1970 helper_method = TypeManager.msvbcs_shorttype_fromobject_object;
1971 if (real_target_type == TypeManager.char_type)
1972 helper_method = TypeManager.msvbcs_chartype_fromobject_object;
1973 if (real_target_type == TypeManager.int32_type)
1974 helper_method = TypeManager.msvbcs_integertype_fromobject_object;
1975 if (real_target_type == TypeManager.int64_type)
1976 helper_method = TypeManager.msvbcs_longtype_fromobject_object;
1977 if (real_target_type == TypeManager.float_type)
1978 helper_method = TypeManager.msvbcs_singletype_fromobject_object;
1979 if (real_target_type == TypeManager.double_type)
1980 helper_method = TypeManager.msvbcs_doubletype_fromobject_object;
1981 if (real_target_type == TypeManager.decimal_type)
1982 helper_method = TypeManager.msvbcs_decimaltype_fromobject_object;
1983 if (real_target_type == TypeManager.date_type)
1984 helper_method = TypeManager.msvbcs_datetype_fromobject_object;
1985 if (real_target_type == TypeManager.string_type)
1986 helper_method = TypeManager.msvbcs_stringtype_fromobject_object;
1988 if (helper_method != null) {
1989 retexpr = new HelperMethodInvocation (ec, loc, real_target_type, helper_method, expr);
1990 if (target_type != real_target_type)
1991 retexpr = new EmptyCast (retexpr, target_type);
1993 return retexpr;
1996 return null;
2000 /// <summary>
2001 /// Returns whether an explicit reference conversion can be performed
2002 /// from source_type to target_type
2003 /// </summary>
2004 public static bool NarrowingReferenceConversionExists (Type source_type, Type target_type)
2006 bool target_is_type_param = target_type.IsGenericParameter;
2007 bool target_is_value_type = target_type.IsValueType;
2009 if (source_type == target_type)
2010 return true;
2013 // From generic parameter to any type
2015 if (source_type.IsGenericParameter)
2016 return true;
2019 // From object to a generic parameter
2021 if (source_type == TypeManager.object_type && target_is_type_param)
2022 return true;
2025 // From object to any reference type
2027 if (source_type == TypeManager.object_type && !target_is_value_type)
2028 return true;
2031 // From any class S to any class-type T, provided S is a base class of T
2033 if (TypeManager.IsSubclassOf (target_type, source_type))
2034 return true;
2037 // From any interface type S to any interface T provided S is not derived from T
2039 if (source_type.IsInterface && target_type.IsInterface){
2040 if (!TypeManager.IsSubclassOf (target_type, source_type))
2041 return true;
2045 // From any class type S to any interface T, provided S is not sealed
2046 // and provided S does not implement T.
2048 if (target_type.IsInterface && !source_type.IsSealed &&
2049 !TypeManager.ImplementsInterface (source_type, target_type))
2050 return true;
2053 // From any interface-type S to to any class type T, provided T is not
2054 // sealed, or provided T implements S.
2056 if (source_type.IsInterface &&
2057 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
2058 return true;
2061 // From an array type S with an element type Se to an array type T with an
2062 // element type Te provided all the following are true:
2063 // * S and T differe only in element type, in other words, S and T
2064 // have the same number of dimensions.
2065 // * Both Se and Te are reference types
2066 // * An explicit referenc conversions exist from Se to Te
2068 if (source_type.IsArray && target_type.IsArray) {
2069 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2071 Type source_element_type = TypeManager.GetElementType (source_type);
2072 Type target_element_type = TypeManager.GetElementType (target_type);
2074 if (source_element_type.IsGenericParameter ||
2075 (!source_element_type.IsValueType && !target_element_type.IsValueType))
2076 if (NarrowingReferenceConversionExists (source_element_type,
2077 target_element_type))
2078 return true;
2083 // From System.Array to any array-type
2084 if (source_type == TypeManager.array_type &&
2085 target_type.IsArray){
2086 return true;
2090 // From System delegate to any delegate-type
2092 if (source_type == TypeManager.delegate_type &&
2093 TypeManager.IsDelegateType (target_type))
2094 return true;
2097 // From ICloneable to Array or Delegate types
2099 if (source_type == TypeManager.icloneable_type &&
2100 (target_type == TypeManager.array_type ||
2101 target_type == TypeManager.delegate_type))
2102 return true;
2104 return false;
2107 /// <summary>
2108 /// Implements Explicit Reference conversions
2109 /// </summary>
2110 static Expression NarrowingReferenceConversion (Expression source, Type target_type)
2112 Type source_type = source.Type;
2113 bool target_is_type_param = target_type.IsGenericParameter;
2114 bool target_is_value_type = target_type.IsValueType;
2117 // From object to a generic parameter
2119 if (source_type == TypeManager.object_type && target_is_type_param)
2120 return new UnboxCast (source, target_type);
2123 // From object to any reference type
2125 if (source_type == TypeManager.object_type && !target_is_value_type)
2126 return new ClassCast (source, target_type);
2129 // Unboxing conversion.
2131 if (((source_type == TypeManager.enum_type &&
2132 !(source is EmptyCast)) ||
2133 source_type == TypeManager.value_type) && target_is_value_type)
2134 return new UnboxCast (source, target_type);
2137 // From any class S to any class-type T, provided S is a base class of T
2139 if (TypeManager.IsSubclassOf (target_type, source_type))
2140 return new ClassCast (source, target_type);
2143 // From any interface type S to any interface T provided S is not derived from T
2145 if (source_type.IsInterface && target_type.IsInterface){
2146 if (TypeManager.ImplementsInterface (source_type, target_type))
2147 return null;
2148 else
2149 return new ClassCast (source, target_type);
2153 // From any class type S to any interface T, provides S is not sealed
2154 // and provided S does not implement T.
2156 if (target_type.IsInterface && !source_type.IsSealed) {
2157 if (TypeManager.ImplementsInterface (source_type, target_type))
2158 return null;
2159 else
2160 return new ClassCast (source, target_type);
2165 // From any interface-type S to to any class type T, provided T is not
2166 // sealed, or provided T implements S.
2168 if (source_type.IsInterface) {
2169 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
2170 if (target_type.IsClass)
2171 return new ClassCast (source, target_type);
2172 else
2173 return new UnboxCast (source, target_type);
2176 return null;
2179 // From an array type S with an element type Se to an array type T with an
2180 // element type Te provided all the following are true:
2181 // * S and T differe only in element type, in other words, S and T
2182 // have the same number of dimensions.
2183 // * Both Se and Te are reference types
2184 // * An explicit referenc conversions exist from Se to Te
2186 if (source_type.IsArray && target_type.IsArray) {
2187 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2189 Type source_element_type = TypeManager.GetElementType (source_type);
2190 Type target_element_type = TypeManager.GetElementType (target_type);
2192 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2193 if (NarrowingReferenceConversionExists (source_element_type,
2194 target_element_type))
2195 return new ClassCast (source, target_type);
2200 // From System.Array to any array-type
2201 if (source_type == TypeManager.array_type &&
2202 target_type.IsArray) {
2203 return new ClassCast (source, target_type);
2207 // From System delegate to any delegate-type
2209 if (source_type == TypeManager.delegate_type &&
2210 TypeManager.IsDelegateType (target_type))
2211 return new ClassCast (source, target_type);
2214 // From ICloneable to Array or Delegate types
2216 if (source_type == TypeManager.icloneable_type &&
2217 (target_type == TypeManager.array_type ||
2218 target_type == TypeManager.delegate_type))
2219 return new ClassCast (source, target_type);
2221 return null;
2224 /// <summary>
2225 /// Performs an explicit conversion of the expression `expr' whose
2226 /// type is expr.Type to `target_type'.
2227 /// </summary>
2228 static public Expression WideningAndNarrowingConversion (EmitContext ec, Expression expr,
2229 Type target_type, Location loc)
2231 Type expr_type = expr.Type;
2232 Type original_expr_type = expr_type;
2234 if (expr_type.IsSubclassOf (TypeManager.enum_type)){
2235 if (target_type == TypeManager.enum_type ||
2236 target_type == TypeManager.object_type) {
2237 if (expr is EnumConstant)
2238 expr = ((EnumConstant) expr).Child;
2239 // We really need all these casts here .... :-(
2240 expr = new BoxedCast (new EmptyCast (expr, expr_type));
2241 return new EmptyCast (expr, target_type);
2242 } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType &&
2243 target_type.IsSubclassOf (TypeManager.enum_type))
2244 return new UnboxCast (expr, target_type);
2247 // Notice that we have kept the expr_type unmodified, which is only
2248 // used later on to
2249 if (expr is EnumConstant)
2250 expr = ((EnumConstant) expr).Child;
2251 else
2252 expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
2253 expr_type = expr.Type;
2256 int errors = Report.Errors;
2257 Expression ne = WideningConversionStandard (ec, expr, target_type, loc);
2258 if (Report.Errors > errors)
2259 return null;
2261 if (ne != null)
2262 return ne;
2264 if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type))
2265 return new Nullable.LiftedConversion (
2266 expr, target_type, false, true, loc).Resolve (ec);
2268 ne = NarrowingNumericConversion (ec, expr, target_type, loc);
2269 if (ne != null)
2270 return ne;
2273 // Unboxing conversion.
2277 // VB.NET treats conversions from object to
2278 // the primitive types using the helper
2279 // routines in Microsoft.VisualBasic.dll
2282 ne = ObjectTypeToPrimitiveTypes(ec, expr, target_type, loc);
2283 if (ne != null)
2284 return ne;
2286 if (expr_type == TypeManager.object_type && target_type.IsValueType)
2287 return new UnboxCast (expr, target_type);
2290 // Skip the NarrowingReferenceConversion because we can not convert
2291 // from Null to a ValueType, and ExplicitReference wont check against
2292 // null literal explicitly
2294 if (expr_type != TypeManager.null_type){
2295 ne = NarrowingReferenceConversion (expr, target_type);
2296 if (ne != null)
2297 return ne;
2300 skip_explicit:
2301 if (ec.InUnsafe){
2302 if (target_type.IsPointer){
2303 if (expr_type.IsPointer)
2304 return new EmptyCast (expr, target_type);
2306 if (expr_type == TypeManager.sbyte_type ||
2307 expr_type == TypeManager.byte_type ||
2308 expr_type == TypeManager.short_type ||
2309 expr_type == TypeManager.ushort_type ||
2310 expr_type == TypeManager.int32_type ||
2311 expr_type == TypeManager.uint32_type ||
2312 expr_type == TypeManager.uint64_type ||
2313 expr_type == TypeManager.int64_type)
2314 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
2316 if (expr_type.IsPointer){
2317 Expression e = null;
2319 if (target_type == TypeManager.sbyte_type)
2320 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
2321 else if (target_type == TypeManager.byte_type)
2322 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
2323 else if (target_type == TypeManager.short_type)
2324 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
2325 else if (target_type == TypeManager.ushort_type)
2326 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
2327 else if (target_type == TypeManager.int32_type)
2328 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
2329 else if (target_type == TypeManager.uint32_type)
2330 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
2331 else if (target_type == TypeManager.uint64_type)
2332 e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
2333 else if (target_type == TypeManager.int64_type){
2334 e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
2337 if (e != null){
2338 Expression ci, ce;
2340 ci = WideningConversionStandard (ec, e, target_type, loc);
2342 if (ci != null)
2343 return ci;
2345 ce = NarrowingNumericConversion (ec, e, target_type, loc);
2346 if (ce != null)
2347 return ce;
2349 // We should always be able to go from an uint32
2350 // implicitly or explicitly to the other integral
2351 // types
2353 throw new Exception ("Internal compiler error");
2359 // VB.NET specific conversions
2362 ne = BooleanConversions (ec, expr, target_type, loc);
2363 if (ne != null)
2364 return ne;
2366 ne = NarrowingStringConversions (ec, expr, target_type, loc);
2367 if (ne != null)
2368 return ne;
2372 // VB.NET has no notion of User defined conversions
2375 // ne = ExplicitUserConversion (ec, expr, target_type, loc);
2376 // if (ne != null)
2377 // return ne;
2379 if (expr is NullLiteral){
2380 Report.Error (37, loc, "Cannot convert null to value type `" +
2381 TypeManager.CSharpName (target_type) + "'");
2382 return null;
2385 Error_CannotConvertType (loc, original_expr_type, target_type);
2386 return null;
2389 /// <summary>
2390 /// Same as WideningAndNarrowingConversion, only it doesn't include user defined conversions
2391 /// </summary>
2392 static public Expression WideningAndNarrowingConversionStandard (EmitContext ec, Expression expr,
2393 Type target_type, Location l)
2395 int errors = Report.Errors;
2396 Expression ne = WideningConversionStandard (ec, expr, target_type, l);
2397 if (Report.Errors > errors)
2398 return null;
2400 if (ne != null)
2401 return ne;
2403 if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type))
2404 return new Nullable.LiftedConversion (
2405 expr, target_type, false, true, l).Resolve (ec);
2407 ne = NarrowingNumericConversion (ec, expr, target_type, l);
2408 if (ne != null)
2409 return ne;
2411 ne = NarrowingReferenceConversion (expr, target_type);
2412 if (ne != null)
2413 return ne;
2415 Error_CannotConvertType (l, expr.Type, target_type);
2416 return null;
2419 /// <summary>
2420 /// Entry point for VB.NET specific implicit conversions
2421 /// </summary>
2422 static public Expression ImplicitVBConversion (EmitContext ec, Expression expr,
2423 Type target_type, Location loc)
2425 if (RootContext.StricterTypeChecking)
2426 return WideningConversion (ec, expr, target_type, loc);
2427 else
2428 return WideningAndNarrowingConversion(ec, expr, target_type, loc);
2431 /// <summary>
2432 /// Mandates VB.NET specific implicit conversions
2433 /// </summary>
2434 static public Expression ImplicitVBConversionRequired (EmitContext ec, Expression source,
2435 Type target_type, Location loc)
2437 Expression e;
2440 int errors = Report.Errors;
2441 e = ImplicitVBConversion (ec, source, target_type, loc);
2442 if (Report.Errors > errors)
2443 return null;
2444 if (e != null)
2445 return e;
2447 if (source is DoubleLiteral) {
2448 if (target_type == TypeManager.float_type) {
2449 Error_664 (loc, "float", "f");
2450 return null;
2452 if (target_type == TypeManager.decimal_type) {
2453 Error_664 (loc, "decimal", "m");
2454 return null;
2458 if (source is Constant){
2459 Constant c = (Constant) source;
2461 Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
2462 return null;
2465 Error_CannotWideningConversion (loc, source.Type, target_type);
2467 return null;
2470 /// <summary>
2471 /// Entry point for VB.NET specific explicit conversions
2472 /// </summary>
2473 static public Expression ExplicitVBConversion (EmitContext ec, Expression expr,
2474 Type target_type, Location loc)
2476 return WideningAndNarrowingConversion(ec, expr, target_type, loc);