2005-12-02 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / gmcs / convert.cs
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 //
10
11 namespace Mono.CSharp {
12         using System;
13         using System.Collections;
14         using System.Diagnostics;
15         using System.Reflection;
16         using System.Reflection.Emit;
17
18         //
19         // A container class for all the conversion operations
20         //
21         public class Convert {
22                 //
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.
26                 //
27                 // FIXME: renamed from `const' to `static' to allow bootstraping from older
28                 // versions of the compiler that could not cope with this construct.
29                 //
30                 public static EmitContext ConstantEC = null;
31                 
32                 static Expression TypeParameter_to_Null (Constant expr, Type target_type,
33                                                          Location loc)
34                 {
35                         if (!TypeParameter_to_Null (target_type)) {
36                                 Report.Error (403, loc, "Cannot convert null to the type " +
37                                               "parameter `{0}' becaues it could be a value " +
38                                               "type. Consider using `default ({0})' instead.",
39                                               target_type.ToString ());
40                                 return null;
41                         }
42
43                         return new NullCast (expr, target_type);
44                 }
45
46                 static bool TypeParameter_to_Null (Type target_type)
47                 {
48                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
49                         if (gc == null)
50                                 return false;
51
52                         if (gc.HasReferenceTypeConstraint)
53                                 return true;
54                         if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
55                                 return true;
56
57                         return false;
58                 }
59
60                 static Type TypeParam_EffectiveBaseType (EmitContext ec, GenericConstraints gc)
61                 {
62                         ArrayList list = new ArrayList ();
63                         list.Add (gc.EffectiveBaseClass);
64                         foreach (Type t in gc.InterfaceConstraints) {
65                                 if (!t.IsGenericParameter)
66                                         continue;
67
68                                 GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
69                                 if (new_gc != null)
70                                         list.Add (TypeParam_EffectiveBaseType (ec, new_gc));
71                         }
72                         return FindMostEncompassedType (ec, list);
73                 }
74
75                 static Expression ImplicitTypeParameterConversion (EmitContext ec, Expression expr,
76                                                                    Type target_type)
77                 {
78                         Type expr_type = expr.Type;
79
80                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
81
82                         if (gc == null) {
83                                 if (target_type == TypeManager.object_type)
84                                         return new BoxedCast (expr, target_type);
85
86                                 return null;
87                         }
88
89                         // We're converting from a type parameter which is known to be a reference type.
90                         Type base_type = TypeParam_EffectiveBaseType (ec, gc);
91
92                         if (TypeManager.IsSubclassOf (base_type, target_type))
93                                 return new ClassCast (expr, target_type);
94
95                         if (target_type.IsInterface) {
96                                 if (TypeManager.ImplementsInterface (base_type, target_type))
97                                         return new ClassCast (expr, target_type);
98
99                                 foreach (Type t in gc.InterfaceConstraints) {
100                                         if (TypeManager.IsSubclassOf (t, target_type))
101                                                 return new ClassCast (expr, target_type);
102                                         if (TypeManager.ImplementsInterface (t, target_type))
103                                                 return new ClassCast (expr, target_type);
104                                 }
105                         }
106
107                         foreach (Type t in gc.InterfaceConstraints) {
108                                 if (!t.IsGenericParameter)
109                                         continue;
110                                 if (TypeManager.IsSubclassOf (t, target_type))
111                                         return new ClassCast (expr, target_type);
112                                 if (TypeManager.ImplementsInterface (t, target_type))
113                                         return new ClassCast (expr, target_type);
114                         }
115
116                         return null;
117                 }
118
119                 static EmptyExpression MyEmptyExpr;
120                 static public Expression ImplicitReferenceConversion (EmitContext ec, Expression expr, Type target_type)
121                 {
122                         Type expr_type = expr.Type;
123
124                         if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
125                                 // if we are a method group, emit a warning
126
127                                 expr.Emit (null);
128                         }
129
130                         if (expr_type == TypeManager.void_type)
131                                 return null;
132
133                         if (expr_type.IsGenericParameter)
134                                 return ImplicitTypeParameterConversion (ec, expr, target_type);
135                                 
136                         //
137                         // notice that it is possible to write "ValueType v = 1", the ValueType here
138                         // is an abstract class, and not really a value type, so we apply the same rules.
139                         //
140                         if (target_type == TypeManager.object_type) {
141                                 //
142                                 // A pointer type cannot be converted to object
143                                 // 
144                                 if (expr_type.IsPointer)
145                                         return null;
146
147                                 if (TypeManager.IsValueType (expr_type))
148                                         return new BoxedCast (expr, target_type);
149                                 if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
150                                         if (expr_type == TypeManager.anonymous_method_type)
151                                                 return null;
152                                         return new EmptyCast (expr, target_type);
153                                 }
154
155                                 return null;
156                         } else if (target_type == TypeManager.value_type) {
157                                 if (TypeManager.IsValueType (expr_type))
158                                         return new BoxedCast (expr, target_type);
159                                 if (expr_type == TypeManager.null_type)
160                                         return new NullCast ((Constant)expr, target_type);
161
162                                 return null;
163                         } else if (TypeManager.IsSubclassOf (expr_type, target_type)) {
164                                 //
165                                 // Special case: enumeration to System.Enum.
166                                 // System.Enum is not a value type, it is a class, so we need
167                                 // a boxing conversion
168                                 //
169                                 if (expr_type.IsEnum || expr_type.IsGenericParameter)
170                                         return new BoxedCast (expr, target_type);
171
172                                 return new EmptyCast (expr, target_type);
173                         }
174
175                         // This code is kind of mirrored inside ImplicitStandardConversionExists
176                         // with the small distinction that we only probe there
177                         //
178                         // Always ensure that the code here and there is in sync
179
180                         // from the null type to any reference-type.
181                         if (expr_type == TypeManager.null_type){
182                                 if (target_type.IsPointer)
183                                         return new EmptyCast (NullPointer.Null, target_type);
184                                         
185                                 if (!target_type.IsValueType) {
186                                         if (expr is Constant)
187                                                 return new NullCast ((Constant)expr, target_type);
188
189                                         // I found only one case when it happens -- Foo () ? null : null;
190                                         Report.Warning (-100, 1, expr.Location, "The result of the expression is always `null'");
191                                         return new NullCast (new NullLiteral (expr.Location), target_type);
192                                 }
193                         }
194
195                         // from any class-type S to any interface-type T.
196                         if (target_type.IsInterface) {
197                                 if (target_type != TypeManager.iconvertible_type &&
198                                     expr_type.IsValueType && (expr is Constant) &&
199                                     !(expr is IntLiteral || expr is BoolLiteral ||
200                                       expr is FloatLiteral || expr is DoubleLiteral ||
201                                       expr is LongLiteral || expr is CharLiteral ||
202                                       expr is StringLiteral || expr is DecimalLiteral ||
203                                       expr is UIntLiteral || expr is ULongLiteral)) {
204                                         return null;
205                                 }
206
207                                 if (TypeManager.ImplementsInterface (expr_type, target_type)){
208                                         if (expr_type.IsGenericParameter || TypeManager.IsValueType (expr_type))
209                                                 return new BoxedCast (expr, target_type);
210                                         else
211                                                 return new EmptyCast (expr, target_type);
212                                 }
213                         }
214
215                         // from any interface type S to interface-type T.
216                         if (expr_type.IsInterface && target_type.IsInterface) {
217                                 if (TypeManager.ImplementsInterface (expr_type, target_type))
218                                         return new EmptyCast (expr, target_type);
219                                 else
220                                         return null;
221                         }
222
223                         // from an array-type S to an array-type of type T
224                         if (expr_type.IsArray && target_type.IsArray) {
225                                 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
226
227                                         Type expr_element_type = TypeManager.GetElementType (expr_type);
228
229                                         if (MyEmptyExpr == null)
230                                                 MyEmptyExpr = new EmptyExpression ();
231                                                 
232                                         MyEmptyExpr.SetType (expr_element_type);
233                                         Type target_element_type = TypeManager.GetElementType (target_type);
234
235                                         if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
236                                                 if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
237                                                                                       target_element_type))
238                                                         return new EmptyCast (expr, target_type);
239                                 }
240                         }
241                                 
242                         // from an array-type to System.Array
243                         if (expr_type.IsArray && target_type == TypeManager.array_type)
244                                 return new EmptyCast (expr, target_type);
245
246                         // from an array-type of type T to IEnumerable<T>
247                         if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
248                                 return new EmptyCast (expr, target_type);
249
250                         // from any delegate type to System.Delegate
251                         if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
252                             target_type == TypeManager.delegate_type)
253                                 return new EmptyCast (expr, target_type);
254                                         
255                         // from any array-type or delegate type into System.ICloneable.
256                         if (expr_type.IsArray ||
257                             expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
258                                 if (target_type == TypeManager.icloneable_type)
259                                         return new EmptyCast (expr, target_type);
260
261                         // from a generic type definition to a generic instance.
262                         if (TypeManager.IsEqual (expr_type, target_type))
263                                 return new EmptyCast (expr, target_type);
264
265                         return null;
266                 }
267
268                 //
269                 // Tests whether an implicit reference conversion exists between expr_type
270                 // and target_type
271                 //
272                 public static bool ImplicitReferenceConversionExists (EmitContext ec, Expression expr, Type target_type)
273                 {
274                         if (target_type.IsValueType)
275                                 return false;
276
277                         Type expr_type = expr.Type;
278
279                         if (expr_type.IsGenericParameter)
280                                 return ImplicitTypeParameterConversion (ec, expr, target_type) != null;
281
282                         //
283                         // This is the boxed case.
284                         //
285                         if (target_type == TypeManager.object_type) {
286                                 if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
287                                     expr_type.IsInterface || expr_type == TypeManager.enum_type)
288                                         if (target_type != TypeManager.anonymous_method_type)
289                                         return true;
290
291                                 return false;
292                         } else if (TypeManager.IsSubclassOf (expr_type, target_type))
293                                 return true;
294
295                         // Please remember that all code below actually comes
296                         // from ImplicitReferenceConversion so make sure code remains in sync
297                                 
298                         // from any class-type S to any interface-type T.
299                         if (target_type.IsInterface) {
300                                 if (target_type != TypeManager.iconvertible_type &&
301                                     expr_type.IsValueType && (expr is Constant) &&
302                                     !(expr is IntLiteral || expr is BoolLiteral ||
303                                       expr is FloatLiteral || expr is DoubleLiteral ||
304                                       expr is LongLiteral || expr is CharLiteral ||
305                                       expr is StringLiteral || expr is DecimalLiteral ||
306                                       expr is UIntLiteral || expr is ULongLiteral)) {
307                                         return false;
308                                 }
309                                 
310                                 if (TypeManager.ImplementsInterface (expr_type, target_type))
311                                         return true;
312                         }
313                                 
314                         // from any interface type S to interface-type T.
315                         if (expr_type.IsInterface && target_type.IsInterface)
316                                 if (TypeManager.ImplementsInterface (expr_type, target_type))
317                                         return true;
318                                 
319                         // from an array-type S to an array-type of type T
320                         if (expr_type.IsArray && target_type.IsArray) {
321                                 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
322                                                 
323                                         Type expr_element_type = expr_type.GetElementType ();
324
325                                         if (MyEmptyExpr == null)
326                                                 MyEmptyExpr = new EmptyExpression ();
327                                                 
328                                         MyEmptyExpr.SetType (expr_element_type);
329                                         Type target_element_type = TypeManager.GetElementType (target_type);
330                                                 
331                                         if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
332                                                 if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
333                                                                                       target_element_type))
334                                                         return true;
335                                 }
336                         }
337                                 
338                         // from an array-type to System.Array
339                         if (expr_type.IsArray && (target_type == TypeManager.array_type))
340                                 return true;
341
342                         // from an array-type of type T to IEnumerable<T>
343                         if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
344                                 return true;
345
346                         // from any delegate type to System.Delegate
347                         if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
348                             target_type == TypeManager.delegate_type)
349                                 if (target_type.IsAssignableFrom (expr_type))
350                                         return true;
351                                         
352                         // from any array-type or delegate type into System.ICloneable.
353                         if (expr_type.IsArray ||
354                             expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type))
355                                 if (target_type == TypeManager.icloneable_type)
356                                         return true;
357                                 
358                         // from the null type to any reference-type.
359                         if (expr_type == TypeManager.null_type){
360                                 if (target_type.IsPointer)
361                                         return true;
362                         
363                                 if (!target_type.IsValueType)
364                                         return true;
365                         }
366
367                         // from a generic type definition to a generic instance.
368                         if (TypeManager.IsEqual (expr_type, target_type))
369                                 return true;
370
371                         return false;
372                 }
373
374                 /// <summary>
375                 ///   Implicit Numeric Conversions.
376                 ///
377                 ///   expr is the expression to convert, returns a new expression of type
378                 ///   target_type or null if an implicit conversion is not possible.
379                 /// </summary>
380                 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
381                                                                     Type target_type)
382                 {
383                         Type expr_type = expr.Type;
384
385                         //
386                         // Attempt to do the implicit constant expression conversions
387
388                         if (expr is Constant){
389                                 if (expr is IntConstant){
390                                         Expression e;
391                                         
392                                         e = TryImplicitIntConversion (target_type, (IntConstant) expr);
393                                         
394                                         if (e != null)
395                                                 return e;
396                                 } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
397                                         //
398                                         // Try the implicit constant expression conversion
399                                         // from long to ulong, instead of a nice routine,
400                                         // we just inline it
401                                         //
402                                         long v = ((LongConstant) expr).Value;
403                                         if (v >= 0)
404                                                 return new ULongConstant ((ulong) v, expr.Location);
405                                 } 
406                         }
407                         
408                         Type real_target_type = target_type;
409
410                         if (expr_type == TypeManager.sbyte_type){
411                                 //
412                                 // From sbyte to short, int, long, float, double, decimal
413                                 //
414                                 if (real_target_type == TypeManager.int32_type)
415                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
416                                 if (real_target_type == TypeManager.int64_type)
417                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
418                                 if (real_target_type == TypeManager.double_type)
419                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
420                                 if (real_target_type == TypeManager.float_type)
421                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
422                                 if (real_target_type == TypeManager.short_type)
423                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
424                                 if (real_target_type == TypeManager.decimal_type)
425                                         return new CastToDecimal (expr);
426                         } else if (expr_type == TypeManager.byte_type){
427                                 //
428                                 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
429                                 // 
430                                 if ((real_target_type == TypeManager.short_type) ||
431                                     (real_target_type == TypeManager.ushort_type) ||
432                                     (real_target_type == TypeManager.int32_type) ||
433                                     (real_target_type == TypeManager.uint32_type))
434                                         return new EmptyCast (expr, target_type);
435
436                                 if (real_target_type == TypeManager.uint64_type)
437                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
438                                 if (real_target_type == TypeManager.int64_type)
439                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
440                                 if (real_target_type == TypeManager.float_type)
441                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
442                                 if (real_target_type == TypeManager.double_type)
443                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
444                                 if (real_target_type == TypeManager.decimal_type)
445                                         return new CastToDecimal (expr);
446                                 
447                         } else if (expr_type == TypeManager.short_type){
448                                 //
449                                 // From short to int, long, float, double, decimal
450                                 // 
451                                 if (real_target_type == TypeManager.int32_type)
452                                         return new EmptyCast (expr, target_type);
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.decimal_type)
460                                         return new CastToDecimal (expr);
461                                 
462                         } else if (expr_type == TypeManager.ushort_type){
463                                 //
464                                 // From ushort to int, uint, long, ulong, float, double, decimal
465                                 //
466                                 if (real_target_type == TypeManager.uint32_type)
467                                         return new EmptyCast (expr, target_type);
468
469                                 if (real_target_type == TypeManager.uint64_type)
470                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
471                                 if (real_target_type == TypeManager.int32_type)
472                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
473                                 if (real_target_type == TypeManager.int64_type)
474                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
475                                 if (real_target_type == TypeManager.double_type)
476                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
477                                 if (real_target_type == TypeManager.float_type)
478                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
479                                 if (real_target_type == TypeManager.decimal_type)
480                                         return new CastToDecimal (expr);
481                         } else if (expr_type == TypeManager.int32_type){
482                                 //
483                                 // From int to long, float, double, decimal
484                                 //
485                                 if (real_target_type == TypeManager.int64_type)
486                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
487                                 if (real_target_type == TypeManager.double_type)
488                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
489                                 if (real_target_type == TypeManager.float_type)
490                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
491                                 if (real_target_type == TypeManager.decimal_type)
492                                         return new CastToDecimal (expr);
493                         } else if (expr_type == TypeManager.uint32_type){
494                                 //
495                                 // From uint to long, ulong, float, double, decimal
496                                 //
497                                 if (real_target_type == TypeManager.int64_type)
498                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
499                                 if (real_target_type == TypeManager.uint64_type)
500                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
501                                 if (real_target_type == TypeManager.double_type)
502                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
503                                                                OpCodes.Conv_R8);
504                                 if (real_target_type == TypeManager.float_type)
505                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
506                                                                OpCodes.Conv_R4);
507                                 if (real_target_type == TypeManager.decimal_type)
508                                         return new CastToDecimal (expr);
509                         } else if (expr_type == TypeManager.int64_type){
510                                 //
511                                 // From long/ulong to float, double
512                                 //
513                                 if (real_target_type == TypeManager.double_type)
514                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
515                                 if (real_target_type == TypeManager.float_type)
516                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
517                                 if (real_target_type == TypeManager.decimal_type)
518                                         return new CastToDecimal (expr);
519                         } else if (expr_type == TypeManager.uint64_type){
520                                 //
521                                 // From ulong to float, double
522                                 //
523                                 if (real_target_type == TypeManager.double_type)
524                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
525                                                                OpCodes.Conv_R8);
526                                 if (real_target_type == TypeManager.float_type)
527                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
528                                                                OpCodes.Conv_R4);
529                                 if (real_target_type == TypeManager.decimal_type)
530                                         return new CastToDecimal (expr);
531                         } else if (expr_type == TypeManager.char_type){
532                                 //
533                                 // From char to ushort, int, uint, long, ulong, float, double, decimal
534                                 // 
535                                 if ((real_target_type == TypeManager.ushort_type) ||
536                                     (real_target_type == TypeManager.int32_type) ||
537                                     (real_target_type == TypeManager.uint32_type))
538                                         return new EmptyCast (expr, target_type);
539                                 if (real_target_type == TypeManager.uint64_type)
540                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
541                                 if (real_target_type == TypeManager.int64_type)
542                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
543                                 if (real_target_type == TypeManager.float_type)
544                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
545                                 if (real_target_type == TypeManager.double_type)
546                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
547                                 if (real_target_type == TypeManager.decimal_type)
548                                         return new CastToDecimal (expr);
549                         } else if (expr_type == TypeManager.float_type){
550                                 //
551                                 // float to double
552                                 //
553                                 if (real_target_type == TypeManager.double_type)
554                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
555                         }
556
557                         return null;
558                 }
559
560                 /// <summary>
561                 ///  Same as ImplicitStandardConversionExists except that it also looks at
562                 ///  implicit user defined conversions - needed for overload resolution
563                 /// </summary>
564                 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
565                 {
566                         if (expr is NullLiteral) {
567                                 if (target_type.IsGenericParameter)
568                                         return TypeParameter_to_Null (target_type);
569
570                                 if (TypeManager.IsNullableType (target_type))
571                                         return true;
572                         }
573
574                         if (ImplicitStandardConversionExists (ec, expr, target_type))
575                                 return true;
576
577                         Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
578
579                         if (dummy != null)
580                                 return true;
581
582                         return false;
583                 }
584
585                 public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
586                 {
587                         return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null;
588                 }
589
590                 /// <summary>
591                 ///  Determines if a standard implicit conversion exists from
592                 ///  expr_type to target_type
593                 ///
594                 ///  ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
595                 /// </summary>
596                 public static bool ImplicitStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
597                 {
598                         Type expr_type = expr.Type;
599
600                         if (expr_type == TypeManager.void_type)
601                                 return false;
602
603                         //Console.WriteLine ("Expr is {0}", expr);
604                         //Console.WriteLine ("{0} -> {1} ?", expr_type, target_type);
605                         if (expr_type.Equals (target_type))
606                                 return true;
607
608
609                         // First numeric conversions 
610
611                         if (expr_type == TypeManager.sbyte_type){
612                                 //
613                                 // From sbyte to short, int, long, float, double, decimal
614                                 //
615                                 if ((target_type == TypeManager.int32_type) || 
616                                     (target_type == TypeManager.int64_type) ||
617                                     (target_type == TypeManager.double_type) ||
618                                     (target_type == TypeManager.float_type)  ||
619                                     (target_type == TypeManager.short_type) ||
620                                     (target_type == TypeManager.decimal_type))
621                                         return true;
622                                 
623                         } else if (expr_type == TypeManager.byte_type){
624                                 //
625                                 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal
626                                 // 
627                                 if ((target_type == TypeManager.short_type) ||
628                                     (target_type == TypeManager.ushort_type) ||
629                                     (target_type == TypeManager.int32_type) ||
630                                     (target_type == TypeManager.uint32_type) ||
631                                     (target_type == TypeManager.uint64_type) ||
632                                     (target_type == TypeManager.int64_type) ||
633                                     (target_type == TypeManager.float_type) ||
634                                     (target_type == TypeManager.double_type) ||
635                                     (target_type == TypeManager.decimal_type))
636                                         return true;
637         
638                         } else if (expr_type == TypeManager.short_type){
639                                 //
640                                 // From short to int, long, double, float, decimal
641                                 // 
642                                 if ((target_type == TypeManager.int32_type) ||
643                                     (target_type == TypeManager.int64_type) ||
644                                     (target_type == TypeManager.double_type) ||
645                                     (target_type == TypeManager.float_type) ||
646                                     (target_type == TypeManager.decimal_type))
647                                         return true;
648                                         
649                         } else if (expr_type == TypeManager.ushort_type){
650                                 //
651                                 // From ushort to int, uint, long, ulong, double, float, decimal
652                                 //
653                                 if ((target_type == TypeManager.uint32_type) ||
654                                     (target_type == TypeManager.uint64_type) ||
655                                     (target_type == TypeManager.int32_type) ||
656                                     (target_type == TypeManager.int64_type) ||
657                                     (target_type == TypeManager.double_type) ||
658                                     (target_type == TypeManager.float_type) ||
659                                     (target_type == TypeManager.decimal_type))
660                                         return true;
661                                     
662                         } else if (expr_type == TypeManager.int32_type){
663                                 //
664                                 // From int to long, double, float, decimal
665                                 //
666                                 if ((target_type == TypeManager.int64_type) ||
667                                     (target_type == TypeManager.double_type) ||
668                                     (target_type == TypeManager.float_type) ||
669                                     (target_type == TypeManager.decimal_type))
670                                         return true;
671                                         
672                         } else if (expr_type == TypeManager.uint32_type){
673                                 //
674                                 // From uint to long, ulong, double, float, decimal
675                                 //
676                                 if ((target_type == TypeManager.int64_type) ||
677                                     (target_type == TypeManager.uint64_type) ||
678                                     (target_type == TypeManager.double_type) ||
679                                     (target_type == TypeManager.float_type) ||
680                                     (target_type == TypeManager.decimal_type))
681                                         return true;
682                                         
683                         } else if ((expr_type == TypeManager.uint64_type) ||
684                                    (expr_type == TypeManager.int64_type)) {
685                                 //
686                                 // From long/ulong to double, float, decimal
687                                 //
688                                 if ((target_type == TypeManager.double_type) ||
689                                     (target_type == TypeManager.float_type) ||
690                                     (target_type == TypeManager.decimal_type))
691                                         return true;
692                                     
693                         } else if (expr_type == TypeManager.char_type){
694                                 //
695                                 // From char to ushort, int, uint, ulong, long, float, double, decimal
696                                 // 
697                                 if ((target_type == TypeManager.ushort_type) ||
698                                     (target_type == TypeManager.int32_type) ||
699                                     (target_type == TypeManager.uint32_type) ||
700                                     (target_type == TypeManager.uint64_type) ||
701                                     (target_type == TypeManager.int64_type) ||
702                                     (target_type == TypeManager.float_type) ||
703                                     (target_type == TypeManager.double_type) ||
704                                     (target_type == TypeManager.decimal_type))
705                                         return true;
706
707                         } else if (expr_type == TypeManager.float_type){
708                                 //
709                                 // float to double
710                                 //
711                                 if (target_type == TypeManager.double_type)
712                                         return true;
713                         }       
714                         
715                         if (expr.eclass == ExprClass.MethodGroup){
716                                 if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
717                                         MethodGroupExpr mg = expr as MethodGroupExpr;
718                                         if (mg != null){
719                                                 //
720                                                 // This should not happen frequently, so we can create an object
721                                                 // to test compatibility
722                                                 //
723                                                 Expression c = ImplicitDelegateCreation.Create (
724                                                         ec, mg, target_type, true, Location.Null);
725                                                 return c != null;
726                                         }
727                                 }
728                         }
729                         
730                         if (ImplicitReferenceConversionExists (ec, expr, target_type))
731                                 return true;
732
733                         //
734                         // Implicit Constant Expression Conversions
735                         //
736                         if (expr is IntConstant){
737                                 int value = ((IntConstant) expr).Value;
738
739                                 if (target_type == TypeManager.sbyte_type){
740                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
741                                                 return true;
742                                 } else if (target_type == TypeManager.byte_type){
743                                         if (value >= 0 && value <= Byte.MaxValue)
744                                                 return true;
745                                 } else if (target_type == TypeManager.short_type){
746                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
747                                                 return true;
748                                 } else if (target_type == TypeManager.ushort_type){
749                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
750                                                 return true;
751                                 } else if (target_type == TypeManager.uint32_type){
752                                         if (value >= 0)
753                                                 return true;
754                                 } else if (target_type == TypeManager.uint64_type){
755                                          //
756                                          // we can optimize this case: a positive int32
757                                          // always fits on a uint64.  But we need an opcode
758                                          // to do it.
759                                          //
760                                         if (value >= 0)
761                                                 return true;
762                                 }
763                                 
764                                 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
765                                         return true;
766                         }
767
768                         if (expr is LongConstant && target_type == TypeManager.uint64_type){
769                                 //
770                                 // Try the implicit constant expression conversion
771                                 // from long to ulong, instead of a nice routine,
772                                 // we just inline it
773                                 //
774                                 long v = ((LongConstant) expr).Value;
775                                 if (v >= 0)
776                                         return true;
777                         }
778                         
779                         if ((target_type == TypeManager.enum_type ||
780                              target_type.IsSubclassOf (TypeManager.enum_type)) &&
781                              expr is IntLiteral){
782                                 IntLiteral i = (IntLiteral) expr;
783
784                                 if (i.Value == 0)
785                                         return true;
786                         }
787
788                         //
789                         // If `expr_type' implements `target_type' (which is an iface)
790                         // see TryImplicitIntConversion
791                         // 
792                         if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
793                                 return true;
794
795                         if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
796                                 return true;
797
798                         if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
799                                 return true;
800
801                         if (expr_type == TypeManager.anonymous_method_type){
802                                 if (!TypeManager.IsDelegateType (target_type))
803                                         return false;
804
805                                 AnonymousMethod am = (AnonymousMethod) expr;
806
807                                 Expression conv = am.Compatible (ec, target_type, true);
808                                 if (conv != null)
809                                         return true;
810                         }
811
812                         return false;
813                 }
814
815                 /// <summary>
816                 ///  Finds "most encompassed type" according to the spec (13.4.2)
817                 ///  amongst the methods in the MethodGroupExpr
818                 /// </summary>
819                 static Type FindMostEncompassedType (EmitContext ec, ArrayList types)
820                 {
821                         Type best = null;
822
823                         if (types.Count == 0)
824                                 return null;
825
826                         if (types.Count == 1)
827                                 return (Type) types [0];
828
829                         EmptyExpression expr = EmptyExpression.Grab ();
830
831                         foreach (Type t in types) {
832                                 if (best == null) {
833                                         best = t;
834                                         continue;
835                                 }
836
837                                 expr.SetType (t);
838                                 if (ImplicitStandardConversionExists (ec, expr, best))
839                                         best = t;
840                         }
841
842                         expr.SetType (best);
843                         foreach (Type t in types) {
844                                 if (best == t)
845                                         continue;
846                                 if (!ImplicitStandardConversionExists (ec, expr, t)) {
847                                         best = null;
848                                         break;
849                                 }
850                         }
851
852                         EmptyExpression.Release (expr);
853
854                         return best;
855                 }
856         
857                 /// <summary>
858                 ///  Finds "most encompassing type" according to the spec (13.4.2)
859                 ///  amongst the types in the given set
860                 /// </summary>
861                 static Type FindMostEncompassingType (EmitContext ec, ArrayList types)
862                 {
863                         Type best = null;
864
865                         if (types.Count == 0)
866                                 return null;
867
868                         if (types.Count == 1)
869                                 return (Type) types [0];
870
871                         EmptyExpression expr = EmptyExpression.Grab ();
872
873                         foreach (Type t in types) {
874                                 if (best == null) {
875                                         best = t;
876                                         continue;
877                                 }
878
879                                 expr.SetType (best);
880                                 if (ImplicitStandardConversionExists (ec, expr, t))
881                                         best = t;
882                         }
883
884                         foreach (Type t in types) {
885                                 if (best == t)
886                                         continue;
887                                 expr.SetType (t);
888                                 if (!ImplicitStandardConversionExists (ec, expr, best)) {
889                                         best = null;
890                                         break;
891                                 }
892                         }
893
894                         EmptyExpression.Release (expr);
895
896                         return best;
897                 }
898
899                 /// <summary>
900                 ///   Finds the most specific source Sx according to the rules of the spec (13.4.4)
901                 ///   by making use of FindMostEncomp* methods. Applies the correct rules separately
902                 ///   for explicit and implicit conversion operators.
903                 /// </summary>
904                 static public Type FindMostSpecificSource (EmitContext ec, IList list,
905                                                            Expression source, bool apply_explicit_conv_rules)
906                 {
907                         ArrayList src_types_set = new ArrayList ();
908                         
909                         //
910                         // If any operator converts from S then Sx = S
911                         //
912                         Type source_type = source.Type;
913                         foreach (MethodBase mb in list){
914                                 ParameterData pd = TypeManager.GetParameterData (mb);
915                                 Type param_type = pd.ParameterType (0);
916
917                                 if (param_type == source_type)
918                                         return param_type;
919
920                                 src_types_set.Add (param_type);
921                         }
922                         
923                         //
924                         // Explicit Conv rules
925                         //
926                         if (apply_explicit_conv_rules) {
927                                 ArrayList candidate_set = new ArrayList ();
928
929                                 foreach (Type param_type in src_types_set){
930                                         if (ImplicitStandardConversionExists (ec, source, param_type))
931                                                 candidate_set.Add (param_type);
932                                 }
933
934                                 if (candidate_set.Count != 0)
935                                         return FindMostEncompassedType (ec, candidate_set);
936                         }
937
938                         //
939                         // Final case
940                         //
941                         if (apply_explicit_conv_rules)
942                                 return FindMostEncompassingType (ec, src_types_set);
943                         else
944                                 return FindMostEncompassedType (ec, src_types_set);
945                 }
946
947                 /// <summary>
948                 ///  Finds the most specific target Tx according to section 13.4.4
949                 /// </summary>
950                 static public Type FindMostSpecificTarget (EmitContext ec, IList list,
951                                                            Type target, bool apply_explicit_conv_rules)
952                 {
953                         ArrayList tgt_types_set = new ArrayList ();
954                         
955                         //
956                         // If any operator converts to T then Tx = T
957                         //
958                         foreach (MethodInfo mi in list){
959                                 Type ret_type = mi.ReturnType;
960                                 if (ret_type == target)
961                                         return ret_type;
962
963                                 tgt_types_set.Add (ret_type);
964                         }
965
966                         //
967                         // Explicit conv rules
968                         //
969                         if (apply_explicit_conv_rules) {
970                                 ArrayList candidate_set = new ArrayList ();
971
972                                 EmptyExpression expr = EmptyExpression.Grab ();
973
974                                 foreach (Type ret_type in tgt_types_set){
975                                         expr.SetType (ret_type);
976                                         
977                                         if (ImplicitStandardConversionExists (ec, expr, target))
978                                                 candidate_set.Add (ret_type);
979                                 }
980
981                                 EmptyExpression.Release (expr);
982
983                                 if (candidate_set.Count != 0)
984                                         return FindMostEncompassingType (ec, candidate_set);
985                         }
986                         
987                         //
988                         // Okay, final case !
989                         //
990                         if (apply_explicit_conv_rules)
991                                 return FindMostEncompassedType (ec, tgt_types_set);
992                         else 
993                                 return FindMostEncompassingType (ec, tgt_types_set);
994                 }
995                 
996                 /// <summary>
997                 ///  User-defined Implicit conversions
998                 /// </summary>
999                 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1000                                                                  Type target, Location loc)
1001                 {
1002                         return UserDefinedConversion (ec, source, target, loc, false);
1003                 }
1004
1005                 /// <summary>
1006                 ///  User-defined Explicit conversions
1007                 /// </summary>
1008                 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1009                                                                  Type target, Location loc)
1010                 {
1011                         return UserDefinedConversion (ec, source, target, loc, true);
1012                 }
1013
1014                 static void AddConversionOperators (EmitContext ec, ArrayList list, 
1015                                                     Expression source, Type target_type, 
1016                                                     bool look_for_explicit,
1017                                                     MethodGroupExpr mg)
1018                 {
1019                         if (mg == null)
1020                                 return;
1021
1022                         Type source_type = source.Type;
1023                         EmptyExpression expr = EmptyExpression.Grab ();
1024                         foreach (MethodInfo m in mg.Methods) {
1025                                 ParameterData pd = TypeManager.GetParameterData (m);
1026                                 Type return_type = m.ReturnType;
1027                                 Type arg_type = pd.ParameterType (0);
1028
1029                                 if (source_type != arg_type) {
1030                                         if (!ImplicitStandardConversionExists (ec, source, arg_type)) {
1031                                                 if (!look_for_explicit)
1032                                                         continue;
1033                                                 expr.SetType (arg_type);
1034                                                 if (!ImplicitStandardConversionExists (ec, expr, source_type))
1035                                                         continue;
1036                                         }
1037                                 }
1038
1039                                 if (target_type != return_type) {
1040                                         expr.SetType (return_type);
1041                                         if (!ImplicitStandardConversionExists (ec, expr, target_type)) {
1042                                                 if (!look_for_explicit)
1043                                                         continue;
1044                                                 expr.SetType (target_type);
1045                                                 if (!ImplicitStandardConversionExists (ec, expr, return_type))
1046                                                         continue;
1047                                         }
1048                                 }
1049
1050                                 list.Add (m);
1051                         }
1052
1053                         EmptyExpression.Release (expr);
1054                 }
1055
1056                 /// <summary>
1057                 ///   Compute the user-defined conversion operator from source_type to target_type. 
1058                 ///   `look_for_explicit' controls whether we should also include the list of explicit operators
1059                 /// </summary>
1060                 static MethodInfo GetConversionOperator (EmitContext ec, Expression source, Type target_type, bool look_for_explicit)
1061                 {
1062                         ArrayList ops = new ArrayList (4);
1063
1064                         Type source_type = source.Type;
1065
1066                         if (source_type != TypeManager.decimal_type) {
1067                                 AddConversionOperators (ec, ops, source, target_type, look_for_explicit,
1068                                         Expression.MethodLookup (ec, source_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1069                                 if (look_for_explicit) {
1070                                         AddConversionOperators (ec, ops, source, target_type, look_for_explicit,
1071                                                 Expression.MethodLookup (
1072                                                         ec, source_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1073                                 }
1074                         }
1075
1076                         if (target_type != TypeManager.decimal_type) {
1077                                 AddConversionOperators (ec, ops, source, target_type, look_for_explicit,
1078                                         Expression.MethodLookup (ec, target_type, "op_Implicit", Location.Null) as MethodGroupExpr);
1079                                 if (look_for_explicit) {
1080                                         AddConversionOperators (ec, ops, source, target_type, look_for_explicit,
1081                                                 Expression.MethodLookup (
1082                                                         ec, target_type, "op_Explicit", Location.Null) as MethodGroupExpr);
1083                                 }
1084                         }
1085
1086                         if (ops.Count == 0)
1087                                 return null;
1088
1089                         Type most_specific_source = FindMostSpecificSource (ec, ops, source, look_for_explicit);
1090                         if (most_specific_source == null)
1091                                 return null;
1092
1093                         Type most_specific_target = FindMostSpecificTarget (ec, ops, target_type, look_for_explicit);
1094                         if (most_specific_target == null)
1095                                 return null;
1096
1097                         MethodInfo method = null;
1098
1099                         foreach (MethodInfo m in ops) {
1100                                 if (m.ReturnType != most_specific_target)
1101                                         continue;
1102                                 if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source)
1103                                         continue;
1104                                 // Ambiguous: more than one conversion operator satisfies the signature.
1105                                 if (method != null)
1106                                         return null;
1107                                 method = m;
1108                         }
1109
1110                         return method;
1111                 }
1112
1113                 static DoubleHash explicit_conv = new DoubleHash (100);
1114                 static DoubleHash implicit_conv = new DoubleHash (100);
1115
1116                 /// <summary>
1117                 ///   User-defined conversions
1118                 /// </summary>
1119                 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1120                                                                 Type target, Location loc,
1121                                                                 bool look_for_explicit)
1122                 {
1123                         Type source_type = source.Type;
1124                         MethodInfo method = null;
1125
1126                         if (TypeManager.IsNullableType (source_type) && TypeManager.IsNullableType (target))
1127                                 return new Nullable.LiftedConversion (
1128                                         source, target, true, look_for_explicit, loc).Resolve (ec);
1129
1130                         object o;
1131                         DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv;
1132
1133                         if (!(source is Constant) && hash.Lookup (source_type, target, out o)) {
1134                                 method = (MethodInfo) o;
1135                         } else {
1136                                 method = GetConversionOperator (ec, source, target, look_for_explicit);
1137                                 if (!(source is Constant))
1138                                         hash.Insert (source_type, target, method);
1139                         }
1140
1141                         if (method == null)
1142                                 return null;
1143                         
1144                         Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0);
1145
1146                         //
1147                         // This will do the conversion to the best match that we
1148                         // found.  Now we need to perform an implict standard conversion
1149                         // if the best match was not the type that we were requested
1150                         // by target.
1151                         //
1152                         if (look_for_explicit)
1153                                 source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
1154                         else
1155                                 source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
1156
1157                         if (source == null)
1158                                 return null;
1159
1160                         Expression e;
1161                         e =  new UserCast (method, source, loc);
1162                         if (e.Type != target){
1163                                 if (!look_for_explicit)
1164                                         e = ImplicitConversionStandard (ec, e, target, loc);
1165                                 else
1166                                         e = ExplicitConversionStandard (ec, e, target, loc);
1167                         }
1168
1169                         return e;
1170                 }
1171                 
1172                 /// <summary>
1173                 ///   Converts implicitly the resolved expression `expr' into the
1174                 ///   `target_type'.  It returns a new expression that can be used
1175                 ///   in a context that expects a `target_type'. 
1176                 /// </summary>
1177                 static public Expression ImplicitConversion (EmitContext ec, Expression expr,
1178                                                              Type target_type, Location loc)
1179                 {
1180                         Expression e;
1181
1182                         if (target_type == null)
1183                                 throw new Exception ("Target type is null");
1184
1185                         e = ImplicitConversionStandard (ec, expr, target_type, loc);
1186                         if (e != null)
1187                                 return e;
1188
1189                         e = ImplicitUserConversion (ec, expr, target_type, loc);
1190                         if (e != null)
1191                                 return e;
1192
1193                         return null;
1194                 }
1195
1196                 
1197                 /// <summary>
1198                 ///   Attempts to apply the `Standard Implicit
1199                 ///   Conversion' rules to the expression `expr' into
1200                 ///   the `target_type'.  It returns a new expression
1201                 ///   that can be used in a context that expects a
1202                 ///   `target_type'.
1203                 ///
1204                 ///   This is different from `ImplicitConversion' in that the
1205                 ///   user defined implicit conversions are excluded. 
1206                 /// </summary>
1207                 static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
1208                                                                      Type target_type, Location loc)
1209                 {
1210                         Type expr_type = expr.Type;
1211                         Expression e;
1212
1213                         if (expr is NullLiteral) {
1214                                 if (target_type.IsGenericParameter)
1215                                         return TypeParameter_to_Null ((Constant) expr, target_type, loc);
1216
1217                                 if (TypeManager.IsNullableType (target_type))
1218                                         return new Nullable.NullableLiteral (target_type, loc);
1219                         }
1220
1221                         if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
1222                                 return new Nullable.LiftedConversion (
1223                                         expr, target_type, false, false, loc).Resolve (ec);
1224
1225                         if (expr.eclass == ExprClass.MethodGroup){
1226                                 if (!TypeManager.IsDelegateType (target_type)){
1227                                         return null;
1228                                 }
1229
1230                                 //
1231                                 // Only allow anonymous method conversions on post ISO_1
1232                                 //
1233                                 if (RootContext.Version != LanguageVersion.ISO_1){
1234                                         MethodGroupExpr mg = expr as MethodGroupExpr;
1235                                         if (mg != null)
1236                                                 return ImplicitDelegateCreation.Create (
1237                                                         ec, mg, target_type, false, loc);
1238                                 }
1239                         }
1240
1241                         if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
1242                                 return expr;
1243
1244                         e = ImplicitNumericConversion (ec, expr, target_type);
1245                         if (e != null)
1246                                 return e;
1247
1248                         e = ImplicitReferenceConversion (ec, expr, target_type);
1249                         if (e != null)
1250                                 return e;
1251                         
1252                         if (TypeManager.IsEnumType (target_type) && expr is IntLiteral){
1253                                 IntLiteral i = (IntLiteral) expr;
1254
1255                                 if (i.Value == 0)
1256                                         return new EnumConstant ((Constant) expr, target_type);
1257                         }
1258
1259                         if (ec.InUnsafe) {
1260                                 if (expr_type.IsPointer){
1261                                         if (target_type == TypeManager.void_ptr_type)
1262                                                 return new EmptyCast (expr, target_type);
1263
1264                                         //
1265                                         // yep, comparing pointer types cant be done with
1266                                         // t1 == t2, we have to compare their element types.
1267                                         //
1268                                         if (target_type.IsPointer){
1269                                                 if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type))
1270                                                         return expr;
1271
1272                                                 //return null;
1273                                         }
1274                                 }
1275                                 
1276                                 if (expr_type == TypeManager.null_type && target_type.IsPointer)
1277                                         return new EmptyCast (NullPointer.Null, target_type);
1278                         }
1279
1280                         if (expr_type == TypeManager.anonymous_method_type){
1281                                 if (!TypeManager.IsDelegateType (target_type)){
1282                                         Report.Error (1660, loc,
1283                                                 "Cannot convert anonymous method block to type `{0}' because it is not a delegate type",
1284                                                 TypeManager.CSharpName (target_type));
1285                                         return null;
1286                                 }
1287
1288                                 AnonymousMethod am = (AnonymousMethod) expr;
1289                                 int errors = Report.Errors;
1290
1291                                 Expression conv = am.Compatible (ec, target_type, false);
1292                                 if (conv != null)
1293                                         return conv;
1294                                 
1295                                 //
1296                                 // We return something instead of null, to avoid
1297                                 // the duplicate error, since am.Compatible would have
1298                                 // reported that already
1299                                 //
1300                                 if (errors != Report.Errors)
1301                                         return new EmptyCast (expr, target_type);
1302                         }
1303                         
1304                         return null;
1305                 }
1306
1307                 /// <summary>
1308                 ///   Attempts to perform an implicit constant conversion of the IntConstant
1309                 ///   into a different data type using casts (See Implicit Constant
1310                 ///   Expression Conversions)
1311                 /// </summary>
1312                 static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
1313                 {
1314                         int value = ic.Value;
1315
1316                         if (target_type == TypeManager.sbyte_type){
1317                                 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1318                                         return new SByteConstant ((sbyte) value, ic.Location);
1319                         } else if (target_type == TypeManager.byte_type){
1320                                 if (value >= Byte.MinValue && value <= Byte.MaxValue)
1321                                         return new ByteConstant ((byte) value, ic.Location);
1322                         } else if (target_type == TypeManager.short_type){
1323                                 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1324                                         return new ShortConstant ((short) value, ic.Location);
1325                         } else if (target_type == TypeManager.ushort_type){
1326                                 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1327                                         return new UShortConstant ((ushort) value, ic.Location);
1328                         } else if (target_type == TypeManager.uint32_type){
1329                                 if (value >= 0)
1330                                         return new UIntConstant ((uint) value, ic.Location);
1331                         } else if (target_type == TypeManager.uint64_type){
1332                                 //
1333                                 // we can optimize this case: a positive int32
1334                                 // always fits on a uint64.  But we need an opcode
1335                                 // to do it.
1336                                 //
1337                                 if (value >= 0)
1338                                         return new ULongConstant ((ulong) value, ic.Location);
1339                         } else if (target_type == TypeManager.double_type)
1340                                 return new DoubleConstant ((double) value, ic.Location);
1341                         else if (target_type == TypeManager.float_type)
1342                                 return new FloatConstant ((float) value, ic.Location);
1343                         
1344                         if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
1345                                 Type underlying = TypeManager.EnumToUnderlying (target_type);
1346                                 Constant e = (Constant) ic;
1347                                 
1348                                 //
1349                                 // Possibly, we need to create a different 0 literal before passing
1350                                 // to EnumConstant
1351                                 //
1352                                 if (underlying == TypeManager.int64_type)
1353                                         e = new LongLiteral (0, ic.Location);
1354                                 else if (underlying == TypeManager.uint64_type)
1355                                         e = new ULongLiteral (0, ic.Location);
1356
1357                                 return new EnumConstant (e, target_type);
1358                         }
1359
1360                         //
1361                         // If `target_type' is an interface and the type of `ic' implements the interface
1362                         // e.g. target_type is IComparable, IConvertible, IFormattable
1363                         //
1364                         if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
1365                                 return new BoxedCast (ic, target_type);
1366
1367                         return null;
1368                 }
1369
1370                 /// <summary>
1371                 ///   Attempts to implicitly convert `source' into `target_type', using
1372                 ///   ImplicitConversion.  If there is no implicit conversion, then
1373                 ///   an error is signaled
1374                 /// </summary>
1375                 static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
1376                                                                      Type target_type, Location loc)
1377                 {
1378                         Expression e;
1379
1380                         int errors = Report.Errors;
1381                         e = ImplicitConversion (ec, source, target_type, loc);
1382                         if (Report.Errors > errors)
1383                                 return null;
1384                         if (e != null)
1385                                 return e;
1386
1387                         if (source is DoubleLiteral) {
1388                                 if (target_type == TypeManager.float_type) {
1389                                         Error_664 (loc, "float", "f");
1390                                         return null;
1391                                 }
1392                                 if (target_type == TypeManager.decimal_type) {
1393                                         Error_664 (loc, "decimal", "m");
1394                                         return null;
1395                                 }
1396                         }
1397
1398                         source.Error_ValueCannotBeConverted (loc, target_type, false);
1399                         return null;
1400                 }
1401
1402                 static void Error_664 (Location loc, string type, string suffix) {
1403                         Report.Error (664, loc,
1404                                 "Literal of type double cannot be implicitly converted to type `{0}'. Add suffix `{1}' to create a literal of this type",
1405                                 type, suffix);
1406                 }
1407
1408                 /// <summary>
1409                 ///   Performs the explicit numeric conversions
1410                 /// </summary>
1411                 public static Expression ExplicitNumericConversion (Expression expr, Type target_type)
1412                 {
1413                         Type expr_type = expr.Type;
1414                         Type real_target_type = target_type;
1415
1416                         if (expr_type == TypeManager.sbyte_type){
1417                                 //
1418                                 // From sbyte to byte, ushort, uint, ulong, char
1419                                 //
1420                                 if (real_target_type == TypeManager.byte_type)
1421                                         return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1);
1422                                 if (real_target_type == TypeManager.ushort_type)
1423                                         return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2);
1424                                 if (real_target_type == TypeManager.uint32_type)
1425                                         return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4);
1426                                 if (real_target_type == TypeManager.uint64_type)
1427                                         return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8);
1428                                 if (real_target_type == TypeManager.char_type)
1429                                         return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH);
1430                         } else if (expr_type == TypeManager.byte_type){
1431                                 //
1432                                 // From byte to sbyte and char
1433                                 //
1434                                 if (real_target_type == TypeManager.sbyte_type)
1435                                         return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1);
1436                                 if (real_target_type == TypeManager.char_type)
1437                                         return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH);
1438                         } else if (expr_type == TypeManager.short_type){
1439                                 //
1440                                 // From short to sbyte, byte, ushort, uint, ulong, char
1441                                 //
1442                                 if (real_target_type == TypeManager.sbyte_type)
1443                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1);
1444                                 if (real_target_type == TypeManager.byte_type)
1445                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1);
1446                                 if (real_target_type == TypeManager.ushort_type)
1447                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2);
1448                                 if (real_target_type == TypeManager.uint32_type)
1449                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4);
1450                                 if (real_target_type == TypeManager.uint64_type)
1451                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8);
1452                                 if (real_target_type == TypeManager.char_type)
1453                                         return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH);
1454                         } else if (expr_type == TypeManager.ushort_type){
1455                                 //
1456                                 // From ushort to sbyte, byte, short, char
1457                                 //
1458                                 if (real_target_type == TypeManager.sbyte_type)
1459                                         return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1);
1460                                 if (real_target_type == TypeManager.byte_type)
1461                                         return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1);
1462                                 if (real_target_type == TypeManager.short_type)
1463                                         return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2);
1464                                 if (real_target_type == TypeManager.char_type)
1465                                         return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH);
1466                         } else if (expr_type == TypeManager.int32_type){
1467                                 //
1468                                 // From int to sbyte, byte, short, ushort, uint, ulong, char
1469                                 //
1470                                 if (real_target_type == TypeManager.sbyte_type)
1471                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1);
1472                                 if (real_target_type == TypeManager.byte_type)
1473                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1);
1474                                 if (real_target_type == TypeManager.short_type)
1475                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2);
1476                                 if (real_target_type == TypeManager.ushort_type)
1477                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2);
1478                                 if (real_target_type == TypeManager.uint32_type)
1479                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4);
1480                                 if (real_target_type == TypeManager.uint64_type)
1481                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8);
1482                                 if (real_target_type == TypeManager.char_type)
1483                                         return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH);
1484                         } else if (expr_type == TypeManager.uint32_type){
1485                                 //
1486                                 // From uint to sbyte, byte, short, ushort, int, char
1487                                 //
1488                                 if (real_target_type == TypeManager.sbyte_type)
1489                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1);
1490                                 if (real_target_type == TypeManager.byte_type)
1491                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1);
1492                                 if (real_target_type == TypeManager.short_type)
1493                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2);
1494                                 if (real_target_type == TypeManager.ushort_type)
1495                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2);
1496                                 if (real_target_type == TypeManager.int32_type)
1497                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4);
1498                                 if (real_target_type == TypeManager.char_type)
1499                                         return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH);
1500                         } else if (expr_type == TypeManager.int64_type){
1501                                 //
1502                                 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1503                                 //
1504                                 if (real_target_type == TypeManager.sbyte_type)
1505                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1);
1506                                 if (real_target_type == TypeManager.byte_type)
1507                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1);
1508                                 if (real_target_type == TypeManager.short_type)
1509                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2);
1510                                 if (real_target_type == TypeManager.ushort_type)
1511                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2);
1512                                 if (real_target_type == TypeManager.int32_type)
1513                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4);
1514                                 if (real_target_type == TypeManager.uint32_type)
1515                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4);
1516                                 if (real_target_type == TypeManager.uint64_type)
1517                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8);
1518                                 if (real_target_type == TypeManager.char_type)
1519                                         return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH);
1520                         } else if (expr_type == TypeManager.uint64_type){
1521                                 //
1522                                 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1523                                 //
1524                                 if (real_target_type == TypeManager.sbyte_type)
1525                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1);
1526                                 if (real_target_type == TypeManager.byte_type)
1527                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1);
1528                                 if (real_target_type == TypeManager.short_type)
1529                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2);
1530                                 if (real_target_type == TypeManager.ushort_type)
1531                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2);
1532                                 if (real_target_type == TypeManager.int32_type)
1533                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4);
1534                                 if (real_target_type == TypeManager.uint32_type)
1535                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4);
1536                                 if (real_target_type == TypeManager.int64_type)
1537                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8);
1538                                 if (real_target_type == TypeManager.char_type)
1539                                         return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH);
1540                         } else if (expr_type == TypeManager.char_type){
1541                                 //
1542                                 // From char to sbyte, byte, short
1543                                 //
1544                                 if (real_target_type == TypeManager.sbyte_type)
1545                                         return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1);
1546                                 if (real_target_type == TypeManager.byte_type)
1547                                         return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1);
1548                                 if (real_target_type == TypeManager.short_type)
1549                                         return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2);
1550                         } else if (expr_type == TypeManager.float_type){
1551                                 //
1552                                 // From float to sbyte, byte, short,
1553                                 // ushort, int, uint, long, ulong, char
1554                                 // or decimal
1555                                 //
1556                                 if (real_target_type == TypeManager.sbyte_type)
1557                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1);
1558                                 if (real_target_type == TypeManager.byte_type)
1559                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1);
1560                                 if (real_target_type == TypeManager.short_type)
1561                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2);
1562                                 if (real_target_type == TypeManager.ushort_type)
1563                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2);
1564                                 if (real_target_type == TypeManager.int32_type)
1565                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4);
1566                                 if (real_target_type == TypeManager.uint32_type)
1567                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4);
1568                                 if (real_target_type == TypeManager.int64_type)
1569                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8);
1570                                 if (real_target_type == TypeManager.uint64_type)
1571                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8);
1572                                 if (real_target_type == TypeManager.char_type)
1573                                         return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH);
1574                                 if (real_target_type == TypeManager.decimal_type)
1575                                         return new CastToDecimal (expr, true);
1576                         } else if (expr_type == TypeManager.double_type){
1577                                 //
1578                                 // From double to sbyte, byte, short,
1579                                 // ushort, int, uint, long, ulong,
1580                                 // char, float or decimal
1581                                 //
1582                                 if (real_target_type == TypeManager.sbyte_type)
1583                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1);
1584                                 if (real_target_type == TypeManager.byte_type)
1585                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1);
1586                                 if (real_target_type == TypeManager.short_type)
1587                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2);
1588                                 if (real_target_type == TypeManager.ushort_type)
1589                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2);
1590                                 if (real_target_type == TypeManager.int32_type)
1591                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4);
1592                                 if (real_target_type == TypeManager.uint32_type)
1593                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4);
1594                                 if (real_target_type == TypeManager.int64_type)
1595                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8);
1596                                 if (real_target_type == TypeManager.uint64_type)
1597                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8);
1598                                 if (real_target_type == TypeManager.char_type)
1599                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH);
1600                                 if (real_target_type == TypeManager.float_type)
1601                                         return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4);
1602                                 if (real_target_type == TypeManager.decimal_type)
1603                                         return new CastToDecimal (expr, true);
1604                         } else if (expr_type == TypeManager.decimal_type) {
1605                                 return new CastFromDecimal (expr, target_type).Resolve ();
1606                         }
1607                         return null;
1608                 }
1609
1610                 /// <summary>
1611                 ///  Returns whether an explicit reference conversion can be performed
1612                 ///  from source_type to target_type
1613                 /// </summary>
1614                 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1615                 {
1616                         bool target_is_type_param = target_type.IsGenericParameter;
1617                         bool target_is_value_type = target_type.IsValueType;
1618                         
1619                         if (source_type == target_type)
1620                                 return true;
1621                         
1622                         //
1623                         // From generic parameter to any type
1624                         //
1625                         if (source_type.IsGenericParameter)
1626                                 return true;
1627
1628                         //
1629                         // From object to a generic parameter
1630                         //
1631                         if (source_type == TypeManager.object_type && target_is_type_param)
1632                                 return true;
1633
1634                         //
1635                         // From object to any reference type
1636                         //
1637                         if (source_type == TypeManager.object_type && !target_is_value_type)
1638                                 return true;
1639                                         
1640                         //
1641                         // From any class S to any class-type T, provided S is a base class of T
1642                         //
1643                         if (TypeManager.IsSubclassOf (target_type, source_type))
1644                                 return true;
1645
1646                         //
1647                         // From any interface type S to any interface T provided S is not derived from T
1648                         //
1649                         if (source_type.IsInterface && target_type.IsInterface){
1650                                 if (!TypeManager.IsSubclassOf (target_type, source_type))
1651                                         return true;
1652                         }
1653                             
1654                         //
1655                         // From any class type S to any interface T, provided S is not sealed
1656                         // and provided S does not implement T.
1657                         //
1658                         if (target_type.IsInterface && !source_type.IsSealed &&
1659                             !TypeManager.ImplementsInterface (source_type, target_type))
1660                                 return true;
1661
1662                         //
1663                         // From any interface-type S to to any class type T, provided T is not
1664                         // sealed, or provided T implements S.
1665                         //
1666                         if (source_type.IsInterface &&
1667                             (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
1668                                 return true;
1669                         
1670                         
1671                         // From an array type S with an element type Se to an array type T with an 
1672                         // element type Te provided all the following are true:
1673                         //     * S and T differe only in element type, in other words, S and T
1674                         //       have the same number of dimensions.
1675                         //     * Both Se and Te are reference types
1676                         //     * An explicit referenc conversions exist from Se to Te
1677                         //
1678                         if (source_type.IsArray && target_type.IsArray) {
1679                                 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1680                                         
1681                                         Type source_element_type = TypeManager.GetElementType (source_type);
1682                                         Type target_element_type = TypeManager.GetElementType (target_type);
1683
1684                                         if (source_element_type.IsGenericParameter ||
1685                                             (!source_element_type.IsValueType && !target_element_type.IsValueType))
1686                                                 if (ExplicitReferenceConversionExists (source_element_type,
1687                                                                                        target_element_type))
1688                                                         return true;
1689                                 }
1690                         }
1691                         
1692
1693                         // From System.Array to any array-type
1694                         if (source_type == TypeManager.array_type &&
1695                             target_type.IsArray){
1696                                 return true;
1697                         }
1698
1699                         //
1700                         // From System delegate to any delegate-type
1701                         //
1702                         if (source_type == TypeManager.delegate_type &&
1703                             TypeManager.IsDelegateType (target_type))
1704                                 return true;
1705
1706                         //
1707                         // From ICloneable to Array or Delegate types
1708                         //
1709                         if (source_type == TypeManager.icloneable_type &&
1710                             (target_type == TypeManager.array_type ||
1711                              target_type == TypeManager.delegate_type))
1712                                 return true;
1713                         
1714                         return false;
1715                 }
1716
1717                 /// <summary>
1718                 ///   Implements Explicit Reference conversions
1719                 /// </summary>
1720                 static Expression ExplicitReferenceConversion (Expression source, Type target_type)
1721                 {
1722                         Type source_type = source.Type;
1723                         bool target_is_type_param = target_type.IsGenericParameter;
1724                         bool target_is_value_type = target_type.IsValueType;
1725
1726                         //
1727                         // From object to a generic parameter
1728                         //
1729                         if (source_type == TypeManager.object_type && target_is_type_param)
1730                                 return new UnboxCast (source, target_type);
1731
1732                         //
1733                         // From object to any reference type
1734                         //
1735                         if (source_type == TypeManager.object_type && !target_is_value_type)
1736                                 return new ClassCast (source, target_type);
1737
1738                         //
1739                         // Unboxing conversion.
1740                         //
1741                         if (((source_type == TypeManager.enum_type &&
1742                                 !(source is EmptyCast)) ||
1743                                 source_type == TypeManager.value_type) && target_is_value_type)
1744                                 return new UnboxCast (source, target_type);
1745
1746                         //
1747                         // From any class S to any class-type T, provided S is a base class of T
1748                         //
1749                         if (TypeManager.IsSubclassOf (target_type, source_type))
1750                                 return new ClassCast (source, target_type);
1751
1752                         //
1753                         // From any interface type S to any interface T provided S is not derived from T
1754                         //
1755                         if (source_type.IsInterface && target_type.IsInterface){
1756                                 if (TypeManager.ImplementsInterface (source_type, target_type))
1757                                         return null;
1758                                 else
1759                                         return new ClassCast (source, target_type);
1760                         }
1761
1762                         //
1763                         // From any class type S to any interface T, provides S is not sealed
1764                         // and provided S does not implement T.
1765                         //
1766                         if (target_type.IsInterface && !source_type.IsSealed) {
1767                                 if (TypeManager.ImplementsInterface (source_type, target_type))
1768                                         return null;
1769                                 else
1770                                         return new ClassCast (source, target_type);
1771                                 
1772                         }
1773
1774                         //
1775                         // From any interface-type S to to any class type T, provided T is not
1776                         // sealed, or provided T implements S.
1777                         //
1778                         if (source_type.IsInterface) {
1779                                 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)) {
1780                                         if (target_type.IsClass)
1781                                                 return new ClassCast (source, target_type);
1782                                         else
1783                                                 return new UnboxCast (source, target_type);
1784                                 }
1785
1786                                 return null;
1787                         }
1788                         
1789                         // From an array type S with an element type Se to an array type T with an 
1790                         // element type Te provided all the following are true:
1791                         //     * S and T differe only in element type, in other words, S and T
1792                         //       have the same number of dimensions.
1793                         //     * Both Se and Te are reference types
1794                         //     * An explicit referenc conversions exist from Se to Te
1795                         //
1796                         if (source_type.IsArray && target_type.IsArray) {
1797                                 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1798                                         
1799                                         Type source_element_type = TypeManager.GetElementType (source_type);
1800                                         Type target_element_type = TypeManager.GetElementType (target_type);
1801                                         
1802                                         if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1803                                                 if (ExplicitReferenceConversionExists (source_element_type,
1804                                                                                        target_element_type))
1805                                                         return new ClassCast (source, target_type);
1806                                 }
1807                         }
1808                         
1809
1810                         // From System.Array to any array-type
1811                         if (source_type == TypeManager.array_type &&
1812                             target_type.IsArray) {
1813                                 return new ClassCast (source, target_type);
1814                         }
1815
1816                         //
1817                         // From System delegate to any delegate-type
1818                         //
1819                         if (source_type == TypeManager.delegate_type &&
1820                             TypeManager.IsDelegateType (target_type))
1821                                 return new ClassCast (source, target_type);
1822
1823                         //
1824                         // From ICloneable to Array or Delegate types
1825                         //
1826                         if (source_type == TypeManager.icloneable_type &&
1827                             (target_type == TypeManager.array_type ||
1828                              target_type == TypeManager.delegate_type))
1829                                 return new ClassCast (source, target_type);
1830                         
1831                         return null;
1832                 }
1833                 
1834                 /// <summary>
1835                 ///   Performs an explicit conversion of the expression `expr' whose
1836                 ///   type is expr.Type to `target_type'.
1837                 /// </summary>
1838                 static public Expression ExplicitConversionCore (EmitContext ec, Expression expr,
1839                                                              Type target_type, Location loc)
1840                 {
1841                         Type expr_type = expr.Type;
1842
1843                         // Explicit conversion includes implicit conversion and it used for enum underlying types too
1844                         Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
1845                         if (ne != null)
1846                                 return ne;
1847
1848                         //
1849                         // Unboxing conversions; only object types can be convertible to enum
1850                         //
1851                         if (expr_type == TypeManager.object_type && target_type.IsValueType || expr_type == TypeManager.enum_type)
1852                                 return new UnboxCast (expr, target_type);
1853
1854                         if (TypeManager.IsEnumType (expr_type)) {
1855                                 if (expr is EnumConstant)
1856                                         return ExplicitConversionCore (ec, ((EnumConstant) expr).Child, target_type, loc);
1857
1858                                 return ExplicitConversionCore (ec, new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)), target_type, loc);
1859                         }
1860
1861                         if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
1862                                 return new Nullable.LiftedConversion (
1863                                         expr, target_type, false, true, loc).Resolve (ec);
1864
1865                         if (TypeManager.IsEnumType (target_type))
1866                                 return new EmptyCast (ExplicitConversionCore (ec, expr, TypeManager.EnumToUnderlying (target_type), loc), target_type);
1867
1868                         ne = ExplicitNumericConversion (expr, target_type);
1869                         if (ne != null)
1870                                 return ne;
1871
1872                         //
1873                         // Skip the ExplicitReferenceConversion because we can not convert
1874                         // from Null to a ValueType, and ExplicitReference wont check against
1875                         // null literal explicitly
1876                         //
1877                         if (expr_type != TypeManager.null_type){
1878                                 ne = ExplicitReferenceConversion (expr, target_type);
1879                                 if (ne != null)
1880                                         return ne;
1881                         }
1882
1883                         if (ec.InUnsafe){
1884                                 ne = ExplicitUnsafe (expr, target_type);
1885                                 if (ne != null)
1886                                         return ne;
1887                         }
1888
1889                         ne = ExplicitUserConversion (ec, expr, target_type, loc);
1890                         if (ne != null)
1891                                 return ne;
1892
1893                         return null;
1894                 }
1895
1896                 public static Expression ExplicitUnsafe (Expression expr, Type target_type)
1897                 {
1898                         Type expr_type = expr.Type;
1899
1900                         if (target_type.IsPointer){
1901                                 if (expr_type.IsPointer)
1902                                         return new EmptyCast (expr, target_type);
1903                                         
1904                                 if (expr_type == TypeManager.sbyte_type ||
1905                                         expr_type == TypeManager.short_type ||
1906                                         expr_type == TypeManager.int32_type ||
1907                                         expr_type == TypeManager.int64_type)
1908                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I);
1909
1910                                 if (expr_type == TypeManager.ushort_type ||
1911                                         expr_type == TypeManager.uint32_type ||
1912                                         expr_type == TypeManager.uint64_type ||
1913                                         expr_type == TypeManager.byte_type)
1914                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
1915                         }
1916                         
1917                         if (expr_type.IsPointer){
1918                                 if (target_type == TypeManager.sbyte_type)
1919                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1920                                 else if (target_type == TypeManager.byte_type)
1921                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1922                                 else if (target_type == TypeManager.short_type)
1923                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1924                                 else if (target_type == TypeManager.ushort_type)
1925                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1926                                 else if (target_type == TypeManager.int32_type)
1927                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1928                                 else if (target_type == TypeManager.uint32_type)
1929                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1930                                 else if (target_type == TypeManager.uint64_type)
1931                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1932                                 else if (target_type == TypeManager.int64_type){
1933                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1934                                 }
1935                         }
1936                         return null;
1937                 }
1938
1939                 /// <summary>
1940                 ///   Same as ExplicitConversion, only it doesn't include user defined conversions
1941                 /// </summary>
1942                 static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
1943                                                                      Type target_type, Location l)
1944                 {
1945                         int errors = Report.Errors;
1946                         Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
1947                         if (Report.Errors > errors)
1948                                 return null;
1949
1950                         if (ne != null)
1951                                 return ne;
1952
1953                         if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type))
1954                                 return new Nullable.LiftedConversion (
1955                                         expr, target_type, false, true, l).Resolve (ec);
1956
1957                         ne = ExplicitNumericConversion (expr, target_type);
1958                         if (ne != null)
1959                                 return ne;
1960
1961                         ne = ExplicitReferenceConversion (expr, target_type);
1962                         if (ne != null)
1963                                 return ne;
1964
1965                         if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer)
1966                                 return new EmptyCast (expr, target_type);
1967
1968                         expr.Error_ValueCannotBeConverted (l, target_type, true);
1969                         return null;
1970                 }
1971
1972                 /// <summary>
1973                 ///   Performs an explicit conversion of the expression `expr' whose
1974                 ///   type is expr.Type to `target_type'.
1975                 /// </summary>
1976                 static public Expression ExplicitConversion (EmitContext ec, Expression expr,
1977                         Type target_type, Location loc)
1978                 {
1979                         Expression e = ExplicitConversionCore (ec, expr, target_type, loc);
1980                         if (e != null)
1981                                 return e;
1982
1983                         expr.Error_ValueCannotBeConverted (loc, target_type, true);
1984                         return null;
1985                 }
1986         }
1987 }