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