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