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