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