2004-03-30 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / gmcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
9 //
10 #define USE_OLD
11
12 namespace Mono.CSharp {
13         using System;
14         using System.Collections;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Text;
18
19         /// <summary>
20         ///   This is just a helper class, it is generated by Unary, UnaryMutator
21         ///   when an overloaded method has been found.  It just emits the code for a
22         ///   static call.
23         /// </summary>
24         public class StaticCallExpr : ExpressionStatement {
25                 ArrayList args;
26                 MethodInfo mi;
27
28                 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
29                 {
30                         mi = m;
31                         args = a;
32
33                         type = m.ReturnType;
34                         eclass = ExprClass.Value;
35                         loc = l;
36                 }
37
38                 public override Expression DoResolve (EmitContext ec)
39                 {
40                         //
41                         // We are born fully resolved
42                         //
43                         return this;
44                 }
45
46                 public override void Emit (EmitContext ec)
47                 {
48                         if (args != null) 
49                                 Invocation.EmitArguments (ec, mi, args);
50
51                         ec.ig.Emit (OpCodes.Call, mi);
52                         return;
53                 }
54                 
55                 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56                                                          Expression e, Location loc)
57                 {
58                         ArrayList args;
59                         MethodBase method;
60                         
61                         args = new ArrayList (1);
62                         Argument a = new Argument (e, Argument.AType.Expression);
63
64                         // We need to resolve the arguments before sending them in !
65                         if (!a.Resolve (ec, loc))
66                                 return null;
67
68                         args.Add (a);
69                         method = Invocation.OverloadResolve (
70                                 ec, (MethodGroupExpr) mg, args, false, loc);
71
72                         if (method == null)
73                                 return null;
74
75                         return new StaticCallExpr ((MethodInfo) method, args, loc);
76                 }
77
78                 public override void EmitStatement (EmitContext ec)
79                 {
80                         Emit (ec);
81                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
82                                 ec.ig.Emit (OpCodes.Pop);
83                 }
84         }
85
86         public class ParenthesizedExpression : Expression
87         {
88                 public Expression Expr;
89
90                 public ParenthesizedExpression (Expression expr, Location loc)
91                 {
92                         this.Expr = expr;
93                         this.loc = loc;
94                 }
95
96                 public override Expression DoResolve (EmitContext ec)
97                 {
98                         Expr = Expr.Resolve (ec);
99                         return Expr;
100                 }
101
102                 public override void Emit (EmitContext ec)
103                 {
104                         throw new Exception ("Should not happen");
105                 }
106         }
107         
108         /// <summary>
109         ///   Unary expressions.  
110         /// </summary>
111         ///
112         /// <remarks>
113         ///   Unary implements unary expressions.   It derives from
114         ///   ExpressionStatement becuase the pre/post increment/decrement
115         ///   operators can be used in a statement context.
116         /// </remarks>
117         public class Unary : Expression {
118                 public enum Operator : byte {
119                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
120                         Indirection, AddressOf,  TOP
121                 }
122
123                 public Operator Oper;
124                 public Expression Expr;
125                 
126                 public Unary (Operator op, Expression expr, Location loc)
127                 {
128                         this.Oper = op;
129                         this.Expr = expr;
130                         this.loc = loc;
131                 }
132
133                 /// <summary>
134                 ///   Returns a stringified representation of the Operator
135                 /// </summary>
136                 static public string OperName (Operator oper)
137                 {
138                         switch (oper){
139                         case Operator.UnaryPlus:
140                                 return "+";
141                         case Operator.UnaryNegation:
142                                 return "-";
143                         case Operator.LogicalNot:
144                                 return "!";
145                         case Operator.OnesComplement:
146                                 return "~";
147                         case Operator.AddressOf:
148                                 return "&";
149                         case Operator.Indirection:
150                                 return "*";
151                         }
152
153                         return oper.ToString ();
154                 }
155
156                 public static readonly string [] oper_names;
157
158                 static Unary ()
159                 {
160                         oper_names = new string [(int)Operator.TOP];
161
162                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
163                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
164                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
165                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
166                         oper_names [(int) Operator.Indirection] = "op_Indirection";
167                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
168                 }
169
170                 void Error23 (Type t)
171                 {
172                         Error (
173                                 23, "Operator " + OperName (Oper) +
174                                 " cannot be applied to operand of type `" +
175                                 TypeManager.CSharpName (t) + "'");
176                 }
177
178                 /// <remarks>
179                 ///   The result has been already resolved:
180                 ///
181                 ///   FIXME: a minus constant -128 sbyte cant be turned into a
182                 ///   constant byte.
183                 /// </remarks>
184                 static Expression TryReduceNegative (Constant expr)
185                 {
186                         Expression e = null;
187
188                         if (expr is IntConstant)
189                                 e = new IntConstant (-((IntConstant) expr).Value);
190                         else if (expr is UIntConstant){
191                                 uint value = ((UIntConstant) expr).Value;
192
193                                 if (value < 2147483649)
194                                         return new IntConstant (-(int)value);
195                                 else
196                                         e = new LongConstant (-value);
197                         }
198                         else if (expr is LongConstant)
199                                 e = new LongConstant (-((LongConstant) expr).Value);
200                         else if (expr is ULongConstant){
201                                 ulong value = ((ULongConstant) expr).Value;
202
203                                 if (value < 9223372036854775809)
204                                         return new LongConstant(-(long)value);
205                         }
206                         else if (expr is FloatConstant)
207                                 e = new FloatConstant (-((FloatConstant) expr).Value);
208                         else if (expr is DoubleConstant)
209                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);
210                         else if (expr is DecimalConstant)
211                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);
212                         else if (expr is ShortConstant)
213                                 e = new IntConstant (-((ShortConstant) expr).Value);
214                         else if (expr is UShortConstant)
215                                 e = new IntConstant (-((UShortConstant) expr).Value);
216                         return e;
217                 }
218
219                 // <summary>
220                 //   This routine will attempt to simplify the unary expression when the
221                 //   argument is a constant.  The result is returned in `result' and the
222                 //   function returns true or false depending on whether a reduction
223                 //   was performed or not
224                 // </summary>
225                 bool Reduce (EmitContext ec, Constant e, out Expression result)
226                 {
227                         Type expr_type = e.Type;
228                         
229                         switch (Oper){
230                         case Operator.UnaryPlus:
231                                 result = e;
232                                 return true;
233                                 
234                         case Operator.UnaryNegation:
235                                 result = TryReduceNegative (e);
236                                 return true;
237                                 
238                         case Operator.LogicalNot:
239                                 if (expr_type != TypeManager.bool_type) {
240                                         result = null;
241                                         Error23 (expr_type);
242                                         return false;
243                                 }
244                                 
245                                 BoolConstant b = (BoolConstant) e;
246                                 result = new BoolConstant (!(b.Value));
247                                 return true;
248                                 
249                         case Operator.OnesComplement:
250                                 if (!((expr_type == TypeManager.int32_type) ||
251                                       (expr_type == TypeManager.uint32_type) ||
252                                       (expr_type == TypeManager.int64_type) ||
253                                       (expr_type == TypeManager.uint64_type) ||
254                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
255
256                                         result = null;
257                                         if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
258                                                 result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
259                                                 result = result.Resolve (ec);
260                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
261                                                 result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
262                                                 result = result.Resolve (ec);
263                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
264                                                 result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
265                                                 result = result.Resolve (ec);
266                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
267                                                 result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
268                                                 result = result.Resolve (ec);
269                                         }
270
271                                         if (result == null || !(result is Constant)){
272                                                 result = null;
273                                                 Error23 (expr_type);
274                                                 return false;
275                                         }
276
277                                         expr_type = result.Type;
278                                         e = (Constant) result;
279                                 }
280
281                                 if (e is EnumConstant){
282                                         EnumConstant enum_constant = (EnumConstant) e;
283                                         Expression reduced;
284                                         
285                                         if (Reduce (ec, enum_constant.Child, out reduced)){
286                                                 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
287                                                 return true;
288                                         } else {
289                                                 result = null;
290                                                 return false;
291                                         }
292                                 }
293
294                                 if (expr_type == TypeManager.int32_type){
295                                         result = new IntConstant (~ ((IntConstant) e).Value);
296                                 } else if (expr_type == TypeManager.uint32_type){
297                                         result = new UIntConstant (~ ((UIntConstant) e).Value);
298                                 } else if (expr_type == TypeManager.int64_type){
299                                         result = new LongConstant (~ ((LongConstant) e).Value);
300                                 } else if (expr_type == TypeManager.uint64_type){
301                                         result = new ULongConstant (~ ((ULongConstant) e).Value);
302                                 } else {
303                                         result = null;
304                                         Error23 (expr_type);
305                                         return false;
306                                 }
307                                 return true;
308
309                         case Operator.AddressOf:
310                                 result = this;
311                                 return false;
312
313                         case Operator.Indirection:
314                                 result = this;
315                                 return false;
316                         }
317                         throw new Exception ("Can not constant fold: " + Oper.ToString());
318                 }
319
320                 Expression ResolveOperator (EmitContext ec)
321                 {
322                         Type expr_type = Expr.Type;
323
324                         //
325                         // Step 1: Perform Operator Overload location
326                         //
327                         Expression mg;
328                         string op_name;
329                         
330                         op_name = oper_names [(int) Oper];
331
332                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
333                         
334                         if (mg != null) {
335                                 Expression e = StaticCallExpr.MakeSimpleCall (
336                                         ec, (MethodGroupExpr) mg, Expr, loc);
337
338                                 if (e == null){
339                                         Error23 (expr_type);
340                                         return null;
341                                 }
342                                 
343                                 return e;
344                         }
345
346                         // Only perform numeric promotions on:
347                         // +, - 
348
349                         if (expr_type == null)
350                                 return null;
351                         
352                         //
353                         // Step 2: Default operations on CLI native types.
354                         //
355
356                         // Attempt to use a constant folding operation.
357                         if (Expr is Constant){
358                                 Expression result;
359                                 
360                                 if (Reduce (ec, (Constant) Expr, out result))
361                                         return result;
362                         }
363
364                         switch (Oper){
365                         case Operator.LogicalNot:
366                                 if (expr_type != TypeManager.bool_type) {
367                                         Expr = ResolveBoolean (ec, Expr, loc);
368                                         if (Expr == null){
369                                                 Error23 (expr_type);
370                                                 return null;
371                                         }
372                                 }
373                                 
374                                 type = TypeManager.bool_type;
375                                 return this;
376
377                         case Operator.OnesComplement:
378                                 if (!((expr_type == TypeManager.int32_type) ||
379                                       (expr_type == TypeManager.uint32_type) ||
380                                       (expr_type == TypeManager.int64_type) ||
381                                       (expr_type == TypeManager.uint64_type) ||
382                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
383                                         Expression e;
384
385                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
386                                         if (e != null){
387                                                 type = TypeManager.int32_type;
388                                                 return this;
389                                         }
390                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
391                                         if (e != null){
392                                                 type = TypeManager.uint32_type;
393                                                 return this;
394                                         }
395                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
396                                         if (e != null){
397                                                 type = TypeManager.int64_type;
398                                                 return this;
399                                         }
400                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
401                                         if (e != null){
402                                                 type = TypeManager.uint64_type;
403                                                 return this;
404                                         }
405                                         Error23 (expr_type);
406                                         return null;
407                                 }
408                                 type = expr_type;
409                                 return this;
410
411                         case Operator.AddressOf:
412                                 if (Expr.eclass != ExprClass.Variable){
413                                         Error (211, "Cannot take the address of non-variables");
414                                         return null;
415                                 }
416                                 
417                                 if (!ec.InUnsafe) {
418                                         UnsafeError (loc); 
419                                         return null;
420                                 }
421                                 
422                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
423                                         return null;
424                                 }
425
426                                 IVariable variable = Expr as IVariable;
427                                 if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
428                                         Error (212, "You can only take the address of an unfixed expression inside " +
429                                                "of a fixed statement initializer");
430                                         return null;
431                                 }
432
433                                 // According to the specs, a variable is considered definitely assigned if you take
434                                 // its address.
435                                 if ((variable != null) && (variable.VariableInfo != null))
436                                         variable.VariableInfo.SetAssigned (ec);
437
438                                 type = TypeManager.GetPointerType (Expr.Type);
439                                 return this;
440
441                         case Operator.Indirection:
442                                 if (!ec.InUnsafe){
443                                         UnsafeError (loc);
444                                         return null;
445                                 }
446                                 
447                                 if (!expr_type.IsPointer){
448                                         Error (193, "The * or -> operator can only be applied to pointers");
449                                         return null;
450                                 }
451                                 
452                                 //
453                                 // We create an Indirection expression, because
454                                 // it can implement the IMemoryLocation.
455                                 // 
456                                 return new Indirection (Expr, loc);
457                         
458                         case Operator.UnaryPlus:
459                                 //
460                                 // A plus in front of something is just a no-op, so return the child.
461                                 //
462                                 return Expr;
463
464                         case Operator.UnaryNegation:
465                                 //
466                                 // Deals with -literals
467                                 // int     operator- (int x)
468                                 // long    operator- (long x)
469                                 // float   operator- (float f)
470                                 // double  operator- (double d)
471                                 // decimal operator- (decimal d)
472                                 //
473                                 Expression expr = null;
474
475                                 //
476                                 // transform - - expr into expr
477                                 //
478                                 if (Expr is Unary){
479                                         Unary unary = (Unary) Expr;
480                                         
481                                         if (unary.Oper == Operator.UnaryNegation)
482                                                 return unary.Expr;
483                                 }
484
485                                 //
486                                 // perform numeric promotions to int,
487                                 // long, double.
488                                 //
489                                 //
490                                 // The following is inneficient, because we call
491                                 // ImplicitConversion too many times.
492                                 //
493                                 // It is also not clear if we should convert to Float
494                                 // or Double initially.
495                                 //
496                                 if (expr_type == TypeManager.uint32_type){
497                                         //
498                                         // FIXME: handle exception to this rule that
499                                         // permits the int value -2147483648 (-2^31) to
500                                         // bt wrote as a decimal interger literal
501                                         //
502                                         type = TypeManager.int64_type;
503                                         Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
504                                         return this;
505                                 }
506
507                                 if (expr_type == TypeManager.uint64_type){
508                                         //
509                                         // FIXME: Handle exception of `long value'
510                                         // -92233720368547758087 (-2^63) to be wrote as
511                                         // decimal integer literal.
512                                         //
513                                         Error23 (expr_type);
514                                         return null;
515                                 }
516
517                                 if (expr_type == TypeManager.float_type){
518                                         type = expr_type;
519                                         return this;
520                                 }
521                                 
522                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
523                                 if (expr != null){
524                                         Expr = expr;
525                                         type = expr.Type;
526                                         return this;
527                                 } 
528
529                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
530                                 if (expr != null){
531                                         Expr = expr;
532                                         type = expr.Type;
533                                         return this;
534                                 }
535
536                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
537                                 if (expr != null){
538                                         Expr = expr;
539                                         type = expr.Type;
540                                         return this;
541                                 }
542                                 
543                                 Error23 (expr_type);
544                                 return null;
545                         }
546
547                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
548                                TypeManager.CSharpName (expr_type) + "'");
549                         return null;
550                 }
551
552                 public override Expression DoResolve (EmitContext ec)
553                 {
554                         if (Oper == Operator.AddressOf)
555                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
556                         else
557                                 Expr = Expr.Resolve (ec);
558                         
559                         if (Expr == null)
560                                 return null;
561
562                         eclass = ExprClass.Value;
563                         return ResolveOperator (ec);
564                 }
565
566                 public override void Emit (EmitContext ec)
567                 {
568                         ILGenerator ig = ec.ig;
569                         
570                         switch (Oper) {
571                         case Operator.UnaryPlus:
572                                 throw new Exception ("This should be caught by Resolve");
573                                 
574                         case Operator.UnaryNegation:
575                                 if (ec.CheckState) {
576                                         ig.Emit (OpCodes.Ldc_I4_0);
577                                         if (type == TypeManager.int64_type)
578                                                 ig.Emit (OpCodes.Conv_U8);
579                                         Expr.Emit (ec);
580                                         ig.Emit (OpCodes.Sub_Ovf);
581                                 } else {
582                                 Expr.Emit (ec);
583                                 ig.Emit (OpCodes.Neg);
584                                 }
585                                 
586                                 break;
587                                 
588                         case Operator.LogicalNot:
589                                 Expr.Emit (ec);
590                                 ig.Emit (OpCodes.Ldc_I4_0);
591                                 ig.Emit (OpCodes.Ceq);
592                                 break;
593                                 
594                         case Operator.OnesComplement:
595                                 Expr.Emit (ec);
596                                 ig.Emit (OpCodes.Not);
597                                 break;
598                                 
599                         case Operator.AddressOf:
600                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
601                                 break;
602                                 
603                         default:
604                                 throw new Exception ("This should not happen: Operator = "
605                                                      + Oper.ToString ());
606                         }
607                 }
608
609                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
610                 {
611                         if (Oper == Operator.LogicalNot)
612                                 Expr.EmitBranchable (ec, target, !onTrue);
613                         else
614                                 base.EmitBranchable (ec, target, onTrue);
615                 }
616
617                 public override string ToString ()
618                 {
619                         return "Unary (" + Oper + ", " + Expr + ")";
620                 }
621                 
622         }
623
624         //
625         // Unary operators are turned into Indirection expressions
626         // after semantic analysis (this is so we can take the address
627         // of an indirection).
628         //
629         public class Indirection : Expression, IMemoryLocation, IAssignMethod {
630                 Expression expr;
631                 LocalTemporary temporary;
632                 bool have_temporary;
633                 
634                 public Indirection (Expression expr, Location l)
635                 {
636                         this.expr = expr;
637                         this.type = TypeManager.GetElementType (expr.Type);
638                         eclass = ExprClass.Variable;
639                         loc = l;
640                 }
641
642                 void LoadExprValue (EmitContext ec)
643                 {
644                 }
645                 
646                 public override void Emit (EmitContext ec)
647                 {
648                         ILGenerator ig = ec.ig;
649
650                         if (temporary != null){
651                                 if (have_temporary) {
652                                         temporary.Emit (ec);
653                                 } else {
654                                 expr.Emit (ec);
655                                 ec.ig.Emit (OpCodes.Dup);
656                                 temporary.Store (ec);
657                                 have_temporary = true;
658                                 }
659                         } else
660                                 expr.Emit (ec);
661                         
662                         LoadFromPtr (ig, Type);
663                 }
664
665                 public void EmitAssign (EmitContext ec, Expression source)
666                 {
667                         if (temporary != null){
668                                 if (have_temporary)
669                                         temporary.Emit (ec);
670                                 else {
671                                         expr.Emit (ec);
672                                         ec.ig.Emit (OpCodes.Dup);
673                                         temporary.Store (ec);
674                                         have_temporary = true;
675                                 }
676                         } else 
677                                 expr.Emit (ec);
678
679                         source.Emit (ec);
680                         StoreFromPtr (ec.ig, type);
681                 }
682                 
683                 public void AddressOf (EmitContext ec, AddressOp Mode)
684                 {
685                         if (temporary != null){
686                                 if (have_temporary){
687                                         temporary.Emit (ec);
688                                         return;
689                                 }
690                                 expr.Emit (ec);
691                                 ec.ig.Emit (OpCodes.Dup);
692                                 temporary.Store (ec);
693                                 have_temporary = true;
694                         } else
695                                 expr.Emit (ec);
696                 }
697
698                 public override Expression DoResolve (EmitContext ec)
699                 {
700                         //
701                         // Born fully resolved
702                         //
703                         return this;
704                 }
705
706                 public new void CacheTemporaries (EmitContext ec)
707                 {
708                         temporary = new LocalTemporary (ec, expr.Type);
709                 }
710
711                 public override string ToString ()
712                 {
713                         return "*(" + expr + ")";
714                 }
715         }
716         
717         /// <summary>
718         ///   Unary Mutator expressions (pre and post ++ and --)
719         /// </summary>
720         ///
721         /// <remarks>
722         ///   UnaryMutator implements ++ and -- expressions.   It derives from
723         ///   ExpressionStatement becuase the pre/post increment/decrement
724         ///   operators can be used in a statement context.
725         ///
726         /// FIXME: Idea, we could split this up in two classes, one simpler
727         /// for the common case, and one with the extra fields for more complex
728         /// classes (indexers require temporary access;  overloaded require method)
729         ///
730         /// </remarks>
731         public class UnaryMutator : ExpressionStatement {
732                 [Flags]
733                 public enum Mode : byte {
734                         IsIncrement    = 0,
735                         IsDecrement    = 1,
736                         IsPre          = 0,
737                         IsPost         = 2,
738                         
739                         PreIncrement   = 0,
740                         PreDecrement   = IsDecrement,
741                         PostIncrement  = IsPost,
742                         PostDecrement  = IsPost | IsDecrement
743                 }
744                 
745                 Mode mode;
746                 Expression expr;
747                 LocalTemporary temp_storage;
748
749                 //
750                 // This is expensive for the simplest case.
751                 //
752                 Expression method;
753                         
754                 public UnaryMutator (Mode m, Expression e, Location l)
755                 {
756                         mode = m;
757                         loc = l;
758                         expr = e;
759                 }
760
761                 static string OperName (Mode mode)
762                 {
763                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
764                                 "++" : "--";
765                 }
766                 
767                 void Error23 (Type t)
768                 {
769                         Error (
770                                 23, "Operator " + OperName (mode) + 
771                                 " cannot be applied to operand of type `" +
772                                 TypeManager.CSharpName (t) + "'");
773                 }
774
775                 /// <summary>
776                 ///   Returns whether an object of type `t' can be incremented
777                 ///   or decremented with add/sub (ie, basically whether we can
778                 ///   use pre-post incr-decr operations on it, but it is not a
779                 ///   System.Decimal, which we require operator overloading to catch)
780                 /// </summary>
781                 static bool IsIncrementableNumber (Type t)
782                 {
783                         return (t == TypeManager.sbyte_type) ||
784                                 (t == TypeManager.byte_type) ||
785                                 (t == TypeManager.short_type) ||
786                                 (t == TypeManager.ushort_type) ||
787                                 (t == TypeManager.int32_type) ||
788                                 (t == TypeManager.uint32_type) ||
789                                 (t == TypeManager.int64_type) ||
790                                 (t == TypeManager.uint64_type) ||
791                                 (t == TypeManager.char_type) ||
792                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
793                                 (t == TypeManager.float_type) ||
794                                 (t == TypeManager.double_type) ||
795                                 (t.IsPointer && t != TypeManager.void_ptr_type);
796                 }
797
798                 Expression ResolveOperator (EmitContext ec)
799                 {
800                         Type expr_type = expr.Type;
801
802                         //
803                         // Step 1: Perform Operator Overload location
804                         //
805                         Expression mg;
806                         string op_name;
807                         
808                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
809                                 op_name = "op_Increment";
810                         else 
811                                 op_name = "op_Decrement";
812
813                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
814
815                         if (mg == null && expr_type.BaseType != null)
816                                 mg = MemberLookup (ec, expr_type.BaseType, op_name,
817                                                    MemberTypes.Method, AllBindingFlags, loc);
818                         
819                         if (mg != null) {
820                                 method = StaticCallExpr.MakeSimpleCall (
821                                         ec, (MethodGroupExpr) mg, expr, loc);
822
823                                 type = method.Type;
824                                 return this;
825                         }
826
827                         //
828                         // The operand of the prefix/postfix increment decrement operators
829                         // should be an expression that is classified as a variable,
830                         // a property access or an indexer access
831                         //
832                         type = expr_type;
833                         if (expr.eclass == ExprClass.Variable){
834                                 LocalVariableReference var = expr as LocalVariableReference;
835                                 if ((var != null) && var.IsReadOnly)
836                                         Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
837                                 if (IsIncrementableNumber (expr_type) ||
838                                     expr_type == TypeManager.decimal_type){
839                                         return this;
840                                 }
841                         } else if (expr.eclass == ExprClass.IndexerAccess){
842                                 IndexerAccess ia = (IndexerAccess) expr;
843                                 
844                                 temp_storage = new LocalTemporary (ec, expr.Type);
845                                 
846                                 expr = ia.ResolveLValue (ec, temp_storage);
847                                 if (expr == null)
848                                         return null;
849
850                                 return this;
851                         } else if (expr.eclass == ExprClass.PropertyAccess){
852                                 PropertyExpr pe = (PropertyExpr) expr;
853
854                                 if (pe.VerifyAssignable ())
855                                         return this;
856
857                                 return null;
858                         } else {
859                                 expr.Error_UnexpectedKind ("variable, indexer or property access");
860                                 return null;
861                         }
862
863                         Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
864                                TypeManager.CSharpName (expr_type) + "'");
865                         return null;
866                 }
867
868                 public override Expression DoResolve (EmitContext ec)
869                 {
870                         expr = expr.Resolve (ec);
871                         
872                         if (expr == null)
873                                 return null;
874
875                         eclass = ExprClass.Value;
876                         return ResolveOperator (ec);
877                 }
878
879                 static int PtrTypeSize (Type t)
880                 {
881                         return GetTypeSize (TypeManager.GetElementType (t));
882                 }
883
884                 //
885                 // Loads the proper "1" into the stack based on the type, then it emits the
886                 // opcode for the operation requested
887                 //
888                 void LoadOneAndEmitOp (EmitContext ec, Type t)
889                 {
890                         //
891                         // Measure if getting the typecode and using that is more/less efficient
892                         // that comparing types.  t.GetTypeCode() is an internal call.
893                         //
894                         ILGenerator ig = ec.ig;
895                                                      
896                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
897                                 LongConstant.EmitLong (ig, 1);
898                         else if (t == TypeManager.double_type)
899                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
900                         else if (t == TypeManager.float_type)
901                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
902                         else if (t.IsPointer){
903                                 int n = PtrTypeSize (t);
904                                 
905                                 if (n == 0)
906                                         ig.Emit (OpCodes.Sizeof, t);
907                                 else
908                                         IntConstant.EmitInt (ig, n);
909                         } else 
910                                 ig.Emit (OpCodes.Ldc_I4_1);
911
912                         //
913                         // Now emit the operation
914                         //
915                         if (ec.CheckState){
916                                 if (t == TypeManager.int32_type ||
917                                     t == TypeManager.int64_type){
918                                         if ((mode & Mode.IsDecrement) != 0)
919                                                 ig.Emit (OpCodes.Sub_Ovf);
920                                         else
921                                                 ig.Emit (OpCodes.Add_Ovf);
922                                 } else if (t == TypeManager.uint32_type ||
923                                            t == TypeManager.uint64_type){
924                                         if ((mode & Mode.IsDecrement) != 0)
925                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
926                                         else
927                                                 ig.Emit (OpCodes.Add_Ovf_Un);
928                                 } else {
929                                         if ((mode & Mode.IsDecrement) != 0)
930                                                 ig.Emit (OpCodes.Sub_Ovf);
931                                         else
932                                                 ig.Emit (OpCodes.Add_Ovf);
933                                 }
934                         } else {
935                                 if ((mode & Mode.IsDecrement) != 0)
936                                         ig.Emit (OpCodes.Sub);
937                                 else
938                                         ig.Emit (OpCodes.Add);
939                         }
940
941                         if (t == TypeManager.sbyte_type){
942                                 if (ec.CheckState)
943                                         ig.Emit (OpCodes.Conv_Ovf_I1);
944                                 else
945                                         ig.Emit (OpCodes.Conv_I1);
946                         } else if (t == TypeManager.byte_type){
947                                 if (ec.CheckState)
948                                         ig.Emit (OpCodes.Conv_Ovf_U1);
949                                 else
950                                         ig.Emit (OpCodes.Conv_U1);
951                         } else if (t == TypeManager.short_type){
952                                 if (ec.CheckState)
953                                         ig.Emit (OpCodes.Conv_Ovf_I2);
954                                 else
955                                         ig.Emit (OpCodes.Conv_I2);
956                         } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
957                                 if (ec.CheckState)
958                                         ig.Emit (OpCodes.Conv_Ovf_U2);
959                                 else
960                                         ig.Emit (OpCodes.Conv_U2);
961                         }
962                         
963                 }
964
965                 static EmptyExpression empty_expr;
966                 
967                 void EmitCode (EmitContext ec, bool is_expr)
968                 {
969                         ILGenerator ig = ec.ig;
970                         IAssignMethod ia = (IAssignMethod) expr;
971                         Type expr_type = expr.Type;
972
973                         ia.CacheTemporaries (ec);
974
975                         if (temp_storage == null){
976                                 //
977                                 // Temporary improvement: if we are dealing with something that does
978                                 // not require complicated instance setup, avoid using a temporary
979                                 //
980                                 // For now: only localvariables when not remapped
981                                 //
982
983                                 if (method == null &&
984                                     ((expr is LocalVariableReference) ||(expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic))){
985                                         if (empty_expr == null)
986                                                 empty_expr = new EmptyExpression ();
987                                         
988                                         switch (mode){
989                                         case Mode.PreIncrement:
990                                         case Mode.PreDecrement:
991                                                 expr.Emit (ec);
992                                         
993                                                 LoadOneAndEmitOp (ec, expr_type);
994                                                 if (is_expr)
995                                                         ig.Emit (OpCodes.Dup);
996                                                 ia.EmitAssign (ec, empty_expr);
997                                                 break;
998                                                 
999                                         case Mode.PostIncrement:
1000                                         case Mode.PostDecrement:
1001                                                 expr.Emit (ec);
1002                                                 if (is_expr)
1003                                                         ig.Emit (OpCodes.Dup);
1004                                                 
1005                                                 LoadOneAndEmitOp (ec, expr_type);
1006                                                 ia.EmitAssign (ec, empty_expr);
1007                                                 break;
1008                                         }
1009                                         return;
1010                                 }
1011                                 temp_storage = new LocalTemporary (ec, expr_type);
1012                         }
1013                         
1014                         switch (mode){
1015                         case Mode.PreIncrement:
1016                         case Mode.PreDecrement:
1017                                 if (method == null){
1018                                         expr.Emit (ec);
1019                                         
1020                                         LoadOneAndEmitOp (ec, expr_type);
1021                                 } else 
1022                                         method.Emit (ec);
1023                                 
1024                                 temp_storage.Store (ec);
1025                                 ia.EmitAssign (ec, temp_storage);
1026                                 if (is_expr)
1027                                         temp_storage.Emit (ec);
1028                                 break;
1029                                 
1030                         case Mode.PostIncrement:
1031                         case Mode.PostDecrement:
1032                                 if (is_expr)
1033                                         expr.Emit (ec);
1034                                 
1035                                 if (method == null){
1036                                         if (!is_expr)
1037                                                 expr.Emit (ec);
1038                                         else
1039                                                 ig.Emit (OpCodes.Dup);
1040                                         
1041                                         LoadOneAndEmitOp (ec, expr_type);
1042                                 } else {
1043                                         method.Emit (ec);
1044                                 }
1045                                 
1046                                 temp_storage.Store (ec);
1047                                 ia.EmitAssign (ec, temp_storage);
1048                                 break;
1049                         }
1050
1051                         temp_storage.Release (ec);
1052                 }
1053
1054                 public override void Emit (EmitContext ec)
1055                 {
1056                         EmitCode (ec, true);
1057                         
1058                 }
1059                 
1060                 public override void EmitStatement (EmitContext ec)
1061                 {
1062                         EmitCode (ec, false);
1063                 }
1064
1065         }
1066
1067         /// <summary>
1068         ///   Base class for the `Is' and `As' classes. 
1069         /// </summary>
1070         ///
1071         /// <remarks>
1072         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
1073         ///   size. 
1074         /// </remarks>
1075         public abstract class Probe : Expression {
1076                 public readonly Expression ProbeType;
1077                 protected Expression expr;
1078                 protected Type probe_type;
1079                 
1080                 public Probe (Expression expr, Expression probe_type, Location l)
1081                 {
1082                         ProbeType = probe_type;
1083                         loc = l;
1084                         this.expr = expr;
1085                 }
1086
1087                 public Expression Expr {
1088                         get {
1089                                 return expr;
1090                         }
1091                 }
1092
1093                 public override Expression DoResolve (EmitContext ec)
1094                 {
1095                         probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1096
1097                         if (probe_type == null)
1098                                 return null;
1099
1100                         expr = expr.Resolve (ec);
1101                         if (expr == null)
1102                                 return null;
1103                         
1104                         return this;
1105                 }
1106         }
1107
1108         /// <summary>
1109         ///   Implementation of the `is' operator.
1110         /// </summary>
1111         public class Is : Probe {
1112                 public Is (Expression expr, Expression probe_type, Location l)
1113                         : base (expr, probe_type, l)
1114                 {
1115                 }
1116
1117                 enum Action {
1118                         AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1119                 }
1120
1121                 Action action;
1122                 
1123                 public override void Emit (EmitContext ec)
1124                 {
1125                         ILGenerator ig = ec.ig;
1126
1127                         expr.Emit (ec);
1128
1129                         switch (action){
1130                         case Action.AlwaysFalse:
1131                                 ig.Emit (OpCodes.Pop);
1132                                 IntConstant.EmitInt (ig, 0);
1133                                 return;
1134                         case Action.AlwaysTrue:
1135                                 ig.Emit (OpCodes.Pop);
1136                                 IntConstant.EmitInt (ig, 1);
1137                                 return;
1138                         case Action.LeaveOnStack:
1139                                 // the `e != null' rule.
1140                                 ig.Emit (OpCodes.Ldnull);
1141                                 ig.Emit (OpCodes.Ceq);
1142                                 ig.Emit (OpCodes.Ldc_I4_0);
1143                                 ig.Emit (OpCodes.Ceq);
1144                                 return;
1145                         case Action.Probe:
1146                                 ig.Emit (OpCodes.Isinst, probe_type);
1147                                 ig.Emit (OpCodes.Ldnull);
1148                                 ig.Emit (OpCodes.Cgt_Un);
1149                                 return;
1150                         }
1151                         throw new Exception ("never reached");
1152                 }
1153
1154                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1155                 {
1156                         ILGenerator ig = ec.ig;
1157
1158                         switch (action){
1159                         case Action.AlwaysFalse:
1160                                 if (! onTrue)
1161                                         ig.Emit (OpCodes.Br, target);
1162                                 
1163                                 return;
1164                         case Action.AlwaysTrue:
1165                                 if (onTrue)
1166                                         ig.Emit (OpCodes.Br, target);
1167                                 
1168                                 return;
1169                         case Action.LeaveOnStack:
1170                                 // the `e != null' rule.
1171                                 expr.Emit (ec);
1172                                 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1173                                 return;
1174                         case Action.Probe:
1175                                 expr.Emit (ec);
1176                                 ig.Emit (OpCodes.Isinst, probe_type);
1177                                 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1178                                 return;
1179                         }
1180                         throw new Exception ("never reached");
1181                 }
1182
1183                 public override Expression DoResolve (EmitContext ec)
1184                 {
1185                         Expression e = base.DoResolve (ec);
1186
1187                         if ((e == null) || (expr == null))
1188                                 return null;
1189
1190                         Type etype = expr.Type;
1191                         bool warning_always_matches = false;
1192                         bool warning_never_matches = false;
1193
1194                         type = TypeManager.bool_type;
1195                         eclass = ExprClass.Value;
1196
1197                         //
1198                         // First case, if at compile time, there is an implicit conversion
1199                         // then e != null (objects) or true (value types)
1200                         //
1201                         e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1202                         if (e != null){
1203                                 expr = e;
1204                                 if (etype.IsValueType)
1205                                         action = Action.AlwaysTrue;
1206                                 else
1207                                         action = Action.LeaveOnStack;
1208
1209                                 warning_always_matches = true;
1210                         } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1211                                 //
1212                                 // Second case: explicit reference convresion
1213                                 //
1214                                 if (expr is NullLiteral)
1215                                         action = Action.AlwaysFalse;
1216                                 else
1217                                         action = Action.Probe;
1218                         } else {
1219                                 action = Action.AlwaysFalse;
1220                                 warning_never_matches = true;
1221                         }
1222                         
1223                         if (RootContext.WarningLevel >= 1){
1224                                 if (warning_always_matches)
1225                                         Warning (183, "The expression is always of type `" +
1226                                                  TypeManager.CSharpName (probe_type) + "'");
1227                                 else if (warning_never_matches){
1228                                         if (!(probe_type.IsInterface || expr.Type.IsInterface))
1229                                                 Warning (184,
1230                                                          "The expression is never of type `" +
1231                                                          TypeManager.CSharpName (probe_type) + "'");
1232                                 }
1233                         }
1234
1235                         return this;
1236                 }                               
1237         }
1238
1239         /// <summary>
1240         ///   Implementation of the `as' operator.
1241         /// </summary>
1242         public class As : Probe {
1243                 public As (Expression expr, Expression probe_type, Location l)
1244                         : base (expr, probe_type, l)
1245                 {
1246                 }
1247
1248                 bool do_isinst = false;
1249                 
1250                 public override void Emit (EmitContext ec)
1251                 {
1252                         ILGenerator ig = ec.ig;
1253
1254                         expr.Emit (ec);
1255
1256                         if (do_isinst)
1257                                 ig.Emit (OpCodes.Isinst, probe_type);
1258                 }
1259
1260                 static void Error_CannotConvertType (Type source, Type target, Location loc)
1261                 {
1262                         Report.Error (
1263                                 39, loc, "as operator can not convert from `" +
1264                                 TypeManager.CSharpName (source) + "' to `" +
1265                                 TypeManager.CSharpName (target) + "'");
1266                 }
1267                 
1268                 public override Expression DoResolve (EmitContext ec)
1269                 {
1270                         Expression e = base.DoResolve (ec);
1271
1272                         if (e == null)
1273                                 return null;
1274
1275                         type = probe_type;
1276                         eclass = ExprClass.Value;
1277                         Type etype = expr.Type;
1278
1279                         if (TypeManager.IsValueType (probe_type)){
1280                                 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1281                                               TypeManager.CSharpName (probe_type) + " is a value type)");
1282                                 return null;
1283                         
1284                         }
1285                         
1286                         e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
1287                         if (e != null){
1288                                 expr = e;
1289                                 do_isinst = false;
1290                                 return this;
1291                         }
1292
1293                         if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1294                                 do_isinst = true;
1295                                 return this;
1296                         }
1297
1298                         Error_CannotConvertType (etype, probe_type, loc);
1299                         return null;
1300                 }                               
1301         }
1302         
1303         /// <summary>
1304         ///   This represents a typecast in the source language.
1305         ///
1306         ///   FIXME: Cast expressions have an unusual set of parsing
1307         ///   rules, we need to figure those out.
1308         /// </summary>
1309         public class Cast : Expression {
1310                 Expression target_type;
1311                 Expression expr;
1312                         
1313                 public Cast (Expression cast_type, Expression expr, Location loc)
1314                 {
1315                         this.target_type = cast_type;
1316                         this.expr = expr;
1317                         this.loc = loc;
1318                 }
1319
1320                 public Expression TargetType {
1321                         get {
1322                                 return target_type;
1323                         }
1324                 }
1325
1326                 public Expression Expr {
1327                         get {
1328                                 return expr;
1329                         }
1330                         set {
1331                                 expr = value;
1332                         }
1333                 }
1334
1335                 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1336                 {
1337                         if (!ec.ConstantCheckState)
1338                                 return true;
1339
1340                         if ((value < min) || (value > max)) {
1341                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1342                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1343                                        "syntax to override)");
1344                                 return false;
1345                         }
1346
1347                         return true;
1348                 }
1349
1350                 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1351                 {
1352                         if (!ec.ConstantCheckState)
1353                                 return true;
1354
1355                         if (value > max) {
1356                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1357                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1358                                        "syntax to override)");
1359                                 return false;
1360                         }
1361
1362                         return true;
1363                 }
1364
1365                 bool CheckUnsigned (EmitContext ec, long value, Type type)
1366                 {
1367                         if (!ec.ConstantCheckState)
1368                                 return true;
1369
1370                         if (value < 0) {
1371                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1372                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1373                                        "syntax to override)");
1374                                 return false;
1375                         }
1376
1377                         return true;
1378                 }
1379
1380                 /// <summary>
1381                 ///   Attempts to do a compile-time folding of a constant cast.
1382                 /// </summary>
1383                 Expression TryReduce (EmitContext ec, Type target_type)
1384                 {
1385                         Expression real_expr = expr;
1386                         if (real_expr is EnumConstant)
1387                                 real_expr = ((EnumConstant) real_expr).Child;
1388                                 
1389                         if (real_expr is ByteConstant){
1390                                 byte v = ((ByteConstant) real_expr).Value;
1391         
1392                                 if (target_type == TypeManager.sbyte_type) {
1393                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1394                                                 return null;
1395                                         return new SByteConstant ((sbyte) v);
1396                                 }
1397                                 if (target_type == TypeManager.short_type)
1398                                         return new ShortConstant ((short) v);
1399                                 if (target_type == TypeManager.ushort_type)
1400                                         return new UShortConstant ((ushort) v);
1401                                 if (target_type == TypeManager.int32_type)
1402                                         return new IntConstant ((int) v);
1403                                 if (target_type == TypeManager.uint32_type)
1404                                         return new UIntConstant ((uint) v);
1405                                 if (target_type == TypeManager.int64_type)
1406                                         return new LongConstant ((long) v);
1407                                 if (target_type == TypeManager.uint64_type)
1408                                         return new ULongConstant ((ulong) v);
1409                                 if (target_type == TypeManager.float_type)
1410                                         return new FloatConstant ((float) v);
1411                                 if (target_type == TypeManager.double_type)
1412                                         return new DoubleConstant ((double) v);
1413                                 if (target_type == TypeManager.char_type)
1414                                         return new CharConstant ((char) v);
1415                                 if (target_type == TypeManager.decimal_type)
1416                                         return new DecimalConstant ((decimal) v);
1417                         }
1418                         if (real_expr is SByteConstant){
1419                                 sbyte v = ((SByteConstant) real_expr).Value;
1420         
1421                                 if (target_type == TypeManager.byte_type) {
1422                                         if (!CheckUnsigned (ec, v, target_type))
1423                                                 return null;
1424                                         return new ByteConstant ((byte) v);
1425                                 }
1426                                 if (target_type == TypeManager.short_type)
1427                                         return new ShortConstant ((short) v);
1428                                 if (target_type == TypeManager.ushort_type) {
1429                                         if (!CheckUnsigned (ec, v, target_type))
1430                                                 return null;
1431                                         return new UShortConstant ((ushort) v);
1432                                 } if (target_type == TypeManager.int32_type)
1433                                         return new IntConstant ((int) v);
1434                                 if (target_type == TypeManager.uint32_type) {
1435                                         if (!CheckUnsigned (ec, v, target_type))
1436                                                 return null;
1437                                         return new UIntConstant ((uint) v);
1438                                 } if (target_type == TypeManager.int64_type)
1439                                         return new LongConstant ((long) v);
1440                                 if (target_type == TypeManager.uint64_type) {
1441                                         if (!CheckUnsigned (ec, v, target_type))
1442                                                 return null;
1443                                         return new ULongConstant ((ulong) v);
1444                                 }
1445                                 if (target_type == TypeManager.float_type)
1446                                         return new FloatConstant ((float) v);
1447                                 if (target_type == TypeManager.double_type)
1448                                         return new DoubleConstant ((double) v);
1449                                 if (target_type == TypeManager.char_type) {
1450                                         if (!CheckUnsigned (ec, v, target_type))
1451                                                 return null;
1452                                         return new CharConstant ((char) v);
1453                                 }
1454                                 if (target_type == TypeManager.decimal_type)
1455                                         return new DecimalConstant ((decimal) v);
1456                         }
1457                         if (real_expr is ShortConstant){
1458                                 short v = ((ShortConstant) real_expr).Value;
1459         
1460                                 if (target_type == TypeManager.byte_type) {
1461                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1462                                                 return null;
1463                                         return new ByteConstant ((byte) v);
1464                                 }
1465                                 if (target_type == TypeManager.sbyte_type) {
1466                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1467                                                 return null;
1468                                         return new SByteConstant ((sbyte) v);
1469                                 }
1470                                 if (target_type == TypeManager.ushort_type) {
1471                                         if (!CheckUnsigned (ec, v, target_type))
1472                                                 return null;
1473                                         return new UShortConstant ((ushort) v);
1474                                 }
1475                                 if (target_type == TypeManager.int32_type)
1476                                         return new IntConstant ((int) v);
1477                                 if (target_type == TypeManager.uint32_type) {
1478                                         if (!CheckUnsigned (ec, v, target_type))
1479                                                 return null;
1480                                         return new UIntConstant ((uint) v);
1481                                 }
1482                                 if (target_type == TypeManager.int64_type)
1483                                         return new LongConstant ((long) v);
1484                                 if (target_type == TypeManager.uint64_type) {
1485                                         if (!CheckUnsigned (ec, v, target_type))
1486                                                 return null;
1487                                         return new ULongConstant ((ulong) v);
1488                                 }
1489                                 if (target_type == TypeManager.float_type)
1490                                         return new FloatConstant ((float) v);
1491                                 if (target_type == TypeManager.double_type)
1492                                         return new DoubleConstant ((double) v);
1493                                 if (target_type == TypeManager.char_type) {
1494                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1495                                                 return null;
1496                                         return new CharConstant ((char) v);
1497                                 }
1498                                 if (target_type == TypeManager.decimal_type)
1499                                         return new DecimalConstant ((decimal) v);
1500                         }
1501                         if (real_expr is UShortConstant){
1502                                 ushort v = ((UShortConstant) real_expr).Value;
1503         
1504                                 if (target_type == TypeManager.byte_type) {
1505                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1506                                                 return null;
1507                                         return new ByteConstant ((byte) v);
1508                                 }
1509                                 if (target_type == TypeManager.sbyte_type) {
1510                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1511                                                 return null;
1512                                         return new SByteConstant ((sbyte) v);
1513                                 }
1514                                 if (target_type == TypeManager.short_type) {
1515                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1516                                                 return null;
1517                                         return new ShortConstant ((short) v);
1518                                 }
1519                                 if (target_type == TypeManager.int32_type)
1520                                         return new IntConstant ((int) v);
1521                                 if (target_type == TypeManager.uint32_type)
1522                                         return new UIntConstant ((uint) v);
1523                                 if (target_type == TypeManager.int64_type)
1524                                         return new LongConstant ((long) v);
1525                                 if (target_type == TypeManager.uint64_type)
1526                                         return new ULongConstant ((ulong) v);
1527                                 if (target_type == TypeManager.float_type)
1528                                         return new FloatConstant ((float) v);
1529                                 if (target_type == TypeManager.double_type)
1530                                         return new DoubleConstant ((double) v);
1531                                 if (target_type == TypeManager.char_type) {
1532                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1533                                                 return null;
1534                                         return new CharConstant ((char) v);
1535                                 }
1536                                 if (target_type == TypeManager.decimal_type)
1537                                         return new DecimalConstant ((decimal) v);
1538                         }
1539                         if (real_expr is IntConstant){
1540                                 int v = ((IntConstant) real_expr).Value;
1541         
1542                                 if (target_type == TypeManager.byte_type) {
1543                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1544                                                 return null;
1545                                         return new ByteConstant ((byte) v);
1546                                 }
1547                                 if (target_type == TypeManager.sbyte_type) {
1548                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1549                                                 return null;
1550                                         return new SByteConstant ((sbyte) v);
1551                                 }
1552                                 if (target_type == TypeManager.short_type) {
1553                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1554                                                 return null;
1555                                         return new ShortConstant ((short) v);
1556                                 }
1557                                 if (target_type == TypeManager.ushort_type) {
1558                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1559                                                 return null;
1560                                         return new UShortConstant ((ushort) v);
1561                                 }
1562                                 if (target_type == TypeManager.uint32_type) {
1563                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1564                                                 return null;
1565                                         return new UIntConstant ((uint) v);
1566                                 }
1567                                 if (target_type == TypeManager.int64_type)
1568                                         return new LongConstant ((long) v);
1569                                 if (target_type == TypeManager.uint64_type) {
1570                                         if (!CheckUnsigned (ec, v, target_type))
1571                                                 return null;
1572                                         return new ULongConstant ((ulong) v);
1573                                 }
1574                                 if (target_type == TypeManager.float_type)
1575                                         return new FloatConstant ((float) v);
1576                                 if (target_type == TypeManager.double_type)
1577                                         return new DoubleConstant ((double) v);
1578                                 if (target_type == TypeManager.char_type) {
1579                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1580                                                 return null;
1581                                         return new CharConstant ((char) v);
1582                                 }
1583                                 if (target_type == TypeManager.decimal_type)
1584                                         return new DecimalConstant ((decimal) v);
1585                         }
1586                         if (real_expr is UIntConstant){
1587                                 uint v = ((UIntConstant) real_expr).Value;
1588         
1589                                 if (target_type == TypeManager.byte_type) {
1590                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1591                                                 return null;
1592                                         return new ByteConstant ((byte) v);
1593                                 }
1594                                 if (target_type == TypeManager.sbyte_type) {
1595                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1596                                                 return null;
1597                                         return new SByteConstant ((sbyte) v);
1598                                 }
1599                                 if (target_type == TypeManager.short_type) {
1600                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1601                                                 return null;
1602                                         return new ShortConstant ((short) v);
1603                                 }
1604                                 if (target_type == TypeManager.ushort_type) {
1605                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1606                                                 return null;
1607                                         return new UShortConstant ((ushort) v);
1608                                 }
1609                                 if (target_type == TypeManager.int32_type) {
1610                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1611                                                 return null;
1612                                         return new IntConstant ((int) v);
1613                                 }
1614                                 if (target_type == TypeManager.int64_type)
1615                                         return new LongConstant ((long) v);
1616                                 if (target_type == TypeManager.uint64_type)
1617                                         return new ULongConstant ((ulong) v);
1618                                 if (target_type == TypeManager.float_type)
1619                                         return new FloatConstant ((float) v);
1620                                 if (target_type == TypeManager.double_type)
1621                                         return new DoubleConstant ((double) v);
1622                                 if (target_type == TypeManager.char_type) {
1623                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1624                                                 return null;
1625                                         return new CharConstant ((char) v);
1626                                 }
1627                                 if (target_type == TypeManager.decimal_type)
1628                                         return new DecimalConstant ((decimal) v);
1629                         }
1630                         if (real_expr is LongConstant){
1631                                 long v = ((LongConstant) real_expr).Value;
1632         
1633                                 if (target_type == TypeManager.byte_type) {
1634                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1635                                                 return null;
1636                                         return new ByteConstant ((byte) v);
1637                                 }
1638                                 if (target_type == TypeManager.sbyte_type) {
1639                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1640                                                 return null;
1641                                         return new SByteConstant ((sbyte) v);
1642                                 }
1643                                 if (target_type == TypeManager.short_type) {
1644                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1645                                                 return null;
1646                                         return new ShortConstant ((short) v);
1647                                 }
1648                                 if (target_type == TypeManager.ushort_type) {
1649                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1650                                                 return null;
1651                                         return new UShortConstant ((ushort) v);
1652                                 }
1653                                 if (target_type == TypeManager.int32_type) {
1654                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1655                                                 return null;
1656                                         return new IntConstant ((int) v);
1657                                 }
1658                                 if (target_type == TypeManager.uint32_type) {
1659                                         if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1660                                                 return null;
1661                                         return new UIntConstant ((uint) v);
1662                                 }
1663                                 if (target_type == TypeManager.uint64_type) {
1664                                         if (!CheckUnsigned (ec, v, target_type))
1665                                                 return null;
1666                                         return new ULongConstant ((ulong) v);
1667                                 }
1668                                 if (target_type == TypeManager.float_type)
1669                                         return new FloatConstant ((float) v);
1670                                 if (target_type == TypeManager.double_type)
1671                                         return new DoubleConstant ((double) v);
1672                                 if (target_type == TypeManager.char_type) {
1673                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1674                                                 return null;
1675                                         return new CharConstant ((char) v);
1676                                 }
1677                                 if (target_type == TypeManager.decimal_type)
1678                                         return new DecimalConstant ((decimal) v);
1679                         }
1680                         if (real_expr is ULongConstant){
1681                                 ulong v = ((ULongConstant) real_expr).Value;
1682         
1683                                 if (target_type == TypeManager.byte_type) {
1684                                         if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1685                                                 return null;
1686                                         return new ByteConstant ((byte) v);
1687                                 }
1688                                 if (target_type == TypeManager.sbyte_type) {
1689                                         if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1690                                                 return null;
1691                                         return new SByteConstant ((sbyte) v);
1692                                 }
1693                                 if (target_type == TypeManager.short_type) {
1694                                         if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1695                                                 return null;
1696                                         return new ShortConstant ((short) v);
1697                                 }
1698                                 if (target_type == TypeManager.ushort_type) {
1699                                         if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1700                                                 return null;
1701                                         return new UShortConstant ((ushort) v);
1702                                 }
1703                                 if (target_type == TypeManager.int32_type) {
1704                                         if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1705                                                 return null;
1706                                         return new IntConstant ((int) v);
1707                                 }
1708                                 if (target_type == TypeManager.uint32_type) {
1709                                         if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1710                                                 return null;
1711                                         return new UIntConstant ((uint) v);
1712                                 }
1713                                 if (target_type == TypeManager.int64_type) {
1714                                         if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1715                                                 return null;
1716                                         return new LongConstant ((long) v);
1717                                 }
1718                                 if (target_type == TypeManager.float_type)
1719                                         return new FloatConstant ((float) v);
1720                                 if (target_type == TypeManager.double_type)
1721                                         return new DoubleConstant ((double) v);
1722                                 if (target_type == TypeManager.char_type) {
1723                                         if (!CheckRange (ec, v, target_type, Char.MaxValue))
1724                                                 return null;
1725                                         return new CharConstant ((char) v);
1726                                 }
1727                                 if (target_type == TypeManager.decimal_type)
1728                                         return new DecimalConstant ((decimal) v);
1729                         }
1730                         if (real_expr is FloatConstant){
1731                                 float v = ((FloatConstant) real_expr).Value;
1732         
1733                                 if (target_type == TypeManager.byte_type)
1734                                         return new ByteConstant ((byte) v);
1735                                 if (target_type == TypeManager.sbyte_type)
1736                                         return new SByteConstant ((sbyte) v);
1737                                 if (target_type == TypeManager.short_type)
1738                                         return new ShortConstant ((short) v);
1739                                 if (target_type == TypeManager.ushort_type)
1740                                         return new UShortConstant ((ushort) v);
1741                                 if (target_type == TypeManager.int32_type)
1742                                         return new IntConstant ((int) v);
1743                                 if (target_type == TypeManager.uint32_type)
1744                                         return new UIntConstant ((uint) v);
1745                                 if (target_type == TypeManager.int64_type)
1746                                         return new LongConstant ((long) v);
1747                                 if (target_type == TypeManager.uint64_type)
1748                                         return new ULongConstant ((ulong) v);
1749                                 if (target_type == TypeManager.double_type)
1750                                         return new DoubleConstant ((double) v);
1751                                 if (target_type == TypeManager.char_type)
1752                                         return new CharConstant ((char) v);
1753                                 if (target_type == TypeManager.decimal_type)
1754                                         return new DecimalConstant ((decimal) v);
1755                         }
1756                         if (real_expr is DoubleConstant){
1757                                 double v = ((DoubleConstant) real_expr).Value;
1758         
1759                                 if (target_type == TypeManager.byte_type){
1760                                         return new ByteConstant ((byte) v);
1761                                 } if (target_type == TypeManager.sbyte_type)
1762                                         return new SByteConstant ((sbyte) v);
1763                                 if (target_type == TypeManager.short_type)
1764                                         return new ShortConstant ((short) v);
1765                                 if (target_type == TypeManager.ushort_type)
1766                                         return new UShortConstant ((ushort) v);
1767                                 if (target_type == TypeManager.int32_type)
1768                                         return new IntConstant ((int) v);
1769                                 if (target_type == TypeManager.uint32_type)
1770                                         return new UIntConstant ((uint) v);
1771                                 if (target_type == TypeManager.int64_type)
1772                                         return new LongConstant ((long) v);
1773                                 if (target_type == TypeManager.uint64_type)
1774                                         return new ULongConstant ((ulong) v);
1775                                 if (target_type == TypeManager.float_type)
1776                                         return new FloatConstant ((float) v);
1777                                 if (target_type == TypeManager.char_type)
1778                                         return new CharConstant ((char) v);
1779                                 if (target_type == TypeManager.decimal_type)
1780                                         return new DecimalConstant ((decimal) v);
1781                         }
1782
1783                         if (real_expr is CharConstant){
1784                                 char v = ((CharConstant) real_expr).Value;
1785                                 
1786                                 if (target_type == TypeManager.byte_type) {
1787                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1788                                                 return null;
1789                                         return new ByteConstant ((byte) v);
1790                                 }
1791                                 if (target_type == TypeManager.sbyte_type) {
1792                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1793                                                 return null;
1794                                         return new SByteConstant ((sbyte) v);
1795                                 }
1796                                 if (target_type == TypeManager.short_type) {
1797                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1798                                                 return null;
1799                                         return new ShortConstant ((short) v);
1800                                 }
1801                                 if (target_type == TypeManager.int32_type)
1802                                         return new IntConstant ((int) v);
1803                                 if (target_type == TypeManager.uint32_type)
1804                                         return new UIntConstant ((uint) v);
1805                                 if (target_type == TypeManager.int64_type)
1806                                         return new LongConstant ((long) v);
1807                                 if (target_type == TypeManager.uint64_type)
1808                                         return new ULongConstant ((ulong) v);
1809                                 if (target_type == TypeManager.float_type)
1810                                         return new FloatConstant ((float) v);
1811                                 if (target_type == TypeManager.double_type)
1812                                         return new DoubleConstant ((double) v);
1813                                 if (target_type == TypeManager.char_type) {
1814                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1815                                                 return null;
1816                                         return new CharConstant ((char) v);
1817                                 }
1818                                 if (target_type == TypeManager.decimal_type)
1819                                         return new DecimalConstant ((decimal) v);
1820                         }
1821
1822                         return null;
1823                 }
1824                 
1825                 public override Expression DoResolve (EmitContext ec)
1826                 {
1827                         expr = expr.Resolve (ec);
1828                         if (expr == null)
1829                                 return null;
1830
1831                         type = ec.DeclSpace.ResolveType (target_type, false, Location);
1832                         
1833                         if (type == null)
1834                                 return null;
1835
1836                         eclass = ExprClass.Value;
1837
1838                         if (expr is Constant){
1839                                 Expression e = TryReduce (ec, type);
1840
1841                                 if (e != null)
1842                                         return e;
1843                         }
1844
1845                         expr = Convert.ExplicitConversion (ec, expr, type, loc);
1846                         return expr;
1847                 }
1848
1849                 public override void Emit (EmitContext ec)
1850                 {
1851                         //
1852                         // This one will never happen
1853                         //
1854                         throw new Exception ("Should not happen");
1855                 }
1856         }
1857
1858         /// <summary>
1859         ///   Binary operators
1860         /// </summary>
1861         public class Binary : Expression {
1862                 public enum Operator : byte {
1863                         Multiply, Division, Modulus,
1864                         Addition, Subtraction,
1865                         LeftShift, RightShift,
1866                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1867                         Equality, Inequality,
1868                         BitwiseAnd,
1869                         ExclusiveOr,
1870                         BitwiseOr,
1871                         LogicalAnd,
1872                         LogicalOr,
1873                         TOP
1874                 }
1875
1876                 Operator oper;
1877                 Expression left, right;
1878
1879                 // This must be kept in sync with Operator!!!
1880                 public static readonly string [] oper_names;
1881                 
1882                 static Binary ()
1883                 {
1884                         oper_names = new string [(int) Operator.TOP];
1885
1886                         oper_names [(int) Operator.Multiply] = "op_Multiply";
1887                         oper_names [(int) Operator.Division] = "op_Division";
1888                         oper_names [(int) Operator.Modulus] = "op_Modulus";
1889                         oper_names [(int) Operator.Addition] = "op_Addition";
1890                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1891                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1892                         oper_names [(int) Operator.RightShift] = "op_RightShift";
1893                         oper_names [(int) Operator.LessThan] = "op_LessThan";
1894                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1895                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1896                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1897                         oper_names [(int) Operator.Equality] = "op_Equality";
1898                         oper_names [(int) Operator.Inequality] = "op_Inequality";
1899                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1900                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1901                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1902                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1903                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1904                 }
1905
1906                 public Binary (Operator oper, Expression left, Expression right, Location loc)
1907                 {
1908                         this.oper = oper;
1909                         this.left = left;
1910                         this.right = right;
1911                         this.loc = loc;
1912                 }
1913
1914                 public Operator Oper {
1915                         get {
1916                                 return oper;
1917                         }
1918                         set {
1919                                 oper = value;
1920                         }
1921                 }
1922                 
1923                 public Expression Left {
1924                         get {
1925                                 return left;
1926                         }
1927                         set {
1928                                 left = value;
1929                         }
1930                 }
1931
1932                 public Expression Right {
1933                         get {
1934                                 return right;
1935                         }
1936                         set {
1937                                 right = value;
1938                         }
1939                 }
1940
1941
1942                 /// <summary>
1943                 ///   Returns a stringified representation of the Operator
1944                 /// </summary>
1945                 static string OperName (Operator oper)
1946                 {
1947                         switch (oper){
1948                         case Operator.Multiply:
1949                                 return "*";
1950                         case Operator.Division:
1951                                 return "/";
1952                         case Operator.Modulus:
1953                                 return "%";
1954                         case Operator.Addition:
1955                                 return "+";
1956                         case Operator.Subtraction:
1957                                 return "-";
1958                         case Operator.LeftShift:
1959                                 return "<<";
1960                         case Operator.RightShift:
1961                                 return ">>";
1962                         case Operator.LessThan:
1963                                 return "<";
1964                         case Operator.GreaterThan:
1965                                 return ">";
1966                         case Operator.LessThanOrEqual:
1967                                 return "<=";
1968                         case Operator.GreaterThanOrEqual:
1969                                 return ">=";
1970                         case Operator.Equality:
1971                                 return "==";
1972                         case Operator.Inequality:
1973                                 return "!=";
1974                         case Operator.BitwiseAnd:
1975                                 return "&";
1976                         case Operator.BitwiseOr:
1977                                 return "|";
1978                         case Operator.ExclusiveOr:
1979                                 return "^";
1980                         case Operator.LogicalOr:
1981                                 return "||";
1982                         case Operator.LogicalAnd:
1983                                 return "&&";
1984                         }
1985
1986                         return oper.ToString ();
1987                 }
1988
1989                 public override string ToString ()
1990                 {
1991                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1992                                 right.ToString () + ")";
1993                 }
1994                 
1995                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1996                 {
1997                         if (expr.Type == target_type)
1998                                 return expr;
1999
2000                         return Convert.ImplicitConversion (ec, expr, target_type, loc);
2001                 }
2002
2003                 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
2004                 {
2005                         Report.Error (
2006                                 34, loc, "Operator `" + OperName (oper) 
2007                                 + "' is ambiguous on operands of type `"
2008                                 + TypeManager.CSharpName (l) + "' "
2009                                 + "and `" + TypeManager.CSharpName (r)
2010                                 + "'");
2011                 }
2012
2013                 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
2014                 {
2015                         if ((l == t) || (r == t))
2016                                 return true;
2017
2018                         if (!check_user_conversions)
2019                                 return false;
2020
2021                         if (Convert.ImplicitUserConversionExists (ec, l, t))
2022                                 return true;
2023                         else if (Convert.ImplicitUserConversionExists (ec, r, t))
2024                                 return true;
2025                         else
2026                                 return false;
2027                 }
2028
2029                 //
2030                 // Note that handling the case l == Decimal || r == Decimal
2031                 // is taken care of by the Step 1 Operator Overload resolution.
2032                 //
2033                 // If `check_user_conv' is true, we also check whether a user-defined conversion
2034                 // exists.  Note that we only need to do this if both arguments are of a user-defined
2035                 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
2036                 // so we don't explicitly check for performance reasons.
2037                 //
2038                 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
2039                 {
2040                         if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
2041                                 //
2042                                 // If either operand is of type double, the other operand is
2043                                 // conveted to type double.
2044                                 //
2045                                 if (r != TypeManager.double_type)
2046                                         right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
2047                                 if (l != TypeManager.double_type)
2048                                         left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
2049                                 
2050                                 type = TypeManager.double_type;
2051                         } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
2052                                 //
2053                                 // if either operand is of type float, the other operand is
2054                                 // converted to type float.
2055                                 //
2056                                 if (r != TypeManager.double_type)
2057                                         right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
2058                                 if (l != TypeManager.double_type)
2059                                         left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
2060                                 type = TypeManager.float_type;
2061                         } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2062                                 Expression e;
2063                                 Type other;
2064                                 //
2065                                 // If either operand is of type ulong, the other operand is
2066                                 // converted to type ulong.  or an error ocurrs if the other
2067                                 // operand is of type sbyte, short, int or long
2068                                 //
2069                                 if (l == TypeManager.uint64_type){
2070                                         if (r != TypeManager.uint64_type){
2071                                                 if (right is IntConstant){
2072                                                         IntConstant ic = (IntConstant) right;
2073                                                         
2074                                                         e = Convert.TryImplicitIntConversion (l, ic);
2075                                                         if (e != null)
2076                                                                 right = e;
2077                                                 } else if (right is LongConstant){
2078                                                         long ll = ((LongConstant) right).Value;
2079
2080                                                         if (ll > 0)
2081                                                                 right = new ULongConstant ((ulong) ll);
2082                                                 } else {
2083                                                         e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2084                                                         if (e != null)
2085                                                                 right = e;
2086                                                 }
2087                                         }
2088                                         other = right.Type;
2089                                 } else {
2090                                         if (left is IntConstant){
2091                                                 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2092                                                 if (e != null)
2093                                                         left = e;
2094                                         } else if (left is LongConstant){
2095                                                 long ll = ((LongConstant) left).Value;
2096                                                 
2097                                                 if (ll > 0)
2098                                                         left = new ULongConstant ((ulong) ll);
2099                                         } else {
2100                                                 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2101                                                 if (e != null)
2102                                                         left = e;
2103                                         }
2104                                         other = left.Type;
2105                                 }
2106
2107                                 if ((other == TypeManager.sbyte_type) ||
2108                                     (other == TypeManager.short_type) ||
2109                                     (other == TypeManager.int32_type) ||
2110                                     (other == TypeManager.int64_type))
2111                                         Error_OperatorAmbiguous (loc, oper, l, r);
2112                                 type = TypeManager.uint64_type;
2113                         } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2114                                 //
2115                                 // If either operand is of type long, the other operand is converted
2116                                 // to type long.
2117                                 //
2118                                 if (l != TypeManager.int64_type)
2119                                         left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2120                                 if (r != TypeManager.int64_type)
2121                                         right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2122                                 
2123                                 type = TypeManager.int64_type;
2124                         } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2125                                 //
2126                                 // If either operand is of type uint, and the other
2127                                 // operand is of type sbyte, short or int, othe operands are
2128                                 // converted to type long (unless we have an int constant).
2129                                 //
2130                                 Type other = null;
2131                                 
2132                                 if (l == TypeManager.uint32_type){
2133                                         if (right is IntConstant){
2134                                                 IntConstant ic = (IntConstant) right;
2135                                                 int val = ic.Value;
2136                                                 
2137                                                 if (val >= 0){
2138                                                         right = new UIntConstant ((uint) val);
2139                                                         type = l;
2140                                                         
2141                                                         return true;
2142                                                 }
2143                                         }
2144                                         other = r;
2145                                 } else if (r == TypeManager.uint32_type){
2146                                         if (left is IntConstant){
2147                                                 IntConstant ic = (IntConstant) left;
2148                                                 int val = ic.Value;
2149                                                 
2150                                                 if (val >= 0){
2151                                                         left = new UIntConstant ((uint) val);
2152                                                         type = r;
2153                                                         return true;
2154                                                 }
2155                                         }
2156                                         
2157                                         other = l;
2158                                 }
2159
2160                                 if ((other == TypeManager.sbyte_type) ||
2161                                     (other == TypeManager.short_type) ||
2162                                     (other == TypeManager.int32_type)){
2163                                         left = ForceConversion (ec, left, TypeManager.int64_type);
2164                                         right = ForceConversion (ec, right, TypeManager.int64_type);
2165                                         type = TypeManager.int64_type;
2166                                 } else {
2167                                         //
2168                                         // if either operand is of type uint, the other
2169                                         // operand is converd to type uint
2170                                         //
2171                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
2172                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
2173                                         type = TypeManager.uint32_type;
2174                                 } 
2175                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2176                                 if (l != TypeManager.decimal_type)
2177                                         left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2178
2179                                 if (r != TypeManager.decimal_type)
2180                                         right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2181                                 type = TypeManager.decimal_type;
2182                         } else {
2183                                 left = ForceConversion (ec, left, TypeManager.int32_type);
2184                                 right = ForceConversion (ec, right, TypeManager.int32_type);
2185
2186                                 type = TypeManager.int32_type;
2187                         }
2188
2189                         return (left != null) && (right != null);
2190                 }
2191
2192                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2193                 {
2194                         Report.Error (19, loc,
2195                                "Operator " + name + " cannot be applied to operands of type `" +
2196                                TypeManager.CSharpName (l) + "' and `" +
2197                                TypeManager.CSharpName (r) + "'");
2198                 }
2199                 
2200                 void Error_OperatorCannotBeApplied ()
2201                 {
2202                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2203                 }
2204
2205                 static bool is_unsigned (Type t)
2206                 {
2207                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2208                                 t == TypeManager.short_type || t == TypeManager.byte_type);
2209                 }
2210
2211                 static bool is_user_defined (Type t)
2212                 {
2213                         if (t.IsSubclassOf (TypeManager.value_type) &&
2214                             (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2215                                 return true;
2216                         else
2217                                 return false;
2218                 }
2219
2220                 Expression Make32or64 (EmitContext ec, Expression e)
2221                 {
2222                         Type t= e.Type;
2223                         
2224                         if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2225                             t == TypeManager.int64_type || t == TypeManager.uint64_type)
2226                                 return e;
2227                         Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
2228                         if (ee != null)
2229                                 return ee;
2230                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
2231                         if (ee != null)
2232                                 return ee;
2233                         ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
2234                         if (ee != null)
2235                                 return ee;
2236                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
2237                         if (ee != null)
2238                                 return ee;
2239                         return null;
2240                 }
2241                                         
2242                 Expression CheckShiftArguments (EmitContext ec)
2243                 {
2244                         Expression e;
2245
2246                         e = ForceConversion (ec, right, TypeManager.int32_type);
2247                         if (e == null){
2248                                 Error_OperatorCannotBeApplied ();
2249                                 return null;
2250                         }
2251                         right = e;
2252
2253                         if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2254                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2255                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2256                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2257                                 left = e;
2258                                 type = e.Type;
2259
2260                                 if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
2261                                         right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31), loc);
2262                                         right = right.DoResolve (ec);
2263                                 } else {
2264                                         right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc);
2265                                         right = right.DoResolve (ec);
2266                                 }
2267
2268                                 return this;
2269                         }
2270                         Error_OperatorCannotBeApplied ();
2271                         return null;
2272                 }
2273
2274                 Expression ResolveOperator (EmitContext ec)
2275                 {
2276                         Type l = left.Type;
2277                         Type r = right.Type;
2278
2279                         bool overload_failed = false;
2280
2281                         //
2282                         // Special cases: string comapred to null
2283                         //
2284                         if (oper == Operator.Equality || oper == Operator.Inequality){
2285                                 if ((l == TypeManager.string_type && (right is NullLiteral)) ||
2286                                     (r == TypeManager.string_type && (left is NullLiteral))){
2287                                         Type = TypeManager.bool_type;
2288                                         
2289                                         return this;
2290                                 }
2291                         }
2292
2293                         //
2294                         // Do not perform operator overload resolution when both sides are
2295                         // built-in types
2296                         //
2297                         if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
2298                                 //
2299                                 // Step 1: Perform Operator Overload location
2300                                 //
2301                                 Expression left_expr, right_expr;
2302                                 
2303                                 string op = oper_names [(int) oper];
2304                                 
2305                                 MethodGroupExpr union;
2306                                 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2307                                 if (r != l){
2308                                         right_expr = MemberLookup (
2309                                                 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2310                                         union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2311                                 } else
2312                                         union = (MethodGroupExpr) left_expr;
2313                                 
2314                                 if (union != null) {
2315                                         ArrayList args = new ArrayList (2);
2316                                         args.Add (new Argument (left, Argument.AType.Expression));
2317                                         args.Add (new Argument (right, Argument.AType.Expression));
2318                                         
2319                                         MethodBase method = Invocation.OverloadResolve (
2320                                                 ec, union, args, true, Location.Null);
2321
2322                                         if (method != null) {
2323                                                 MethodInfo mi = (MethodInfo) method;
2324                                                 
2325                                                 return new BinaryMethod (mi.ReturnType, method, args);
2326                                         } else {
2327                                                 overload_failed = true;
2328                                         }
2329                                 }
2330                         }
2331                         
2332                         //
2333                         // Step 0: String concatenation (because overloading will get this wrong)
2334                         //
2335                         if (oper == Operator.Addition){
2336                                 //
2337                                 // If any of the arguments is a string, cast to string
2338                                 //
2339                                 
2340                                 if (l == TypeManager.string_type){
2341                                         MethodBase method;
2342                                         
2343                                         if (r == TypeManager.void_type) {
2344                                                 Error_OperatorCannotBeApplied ();
2345                                                 return null;
2346                                         }
2347                                         
2348                                         if (r == TypeManager.string_type){
2349                                                 if (left is Constant && right is Constant){
2350                                                         StringConstant ls = (StringConstant) left;
2351                                                         StringConstant rs = (StringConstant) right;
2352                                                         
2353                                                         return new StringConstant (
2354                                                                 ls.Value + rs.Value);
2355                                                 }
2356
2357                                                 if (left is BinaryMethod){
2358                                                         BinaryMethod b = (BinaryMethod) left;
2359
2360                                                         //
2361                                                         // Call String.Concat (string, string, string) or
2362                                                         // String.Concat (string, string, string, string)
2363                                                         // if possible.
2364                                                         //
2365                                                         if (b.method == TypeManager.string_concat_string_string ||
2366                                                              b.method == TypeManager.string_concat_string_string_string){
2367                                                                 int count = b.Arguments.Count;
2368                                                                 
2369                                                                 if (count == 2){
2370                                                                         ArrayList bargs = new ArrayList (3);
2371                                                                         bargs.AddRange (b.Arguments);
2372                                                                         bargs.Add (new Argument (right, Argument.AType.Expression));
2373                                                                         return new BinaryMethod (
2374                                                                                 TypeManager.string_type,
2375                                                                                 TypeManager.string_concat_string_string_string, bargs);
2376                                                                 } else if (count == 3){
2377                                                                         ArrayList bargs = new ArrayList (4);
2378                                                                         bargs.AddRange (b.Arguments);
2379                                                                         bargs.Add (new Argument (right, Argument.AType.Expression));
2380                                                                         return new BinaryMethod (
2381                                                                                 TypeManager.string_type,
2382                                                                                 TypeManager.string_concat_string_string_string_string, bargs);
2383                                                                 }
2384                                                         }
2385                                                 }
2386
2387                                                 // string + string
2388                                                 method = TypeManager.string_concat_string_string;
2389                                         } else {
2390                                                 // string + object
2391                                                 method = TypeManager.string_concat_object_object;
2392                                                 right = Convert.ImplicitConversion (
2393                                                         ec, right, TypeManager.object_type, loc);
2394                                                 if (right == null){
2395                                                         Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2396                                                         return null;
2397                                                 }
2398                                         }
2399
2400                                         //
2401                                         // Cascading concats will hold up to 2 arguments, any extras will be
2402                                         // reallocated above.
2403                                         //
2404                                         ArrayList args = new ArrayList (2);
2405                                         args.Add (new Argument (left, Argument.AType.Expression));
2406                                         args.Add (new Argument (right, Argument.AType.Expression));
2407
2408                                         return new BinaryMethod (TypeManager.string_type, method, args);
2409                                 } else if (r == TypeManager.string_type){
2410                                         // object + string
2411
2412                                         if (l == TypeManager.void_type) {
2413                                                 Error_OperatorCannotBeApplied ();
2414                                                 return null;
2415                                         }
2416                                         
2417                                         left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc);
2418                                         if (left == null){
2419                                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2420                                                 return null;
2421                                         }
2422                                         ArrayList args = new ArrayList (2);
2423                                         args.Add (new Argument (left, Argument.AType.Expression));
2424                                         args.Add (new Argument (right, Argument.AType.Expression));
2425
2426                                         return new BinaryMethod (TypeManager.string_type, TypeManager.string_concat_object_object, args);
2427                                 }
2428
2429                                 //
2430                                 // Transform a + ( - b) into a - b
2431                                 //
2432                                 if (right is Unary){
2433                                         Unary right_unary = (Unary) right;
2434
2435                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
2436                                                 oper = Operator.Subtraction;
2437                                                 right = right_unary.Expr;
2438                                                 r = right.Type;
2439                                         }
2440                                 }
2441                         }
2442
2443                         if (oper == Operator.Equality || oper == Operator.Inequality){
2444                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2445                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2446                                                 Error_OperatorCannotBeApplied ();
2447                                                 return null;
2448                                         }
2449                                         
2450                                         type = TypeManager.bool_type;
2451                                         return this;
2452                                 }
2453
2454                                 //
2455                                 // operator != (object a, object b)
2456                                 // operator == (object a, object b)
2457                                 //
2458                                 // For this to be used, both arguments have to be reference-types.
2459                                 // Read the rationale on the spec (14.9.6)
2460                                 //
2461                                 // Also, if at compile time we know that the classes do not inherit
2462                                 // one from the other, then we catch the error there.
2463                                 //
2464                                 if (!(l.IsValueType || r.IsValueType)){
2465                                         type = TypeManager.bool_type;
2466
2467                                         if (l == r)
2468                                                 return this;
2469                                         
2470                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2471                                                 return this;
2472
2473                                         //
2474                                         // Also, a standard conversion must exist from either one
2475                                         //
2476                                         if (!(Convert.ImplicitStandardConversionExists (left, r) ||
2477                                               Convert.ImplicitStandardConversionExists (right, l))){
2478                                                 Error_OperatorCannotBeApplied ();
2479                                                 return null;
2480                                         }
2481                                         //
2482                                         // We are going to have to convert to an object to compare
2483                                         //
2484                                         if (l != TypeManager.object_type)
2485                                                 left = new EmptyCast (left, TypeManager.object_type);
2486                                         if (r != TypeManager.object_type)
2487                                                 right = new EmptyCast (right, TypeManager.object_type);
2488
2489                                         //
2490                                         // FIXME: CSC here catches errors cs254 and cs252
2491                                         //
2492                                         return this;
2493                                 }
2494
2495                                 //
2496                                 // One of them is a valuetype, but the other one is not.
2497                                 //
2498                                 if (!l.IsValueType || !r.IsValueType) {
2499                                         Error_OperatorCannotBeApplied ();
2500                                         return null;
2501                                 }
2502                         }
2503
2504                         // Only perform numeric promotions on:
2505                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2506                         //
2507                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2508                                 if (TypeManager.IsDelegateType (l)){
2509                                         if (right.eclass == ExprClass.MethodGroup && RootContext.V2){
2510                                                 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2511                                                 if (tmp == null)
2512                                                         return null;
2513                                                 right = tmp;
2514                                                 r = right.Type;
2515                                         }
2516                                 
2517                                         if (TypeManager.IsDelegateType (r)){
2518                                         MethodInfo method;
2519                                         ArrayList args = new ArrayList (2);
2520                                         
2521                                         args = new ArrayList (2);
2522                                         args.Add (new Argument (left, Argument.AType.Expression));
2523                                         args.Add (new Argument (right, Argument.AType.Expression));
2524                                         
2525                                         if (oper == Operator.Addition)
2526                                                 method = TypeManager.delegate_combine_delegate_delegate;
2527                                         else
2528                                                 method = TypeManager.delegate_remove_delegate_delegate;
2529
2530                                         if (l != r) {
2531                                                 Error_OperatorCannotBeApplied ();
2532                                                 return null;
2533                                         }
2534
2535                                         return new BinaryDelegate (l, method, args);
2536                                 }
2537                                 }
2538
2539                                 //
2540                                 // Pointer arithmetic:
2541                                 //
2542                                 // T* operator + (T* x, int y);
2543                                 // T* operator + (T* x, uint y);
2544                                 // T* operator + (T* x, long y);
2545                                 // T* operator + (T* x, ulong y);
2546                                 //
2547                                 // T* operator + (int y,   T* x);
2548                                 // T* operator + (uint y,  T *x);
2549                                 // T* operator + (long y,  T *x);
2550                                 // T* operator + (ulong y, T *x);
2551                                 //
2552                                 // T* operator - (T* x, int y);
2553                                 // T* operator - (T* x, uint y);
2554                                 // T* operator - (T* x, long y);
2555                                 // T* operator - (T* x, ulong y);
2556                                 //
2557                                 // long operator - (T* x, T *y)
2558                                 //
2559                                 if (l.IsPointer){
2560                                         if (r.IsPointer && oper == Operator.Subtraction){
2561                                                 if (r == l)
2562                                                         return new PointerArithmetic (
2563                                                                 false, left, right, TypeManager.int64_type,
2564                                                                 loc);
2565                                         } else {
2566                                                 Expression t = Make32or64 (ec, right);
2567                                                 if (t != null)
2568                                                         return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc);
2569                                         }
2570                                 } else if (r.IsPointer && oper == Operator.Addition){
2571                                         Expression t = Make32or64 (ec, left);
2572                                         if (t != null)
2573                                                 return new PointerArithmetic (true, right, t, r, loc);
2574                                 }
2575                         }
2576                         
2577                         //
2578                         // Enumeration operators
2579                         //
2580                         bool lie = TypeManager.IsEnumType (l);
2581                         bool rie = TypeManager.IsEnumType (r);
2582                         if (lie || rie){
2583                                 Expression temp;
2584
2585                                 // U operator - (E e, E f)
2586                                 if (lie && rie){
2587                                         if (oper == Operator.Subtraction){
2588                                         if (l == r){
2589                                                 type = TypeManager.EnumToUnderlying (l);
2590                                                 return this;
2591                                         } 
2592                                         Error_OperatorCannotBeApplied ();
2593                                         return null;
2594                                 }
2595                                 }
2596                                         
2597                                 //
2598                                 // operator + (E e, U x)
2599                                 // operator - (E e, U x)
2600                                 //
2601                                 if (oper == Operator.Addition || oper == Operator.Subtraction){
2602                                         Type enum_type = lie ? l : r;
2603                                         Type other_type = lie ? r : l;
2604                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2605                                         
2606                                         if (underlying_type != other_type){
2607                                                 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2608                                                 if (temp != null){
2609                                                         if (lie)
2610                                                                 right = temp;
2611                                                         else
2612                                                                 left = temp;
2613                                                         type = enum_type;
2614                                                         return this;
2615                                                 }
2616                                                         
2617                                                 Error_OperatorCannotBeApplied ();
2618                                                 return null;
2619                                         }
2620
2621                                         type = enum_type;
2622                                         return this;
2623                                 }
2624                                 
2625                                 if (!rie){
2626                                         temp = Convert.ImplicitConversion (ec, right, l, loc);
2627                                         if (temp != null)
2628                                                 right = temp;
2629                                         else {
2630                                                 Error_OperatorCannotBeApplied ();
2631                                                 return null;
2632                                         }
2633                                 } if (!lie){
2634                                         temp = Convert.ImplicitConversion (ec, left, r, loc);
2635                                         if (temp != null){
2636                                                 left = temp;
2637                                                 l = r;
2638                                         } else {
2639                                                 Error_OperatorCannotBeApplied ();
2640                                                 return null;
2641                                         }
2642                                 }
2643
2644                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2645                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2646                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2647                                         if (left.Type != right.Type){
2648                                                 Error_OperatorCannotBeApplied ();
2649                                                 return null;
2650                                         }
2651                                         type = TypeManager.bool_type;
2652                                         return this;
2653                                 }
2654
2655                                 if (oper == Operator.BitwiseAnd ||
2656                                     oper == Operator.BitwiseOr ||
2657                                     oper == Operator.ExclusiveOr){
2658                                         type = l;
2659                                         return this;
2660                                 }
2661                                 Error_OperatorCannotBeApplied ();
2662                                 return null;
2663                         }
2664                         
2665                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2666                                 return CheckShiftArguments (ec);
2667
2668                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2669                                 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2670                                         type = TypeManager.bool_type;
2671                                         return this;
2672                                 }
2673
2674                                 if (l != r) {
2675                                         Error_OperatorCannotBeApplied ();
2676                                         return null;
2677                                 }
2678
2679                                 Expression e = new ConditionalLogicalOperator (
2680                                         oper == Operator.LogicalAnd, left, right, l, loc);
2681                                 return e.Resolve (ec);
2682                         } 
2683
2684                         //
2685                         // operator & (bool x, bool y)
2686                         // operator | (bool x, bool y)
2687                         // operator ^ (bool x, bool y)
2688                         //
2689                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2690                                 if (oper == Operator.BitwiseAnd ||
2691                                     oper == Operator.BitwiseOr ||
2692                                     oper == Operator.ExclusiveOr){
2693                                         type = l;
2694                                         return this;
2695                                 }
2696                         }
2697                         
2698                         //
2699                         // Pointer comparison
2700                         //
2701                         if (l.IsPointer && r.IsPointer){
2702                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2703                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2704                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2705                                         type = TypeManager.bool_type;
2706                                         return this;
2707                                 }
2708                         }
2709                         
2710                         //
2711                         // We are dealing with numbers
2712                         //
2713                         if (overload_failed){
2714                                 Error_OperatorCannotBeApplied ();
2715                                 return null;
2716                         }
2717
2718                         //
2719                         // This will leave left or right set to null if there is an error
2720                         //
2721                         bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2722                         DoNumericPromotions (ec, l, r, check_user_conv);
2723                         if (left == null || right == null){
2724                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2725                                 return null;
2726                         }
2727
2728                         //
2729                         // reload our cached types if required
2730                         //
2731                         l = left.Type;
2732                         r = right.Type;
2733                         
2734                         if (oper == Operator.BitwiseAnd ||
2735                             oper == Operator.BitwiseOr ||
2736                             oper == Operator.ExclusiveOr){
2737                                 if (l == r){
2738                                         if (!((l == TypeManager.int32_type) ||
2739                                               (l == TypeManager.uint32_type) ||
2740                                               (l == TypeManager.short_type) ||
2741                                               (l == TypeManager.ushort_type) ||
2742                                               (l == TypeManager.int64_type) ||
2743                                               (l == TypeManager.uint64_type))){
2744                                                 type = l;
2745                                         }
2746                                 } else {
2747                                         Error_OperatorCannotBeApplied ();
2748                                         return null;
2749                                 }
2750                         }
2751
2752                         if (oper == Operator.Equality ||
2753                             oper == Operator.Inequality ||
2754                             oper == Operator.LessThanOrEqual ||
2755                             oper == Operator.LessThan ||
2756                             oper == Operator.GreaterThanOrEqual ||
2757                             oper == Operator.GreaterThan){
2758                                 type = TypeManager.bool_type;
2759                         }
2760
2761                         return this;
2762                 }
2763
2764                 public override Expression DoResolve (EmitContext ec)
2765                 {
2766                         if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2767                                 left = ((ParenthesizedExpression) left).Expr;
2768                                 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2769                                 if (left == null)
2770                                         return null;
2771
2772                                 if (left.eclass == ExprClass.Type) {
2773                                         Error (75, "Casting a negative value needs to have the value in parentheses.");
2774                                         return null;
2775                                 }
2776                         } else
2777                                 left = left.Resolve (ec);
2778                         right = right.Resolve (ec);
2779
2780                         if (left == null || right == null)
2781                                 return null;
2782
2783                         eclass = ExprClass.Value;
2784
2785                         Constant rc = right as Constant;
2786                         Constant lc = left as Constant;
2787
2788                         if (rc != null & lc != null){
2789                                 Expression e = ConstantFold.BinaryFold (
2790                                         ec, oper, lc, rc, loc);
2791                                         if (e != null)
2792                                                 return e;
2793                         }
2794
2795                         return ResolveOperator (ec);
2796                 }
2797
2798                 /// <remarks>
2799                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2800                 ///   context of a conditional bool expression.  This function will return
2801                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2802                 ///
2803                 ///   The expression's code is generated, and we will generate a branch to `target'
2804                 ///   if the resulting expression value is equal to isTrue
2805                 /// </remarks>
2806                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2807                 {
2808                         ILGenerator ig = ec.ig;
2809
2810                         //
2811                         // This is more complicated than it looks, but its just to avoid
2812                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2813                         // but on top of that we want for == and != to use a special path
2814                         // if we are comparing against null
2815                         //
2816                         if (oper == Operator.Equality || oper == Operator.Inequality) {
2817                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2818
2819                                 if (left is NullLiteral || left is IntConstant && ((IntConstant) left).Value == 0) {
2820                                         right.Emit (ec);
2821                                         if (my_on_true)
2822                                                 ig.Emit (OpCodes.Brtrue, target);
2823                                         else
2824                                                 ig.Emit (OpCodes.Brfalse, target);
2825                                         
2826                                         return;
2827                                 } else if (right is NullLiteral || right is IntConstant && ((IntConstant) right).Value == 0){
2828                                         left.Emit (ec);
2829                                         if (my_on_true)
2830                                                 ig.Emit (OpCodes.Brtrue, target);
2831                                         else
2832                                                 ig.Emit (OpCodes.Brfalse, target);
2833                                         
2834                                         return;
2835                                 } else if (left is BoolConstant){
2836                                         right.Emit (ec);
2837                                         if (my_on_true != ((BoolConstant) left).Value)
2838                                                 ig.Emit (OpCodes.Brtrue, target);
2839                                         else
2840                                                 ig.Emit (OpCodes.Brfalse, target);
2841                                         
2842                                         return;
2843                                 } else if (right is BoolConstant){
2844                                         left.Emit (ec);
2845                                         if (my_on_true != ((BoolConstant) right).Value)
2846                                                 ig.Emit (OpCodes.Brtrue, target);
2847                                         else
2848                                                 ig.Emit (OpCodes.Brfalse, target);
2849                                         
2850                                         return;
2851                                 }
2852
2853                         } else if (oper == Operator.LogicalAnd) {
2854
2855                                 if (onTrue) {
2856                                                 Label tests_end = ig.DefineLabel ();
2857                                                 
2858                                         left.EmitBranchable (ec, tests_end, false);
2859                                         right.EmitBranchable (ec, target, true);
2860                                                         ig.MarkLabel (tests_end);
2861                                         } else {
2862                                         left.EmitBranchable (ec, target, false);
2863                                         right.EmitBranchable (ec, target, false);
2864                                         }
2865
2866                                 return;
2867                                                                 
2868                         } else if (oper == Operator.LogicalOr){
2869                                 if (onTrue) {
2870                                         left.EmitBranchable (ec, target, true);
2871                                         right.EmitBranchable (ec, target, true);
2872                                                 
2873                                         } else {
2874                                                 Label tests_end = ig.DefineLabel ();
2875                                         left.EmitBranchable (ec, tests_end, true);
2876                                         right.EmitBranchable (ec, target, false);
2877                                         ig.MarkLabel (tests_end);
2878                                 }
2879                                                 
2880                                 return;
2881
2882                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
2883                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2884                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
2885                                 base.EmitBranchable (ec, target, onTrue);
2886                                 return;
2887                                 }
2888                                 
2889                         left.Emit (ec);
2890                         right.Emit (ec);
2891
2892                         Type t = left.Type;
2893                         bool isUnsigned = is_unsigned (t);
2894
2895                         switch (oper){
2896                         case Operator.Equality:
2897                                 if (onTrue)
2898                                         ig.Emit (OpCodes.Beq, target);
2899                                 else
2900                                         ig.Emit (OpCodes.Bne_Un, target);
2901                                 break;
2902
2903                         case Operator.Inequality:
2904                                 if (onTrue)
2905                                         ig.Emit (OpCodes.Bne_Un, target);
2906                                 else
2907                                         ig.Emit (OpCodes.Beq, target);
2908                                 break;
2909
2910                         case Operator.LessThan:
2911                                 if (onTrue)
2912                                         if (isUnsigned)
2913                                                 ig.Emit (OpCodes.Blt_Un, target);
2914                                         else
2915                                                 ig.Emit (OpCodes.Blt, target);
2916                                 else
2917                                         if (isUnsigned)
2918                                                 ig.Emit (OpCodes.Bge_Un, target);
2919                                         else
2920                                                 ig.Emit (OpCodes.Bge, target);
2921                                 break;
2922
2923                         case Operator.GreaterThan:
2924                                 if (onTrue)
2925                                         if (isUnsigned)
2926                                                 ig.Emit (OpCodes.Bgt_Un, target);
2927                                         else
2928                                                 ig.Emit (OpCodes.Bgt, target);
2929                                 else
2930                                         if (isUnsigned)
2931                                                 ig.Emit (OpCodes.Ble_Un, target);
2932                                         else
2933                                                 ig.Emit (OpCodes.Ble, target);
2934                                 break;
2935
2936                         case Operator.LessThanOrEqual:
2937                                 if (t == TypeManager.double_type || t == TypeManager.float_type)
2938                                         isUnsigned = true;
2939
2940                                 if (onTrue)
2941                                         if (isUnsigned)
2942                                                 ig.Emit (OpCodes.Ble_Un, target);
2943                                         else
2944                                                 ig.Emit (OpCodes.Ble, target);
2945                                 else
2946                                         if (isUnsigned)
2947                                                 ig.Emit (OpCodes.Bgt_Un, target);
2948                                         else
2949                                                 ig.Emit (OpCodes.Bgt, target);
2950                                 break;
2951
2952
2953                         case Operator.GreaterThanOrEqual:
2954                                 if (t == TypeManager.double_type || t == TypeManager.float_type)
2955                                         isUnsigned = true;
2956                                 if (onTrue)
2957                                         if (isUnsigned)
2958                                                 ig.Emit (OpCodes.Bge_Un, target);
2959                                         else
2960                                                 ig.Emit (OpCodes.Bge, target);
2961                                 else
2962                                         if (isUnsigned)
2963                                                 ig.Emit (OpCodes.Blt_Un, target);
2964                                         else
2965                                                 ig.Emit (OpCodes.Blt, target);
2966                                 break;
2967                         default:
2968                                 Console.WriteLine (oper);
2969                                 throw new Exception ("what is THAT");
2970                         }
2971                 }
2972                 
2973                 public override void Emit (EmitContext ec)
2974                 {
2975                         ILGenerator ig = ec.ig;
2976                         Type l = left.Type;
2977                         OpCode opcode;
2978
2979                         //
2980                         // Handle short-circuit operators differently
2981                         // than the rest
2982                         //
2983                         if (oper == Operator.LogicalAnd) {
2984                                 Label load_zero = ig.DefineLabel ();
2985                                 Label end = ig.DefineLabel ();
2986
2987                                 left.EmitBranchable (ec, load_zero, false);
2988                                                 right.Emit (ec);
2989                                                 ig.Emit (OpCodes.Br, end);
2990
2991                                 ig.MarkLabel (load_zero);
2992                                 ig.Emit (OpCodes.Ldc_I4_0);
2993                                 ig.MarkLabel (end);
2994                                 return;
2995                         } else if (oper == Operator.LogicalOr) {
2996                                 Label load_one = ig.DefineLabel ();
2997                                 Label end = ig.DefineLabel ();
2998                                 
2999                                 left.EmitBranchable (ec, load_one, true);
3000                                                 right.Emit (ec);
3001                                                 ig.Emit (OpCodes.Br, end);
3002
3003                                 ig.MarkLabel (load_one);
3004                                 ig.Emit (OpCodes.Ldc_I4_1);
3005                                 ig.MarkLabel (end);
3006                                 return;
3007                         }
3008                         
3009                         left.Emit (ec);
3010                         right.Emit (ec);
3011
3012                         bool isUnsigned = is_unsigned (left.Type);
3013                         
3014                         switch (oper){
3015                         case Operator.Multiply:
3016                                 if (ec.CheckState){
3017                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3018                                                 opcode = OpCodes.Mul_Ovf;
3019                                         else if (isUnsigned)
3020                                                 opcode = OpCodes.Mul_Ovf_Un;
3021                                         else
3022                                                 opcode = OpCodes.Mul;
3023                                 } else
3024                                         opcode = OpCodes.Mul;
3025
3026                                 break;
3027
3028                         case Operator.Division:
3029                                 if (isUnsigned)
3030                                         opcode = OpCodes.Div_Un;
3031                                 else
3032                                         opcode = OpCodes.Div;
3033                                 break;
3034
3035                         case Operator.Modulus:
3036                                 if (isUnsigned)
3037                                         opcode = OpCodes.Rem_Un;
3038                                 else
3039                                         opcode = OpCodes.Rem;
3040                                 break;
3041
3042                         case Operator.Addition:
3043                                 if (ec.CheckState){
3044                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3045                                                 opcode = OpCodes.Add_Ovf;
3046                                         else if (isUnsigned)
3047                                                 opcode = OpCodes.Add_Ovf_Un;
3048                                         else
3049                                                 opcode = OpCodes.Add;
3050                                 } else
3051                                         opcode = OpCodes.Add;
3052                                 break;
3053
3054                         case Operator.Subtraction:
3055                                 if (ec.CheckState){
3056                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3057                                                 opcode = OpCodes.Sub_Ovf;
3058                                         else if (isUnsigned)
3059                                                 opcode = OpCodes.Sub_Ovf_Un;
3060                                         else
3061                                                 opcode = OpCodes.Sub;
3062                                 } else
3063                                         opcode = OpCodes.Sub;
3064                                 break;
3065
3066                         case Operator.RightShift:
3067                                 if (isUnsigned)
3068                                         opcode = OpCodes.Shr_Un;
3069                                 else
3070                                         opcode = OpCodes.Shr;
3071                                 break;
3072                                 
3073                         case Operator.LeftShift:
3074                                 opcode = OpCodes.Shl;
3075                                 break;
3076
3077                         case Operator.Equality:
3078                                 opcode = OpCodes.Ceq;
3079                                 break;
3080
3081                         case Operator.Inequality:
3082                                 ig.Emit (OpCodes.Ceq);
3083                                 ig.Emit (OpCodes.Ldc_I4_0);
3084                                 
3085                                 opcode = OpCodes.Ceq;
3086                                 break;
3087
3088                         case Operator.LessThan:
3089                                 if (isUnsigned)
3090                                         opcode = OpCodes.Clt_Un;
3091                                 else
3092                                         opcode = OpCodes.Clt;
3093                                 break;
3094
3095                         case Operator.GreaterThan:
3096                                 if (isUnsigned)
3097                                         opcode = OpCodes.Cgt_Un;
3098                                 else
3099                                         opcode = OpCodes.Cgt;
3100                                 break;
3101
3102                         case Operator.LessThanOrEqual:
3103                                 Type lt = left.Type;
3104                                 
3105                                 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3106                                         ig.Emit (OpCodes.Cgt_Un);
3107                                 else
3108                                         ig.Emit (OpCodes.Cgt);
3109                                 ig.Emit (OpCodes.Ldc_I4_0);
3110                                 
3111                                 opcode = OpCodes.Ceq;
3112                                 break;
3113
3114                         case Operator.GreaterThanOrEqual:
3115                                 Type le = left.Type;
3116                                 
3117                                 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3118                                         ig.Emit (OpCodes.Clt_Un);
3119                                 else
3120                                         ig.Emit (OpCodes.Clt);
3121                                 
3122                                 ig.Emit (OpCodes.Ldc_I4_0);
3123                                 
3124                                 opcode = OpCodes.Ceq;
3125                                 break;
3126
3127                         case Operator.BitwiseOr:
3128                                 opcode = OpCodes.Or;
3129                                 break;
3130
3131                         case Operator.BitwiseAnd:
3132                                 opcode = OpCodes.And;
3133                                 break;
3134
3135                         case Operator.ExclusiveOr:
3136                                 opcode = OpCodes.Xor;
3137                                 break;
3138
3139                         default:
3140                                 throw new Exception ("This should not happen: Operator = "
3141                                                      + oper.ToString ());
3142                         }
3143
3144                         ig.Emit (opcode);
3145                 }
3146         }
3147
3148         //
3149         // Object created by Binary when the binary operator uses an method instead of being
3150         // a binary operation that maps to a CIL binary operation.
3151         //
3152         public class BinaryMethod : Expression {
3153                 public MethodBase method;
3154                 public ArrayList  Arguments;
3155                 
3156                 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3157                 {
3158                         method = m;
3159                         Arguments = args;
3160                         type = t;
3161                         eclass = ExprClass.Value;
3162                 }
3163
3164                 public override Expression DoResolve (EmitContext ec)
3165                 {
3166                         return this;
3167                 }
3168
3169                 public override void Emit (EmitContext ec)
3170                 {
3171                         ILGenerator ig = ec.ig;
3172                         
3173                         if (Arguments != null) 
3174                                 Invocation.EmitArguments (ec, method, Arguments);
3175                         
3176                         if (method is MethodInfo)
3177                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
3178                         else
3179                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3180                 }
3181         }
3182
3183         //
3184         // Object created with +/= on delegates
3185         //
3186         public class BinaryDelegate : Expression {
3187                 MethodInfo method;
3188                 ArrayList  args;
3189
3190                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3191                 {
3192                         method = mi;
3193                         this.args = args;
3194                         type = t;
3195                         eclass = ExprClass.Value;
3196                 }
3197
3198                 public override Expression DoResolve (EmitContext ec)
3199                 {
3200                         return this;
3201                 }
3202
3203                 public override void Emit (EmitContext ec)
3204                 {
3205                         ILGenerator ig = ec.ig;
3206                         
3207                         Invocation.EmitArguments (ec, method, args);
3208                         
3209                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3210                         ig.Emit (OpCodes.Castclass, type);
3211                 }
3212
3213                 public Expression Right {
3214                         get {
3215                                 Argument arg = (Argument) args [1];
3216                                 return arg.Expr;
3217                         }
3218                 }
3219
3220                 public bool IsAddition {
3221                         get {
3222                                 return method == TypeManager.delegate_combine_delegate_delegate;
3223                         }
3224                 }
3225         }
3226         
3227         //
3228         // User-defined conditional logical operator
3229         public class ConditionalLogicalOperator : Expression {
3230                 Expression left, right;
3231                 bool is_and;
3232
3233                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3234                 {
3235                         type = t;
3236                         eclass = ExprClass.Value;
3237                         this.loc = loc;
3238                         this.left = left;
3239                         this.right = right;
3240                         this.is_and = is_and;
3241                 }
3242
3243                 protected void Error19 ()
3244                 {
3245                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3246                 }
3247
3248                 protected void Error218 ()
3249                 {
3250                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3251                                "declarations of operator true and operator false");
3252                 }
3253
3254                 Expression op_true, op_false, op;
3255
3256                 public override Expression DoResolve (EmitContext ec)
3257                 {
3258                         MethodInfo method;
3259                         Expression operator_group;
3260
3261                         operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3262                         if (operator_group == null) {
3263                                 Error19 ();
3264                                 return null;
3265                         }
3266
3267                         ArrayList arguments = new ArrayList ();
3268                         arguments.Add (new Argument (left, Argument.AType.Expression));
3269                         arguments.Add (new Argument (right, Argument.AType.Expression));
3270                         method = Invocation.OverloadResolve (
3271                                 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3272                                 as MethodInfo;
3273                         if ((method == null) || (method.ReturnType != type)) {
3274                                 Error19 ();
3275                                 return null;
3276                         }
3277
3278                         op = new StaticCallExpr (method, arguments, loc);
3279
3280                         op_true = GetOperatorTrue (ec, left, loc);
3281                         op_false = GetOperatorFalse (ec, left, loc);
3282                         if ((op_true == null) || (op_false == null)) {
3283                                 Error218 ();
3284                                 return null;
3285                         }
3286
3287                         return this;
3288                 }
3289
3290                 public override void Emit (EmitContext ec)
3291                 {
3292                         ILGenerator ig = ec.ig;
3293                         Label false_target = ig.DefineLabel ();
3294                         Label end_target = ig.DefineLabel ();
3295
3296                         ig.Emit (OpCodes.Nop);
3297
3298                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3299                         left.Emit (ec);
3300                         ig.Emit (OpCodes.Br, end_target);
3301                         ig.MarkLabel (false_target);
3302                         op.Emit (ec);
3303                         ig.MarkLabel (end_target);
3304
3305                         ig.Emit (OpCodes.Nop);
3306                 }
3307         }
3308
3309         public class PointerArithmetic : Expression {
3310                 Expression left, right;
3311                 bool is_add;
3312
3313                 //
3314                 // We assume that `l' is always a pointer
3315                 //
3316                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3317                 {
3318                         type = t;
3319                         eclass = ExprClass.Variable;
3320                         this.loc = loc;
3321                         left = l;
3322                         right = r;
3323                         is_add = is_addition;
3324                 }
3325
3326                 public override Expression DoResolve (EmitContext ec)
3327                 {
3328                         //
3329                         // We are born fully resolved
3330                         //
3331                         return this;
3332                 }
3333
3334                 public override void Emit (EmitContext ec)
3335                 {
3336                         Type op_type = left.Type;
3337                         ILGenerator ig = ec.ig;
3338                         int size = GetTypeSize (TypeManager.GetElementType (op_type));
3339                         Type rtype = right.Type;
3340                         
3341                         if (rtype.IsPointer){
3342                                 //
3343                                 // handle (pointer - pointer)
3344                                 //
3345                                 left.Emit (ec);
3346                                 right.Emit (ec);
3347                                 ig.Emit (OpCodes.Sub);
3348
3349                                 if (size != 1){
3350                                         if (size == 0)
3351                                                 ig.Emit (OpCodes.Sizeof, op_type);
3352                                         else 
3353                                                 IntLiteral.EmitInt (ig, size);
3354                                         ig.Emit (OpCodes.Div);
3355                                 }
3356                                 ig.Emit (OpCodes.Conv_I8);
3357                         } else {
3358                                 //
3359                                 // handle + and - on (pointer op int)
3360                                 //
3361                                 left.Emit (ec);
3362                                 ig.Emit (OpCodes.Conv_I);
3363                                 right.Emit (ec);
3364                                 if (size != 1){
3365                                         if (size == 0)
3366                                                 ig.Emit (OpCodes.Sizeof, op_type);
3367                                         else 
3368                                                 IntLiteral.EmitInt (ig, size);
3369                                         if (rtype == TypeManager.int64_type)
3370                                                 ig.Emit (OpCodes.Conv_I8);
3371                                         else if (rtype == TypeManager.uint64_type)
3372                                                 ig.Emit (OpCodes.Conv_U8);
3373                                         ig.Emit (OpCodes.Mul);
3374                                         ig.Emit (OpCodes.Conv_I);
3375                                 }
3376                                 if (is_add)
3377                                         ig.Emit (OpCodes.Add);
3378                                 else
3379                                         ig.Emit (OpCodes.Sub);
3380                         }
3381                 }
3382         }
3383         
3384         /// <summary>
3385         ///   Implements the ternary conditional operator (?:)
3386         /// </summary>
3387         public class Conditional : Expression {
3388                 Expression expr, trueExpr, falseExpr;
3389                 
3390                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3391                 {
3392                         this.expr = expr;
3393                         this.trueExpr = trueExpr;
3394                         this.falseExpr = falseExpr;
3395                         this.loc = l;
3396                 }
3397
3398                 public Expression Expr {
3399                         get {
3400                                 return expr;
3401                         }
3402                 }
3403
3404                 public Expression TrueExpr {
3405                         get {
3406                                 return trueExpr;
3407                         }
3408                 }
3409
3410                 public Expression FalseExpr {
3411                         get {
3412                                 return falseExpr;
3413                         }
3414                 }
3415
3416                 public override Expression DoResolve (EmitContext ec)
3417                 {
3418                         expr = expr.Resolve (ec);
3419
3420                         if (expr == null)
3421                                 return null;
3422                         
3423                         if (expr.Type != TypeManager.bool_type){
3424                                 expr = Expression.ResolveBoolean (
3425                                         ec, expr, loc);
3426                                 
3427                                 if (expr == null)
3428                                         return null;
3429                         }
3430                         
3431                         trueExpr = trueExpr.Resolve (ec);
3432                         falseExpr = falseExpr.Resolve (ec);
3433
3434                         if (trueExpr == null || falseExpr == null)
3435                                 return null;
3436
3437                         eclass = ExprClass.Value;
3438                         if (trueExpr.Type == falseExpr.Type)
3439                                 type = trueExpr.Type;
3440                         else {
3441                                 Expression conv;
3442                                 Type true_type = trueExpr.Type;
3443                                 Type false_type = falseExpr.Type;
3444
3445                                 if (trueExpr is NullLiteral){
3446                                         type = false_type;
3447                                         return this;
3448                                 } else if (falseExpr is NullLiteral){
3449                                         type = true_type;
3450                                         return this;
3451                                 }
3452                                 
3453                                 //
3454                                 // First, if an implicit conversion exists from trueExpr
3455                                 // to falseExpr, then the result type is of type falseExpr.Type
3456                                 //
3457                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3458                                 if (conv != null){
3459                                         //
3460                                         // Check if both can convert implicitl to each other's type
3461                                         //
3462                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3463                                                 Error (172,
3464                                                        "Can not compute type of conditional expression " +
3465                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3466                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3467                                                        "' convert implicitly to each other");
3468                                                 return null;
3469                                         }
3470                                         type = false_type;
3471                                         trueExpr = conv;
3472                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3473                                         type = true_type;
3474                                         falseExpr = conv;
3475                                 } else {
3476                                         Error (173, "The type of the conditional expression can " +
3477                                                "not be computed because there is no implicit conversion" +
3478                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3479                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3480                                         return null;
3481                                 }
3482                         }
3483
3484                         if (expr is BoolConstant){
3485                                 BoolConstant bc = (BoolConstant) expr;
3486
3487                                 if (bc.Value)
3488                                         return trueExpr;
3489                                 else
3490                                         return falseExpr;
3491                         }
3492
3493                         return this;
3494                 }
3495
3496                 public override void Emit (EmitContext ec)
3497                 {
3498                         ILGenerator ig = ec.ig;
3499                         Label false_target = ig.DefineLabel ();
3500                         Label end_target = ig.DefineLabel ();
3501
3502                         expr.EmitBranchable (ec, false_target, false);
3503                         trueExpr.Emit (ec);
3504                         ig.Emit (OpCodes.Br, end_target);
3505                         ig.MarkLabel (false_target);
3506                         falseExpr.Emit (ec);
3507                         ig.MarkLabel (end_target);
3508                 }
3509
3510         }
3511
3512         /// <summary>
3513         ///   Local variables
3514         /// </summary>
3515         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3516                 public readonly string Name;
3517                 public readonly Block Block;
3518                 LocalInfo local_info;
3519                 bool is_readonly;
3520                 
3521                 public LocalVariableReference (Block block, string name, Location l)
3522                 {
3523                         Block = block;
3524                         Name = name;
3525                         loc = l;
3526                         eclass = ExprClass.Variable;
3527                 }
3528
3529                 // Setting `is_readonly' to false will allow you to create a writable
3530                 // reference to a read-only variable.  This is used by foreach and using.
3531                 public LocalVariableReference (Block block, string name, Location l,
3532                                                LocalInfo local_info, bool is_readonly)
3533                         : this (block, name, l)
3534                 {
3535                         this.local_info = local_info;
3536                         this.is_readonly = is_readonly;
3537                 }
3538
3539                 public VariableInfo VariableInfo {
3540                         get { return local_info.VariableInfo; }
3541                 }
3542
3543                 public bool IsReadOnly {
3544                         get {
3545                                 return is_readonly;
3546                         }
3547                 }
3548
3549                 protected void DoResolveBase (EmitContext ec)
3550                 {
3551                         if (local_info == null) {
3552                                 local_info = Block.GetLocalInfo (Name);
3553                                 is_readonly = local_info.ReadOnly;
3554                         }
3555
3556                         type = local_info.VariableType;
3557 #if false
3558                         if (ec.InAnonymousMethod)
3559                                 Block.LiftVariable (local_info);
3560 #endif
3561                 }
3562                 
3563                 protected Expression DoResolve (EmitContext ec, bool is_lvalue)
3564                 {
3565                         Expression e = Block.GetConstantExpression (Name);
3566                         if (e != null) {
3567                                 local_info.Used = true;
3568                                 eclass = ExprClass.Value;
3569                                 return e;
3570                         }
3571
3572                         VariableInfo variable_info = local_info.VariableInfo; 
3573                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3574                                 return null;
3575
3576                         if (!is_lvalue)
3577                                 local_info.Used = true;
3578
3579                         if (local_info.LocalBuilder == null)
3580                                 return ec.RemapLocal (local_info);
3581                         
3582                         return this;
3583                 }
3584
3585                 public override Expression DoResolve (EmitContext ec)
3586                 {
3587                         DoResolveBase (ec);
3588
3589                         return DoResolve (ec, false);
3590                 }
3591
3592                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3593                 {
3594                         DoResolveBase (ec);
3595
3596                         VariableInfo variable_info = local_info.VariableInfo; 
3597                         if (variable_info != null)
3598                                 variable_info.SetAssigned (ec);
3599
3600                         Expression e = DoResolve (ec, true);
3601
3602                         if (e == null)
3603                                 return null;
3604
3605                         if (is_readonly){
3606                                 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3607                                 return null;
3608                         }
3609
3610                         if (local_info.LocalBuilder == null)
3611                                 return ec.RemapLocalLValue (local_info, right_side);
3612                         
3613                         return this;
3614                 }
3615
3616                 public bool VerifyFixed (bool is_expression)
3617                 {
3618                         return !is_expression || local_info.IsFixed;
3619                 }
3620
3621                 public override void Emit (EmitContext ec)
3622                 {
3623                         ILGenerator ig = ec.ig;
3624
3625                         ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3626                 }
3627                 
3628                 public void EmitAssign (EmitContext ec, Expression source)
3629                 {
3630                         ILGenerator ig = ec.ig;
3631
3632                         source.Emit (ec);
3633                         ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3634                 }
3635                 
3636                 public void AddressOf (EmitContext ec, AddressOp mode)
3637                 {
3638                         ILGenerator ig = ec.ig;
3639                         
3640                         ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3641                 }
3642
3643                 public override string ToString ()
3644                 {
3645                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3646                 }
3647         }
3648
3649         /// <summary>
3650         ///   This represents a reference to a parameter in the intermediate
3651         ///   representation.
3652         /// </summary>
3653         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3654                 Parameters pars;
3655                 String name;
3656                 int idx;
3657                 Block block;
3658                 VariableInfo vi;
3659                 public Parameter.Modifier mod;
3660                 public bool is_ref, is_out;
3661                 
3662                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3663                 {
3664                         this.pars = pars;
3665                         this.block = block;
3666                         this.idx  = idx;
3667                         this.name = name;
3668                         this.loc = loc;
3669                         eclass = ExprClass.Variable;
3670                 }
3671
3672                 public VariableInfo VariableInfo {
3673                         get { return vi; }
3674                 }
3675
3676                 public bool VerifyFixed (bool is_expression)
3677                 {
3678                         return !is_expression || TypeManager.IsValueType (type);
3679                 }
3680
3681                 public bool IsAssigned (EmitContext ec, Location loc)
3682                 {
3683                         if (!ec.DoFlowAnalysis || !is_out ||
3684                             ec.CurrentBranching.IsAssigned (vi))
3685                                 return true;
3686
3687                         Report.Error (165, loc,
3688                                       "Use of unassigned parameter `" + name + "'");
3689                         return false;
3690                 }
3691
3692                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3693                 {
3694                         if (!ec.DoFlowAnalysis || !is_out ||
3695                             ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3696                                 return true;
3697
3698                         Report.Error (170, loc,
3699                                       "Use of possibly unassigned field `" + field_name + "'");
3700                         return false;
3701                 }
3702
3703                 public void SetAssigned (EmitContext ec)
3704                 {
3705                         if (is_out && ec.DoFlowAnalysis)
3706                                 ec.CurrentBranching.SetAssigned (vi);
3707                 }
3708
3709                 public void SetFieldAssigned (EmitContext ec, string field_name)
3710                 {
3711                         if (is_out && ec.DoFlowAnalysis)
3712                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3713                 }
3714
3715                 protected void DoResolveBase (EmitContext ec)
3716                 {
3717                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3718                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3719                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3720                         eclass = ExprClass.Variable;
3721
3722                         if (is_out)
3723                                 vi = block.ParameterMap [idx];
3724                 }
3725
3726                 //
3727                 // Notice that for ref/out parameters, the type exposed is not the
3728                 // same type exposed externally.
3729                 //
3730                 // for "ref int a":
3731                 //   externally we expose "int&"
3732                 //   here we expose       "int".
3733                 //
3734                 // We record this in "is_ref".  This means that the type system can treat
3735                 // the type as it is expected, but when we generate the code, we generate
3736                 // the alternate kind of code.
3737                 //
3738                 public override Expression DoResolve (EmitContext ec)
3739                 {
3740                         DoResolveBase (ec);
3741
3742                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3743                                 return null;
3744
3745                         if (ec.RemapToProxy)
3746                                 return ec.RemapParameter (idx);
3747                         
3748                         return this;
3749                 }
3750
3751                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3752                 {
3753                         DoResolveBase (ec);
3754
3755                         SetAssigned (ec);
3756
3757                         if (ec.RemapToProxy)
3758                                 return ec.RemapParameterLValue (idx, right_side);
3759                         
3760                         return this;
3761                 }
3762
3763                 static public void EmitLdArg (ILGenerator ig, int x)
3764                 {
3765                         if (x <= 255){
3766                                 switch (x){
3767                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3768                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3769                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3770                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3771                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3772                                 }
3773                         } else
3774                                 ig.Emit (OpCodes.Ldarg, x);
3775                 }
3776                 
3777                 //
3778                 // This method is used by parameters that are references, that are
3779                 // being passed as references:  we only want to pass the pointer (that
3780                 // is already stored in the parameter, not the address of the pointer,
3781                 // and not the value of the variable).
3782                 //
3783                 public void EmitLoad (EmitContext ec)
3784                 {
3785                         ILGenerator ig = ec.ig;
3786                         int arg_idx = idx;
3787
3788                         if (!ec.IsStatic)
3789                                 arg_idx++;
3790
3791                         EmitLdArg (ig, arg_idx);
3792                 }
3793                 
3794                 public override void Emit (EmitContext ec)
3795                 {
3796                         ILGenerator ig = ec.ig;
3797                         
3798                         int arg_idx = idx;
3799
3800                         if (!ec.IsStatic)
3801                                 arg_idx++;
3802
3803                         EmitLdArg (ig, arg_idx);
3804
3805                         if (!is_ref)
3806                                 return;
3807
3808                         //
3809                         // If we are a reference, we loaded on the stack a pointer
3810                         // Now lets load the real value
3811                         //
3812                         LoadFromPtr (ig, type);
3813                 }
3814
3815                 public void EmitAssign (EmitContext ec, Expression source)
3816                 {
3817                         ILGenerator ig = ec.ig;
3818                         
3819                         int arg_idx = idx;
3820
3821                         if (!ec.IsStatic)
3822                                 arg_idx++;
3823
3824                         if (is_ref)
3825                                 EmitLdArg (ig, arg_idx);
3826                         
3827                         source.Emit (ec);
3828
3829                         if (is_ref)
3830                                 StoreFromPtr (ig, type);
3831                         else {
3832                                 if (arg_idx <= 255)
3833                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3834                                 else
3835                                         ig.Emit (OpCodes.Starg, arg_idx);
3836                         }
3837                 }
3838
3839                 public void AddressOf (EmitContext ec, AddressOp mode)
3840                 {
3841                         int arg_idx = idx;
3842
3843                         if (!ec.IsStatic)
3844                                 arg_idx++;
3845
3846                         if (is_ref){
3847                                 if (arg_idx <= 255)
3848                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3849                                 else
3850                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3851                         } else {
3852                                 if (arg_idx <= 255)
3853                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3854                                 else
3855                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3856                         }
3857                 }
3858
3859         }
3860         
3861         /// <summary>
3862         ///   Used for arguments to New(), Invocation()
3863         /// </summary>
3864         public class Argument {
3865                 public enum AType : byte {
3866                         Expression,
3867                         Ref,
3868                         Out
3869                 };
3870
3871                 public readonly AType ArgType;
3872                 public Expression Expr;
3873                 
3874                 public Argument (Expression expr, AType type)
3875                 {
3876                         this.Expr = expr;
3877                         this.ArgType = type;
3878                 }
3879
3880                 public Type Type {
3881                         get {
3882                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3883                                         return TypeManager.GetReferenceType (Expr.Type);
3884                                 else
3885                                         return Expr.Type;
3886                         }
3887                 }
3888
3889                 public Parameter.Modifier GetParameterModifier ()
3890                 {
3891                         switch (ArgType) {
3892                         case AType.Out:
3893                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
3894
3895                         case AType.Ref:
3896                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
3897
3898                         default:
3899                                 return Parameter.Modifier.NONE;
3900                         }
3901                 }
3902
3903                 public static string FullDesc (Argument a)
3904                 {
3905                         return (a.ArgType == AType.Ref ? "ref " :
3906                                 (a.ArgType == AType.Out ? "out " : "")) +
3907                                 TypeManager.CSharpName (a.Expr.Type);
3908                 }
3909
3910                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
3911                 {
3912                         ConstructedType ctype = Expr as ConstructedType;
3913                         if (ctype != null)
3914                                 Expr = ctype.GetMemberAccess (ec);
3915
3916                         // FIXME: csc doesn't report any error if you try to use `ref' or
3917                         //        `out' in a delegate creation expression.
3918                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3919                         if (Expr == null)
3920                                 return false;
3921
3922                         return true;
3923                 }
3924                 
3925                 public bool Resolve (EmitContext ec, Location loc)
3926                 {
3927                         if (ArgType == AType.Ref) {
3928                                 Expr = Expr.Resolve (ec);
3929                                 if (Expr == null)
3930                                         return false;
3931
3932                                 Expr = Expr.ResolveLValue (ec, Expr);
3933                         } else if (ArgType == AType.Out)
3934                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
3935                         else
3936                                 Expr = Expr.Resolve (ec);
3937
3938                         if (Expr == null)
3939                                 return false;
3940
3941                         if (ArgType == AType.Expression)
3942                                 return true;
3943
3944                         if (Expr.eclass != ExprClass.Variable){
3945                                 //
3946                                 // We just probe to match the CSC output
3947                                 //
3948                                 if (Expr.eclass == ExprClass.PropertyAccess ||
3949                                     Expr.eclass == ExprClass.IndexerAccess){
3950                                         Report.Error (
3951                                                 206, loc,
3952                                                 "A property or indexer can not be passed as an out or ref " +
3953                                                 "parameter");
3954                                 } else {
3955                                         Report.Error (
3956                                                 1510, loc,
3957                                                 "An lvalue is required as an argument to out or ref");
3958                                 }
3959                                 return false;
3960                         }
3961                                 
3962                         return true;
3963                 }
3964
3965                 public void Emit (EmitContext ec)
3966                 {
3967                         //
3968                         // Ref and Out parameters need to have their addresses taken.
3969                         //
3970                         // ParameterReferences might already be references, so we want
3971                         // to pass just the value
3972                         //
3973                         if (ArgType == AType.Ref || ArgType == AType.Out){
3974                                 AddressOp mode = AddressOp.Store;
3975
3976                                 if (ArgType == AType.Ref)
3977                                         mode |= AddressOp.Load;
3978                                 
3979                                 if (Expr is ParameterReference){
3980                                         ParameterReference pr = (ParameterReference) Expr;
3981
3982                                         if (pr.is_ref)
3983                                                 pr.EmitLoad (ec);
3984                                         else {
3985                                                 
3986                                                 pr.AddressOf (ec, mode);
3987                                         }
3988                                 } else
3989                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
3990                         } else
3991                                 Expr.Emit (ec);
3992                 }
3993         }
3994
3995         /// <summary>
3996         ///   Invocation of methods or delegates.
3997         /// </summary>
3998         public class Invocation : ExpressionStatement {
3999                 public readonly ArrayList Arguments;
4000
4001                 Expression expr;
4002                 MethodBase method = null;
4003                 bool is_base;
4004                 
4005                 static Hashtable method_parameter_cache;
4006
4007                 static Invocation ()
4008                 {
4009                         method_parameter_cache = new PtrHashtable ();
4010                 }
4011                         
4012                 //
4013                 // arguments is an ArrayList, but we do not want to typecast,
4014                 // as it might be null.
4015                 //
4016                 // FIXME: only allow expr to be a method invocation or a
4017                 // delegate invocation (7.5.5)
4018                 //
4019                 public Invocation (Expression expr, ArrayList arguments, Location l)
4020                 {
4021                         this.expr = expr;
4022                         Arguments = arguments;
4023                         loc = l;
4024                 }
4025
4026                 public Expression Expr {
4027                         get {
4028                                 return expr;
4029                         }
4030                 }
4031
4032                 /// <summary>
4033                 ///   Returns the Parameters (a ParameterData interface) for the
4034                 ///   Method `mb'
4035                 /// </summary>
4036                 public static ParameterData GetParameterData (MethodBase mb)
4037                 {
4038                         object pd = method_parameter_cache [mb];
4039                         object ip;
4040                         
4041                         if (pd != null)
4042                                 return (ParameterData) pd;
4043
4044                         ip = TypeManager.LookupParametersByBuilder (mb);
4045                         if (ip != null){
4046                                 method_parameter_cache [mb] = ip;
4047
4048                                 return (ParameterData) ip;
4049                         } else {
4050                                 ReflectionParameters rp = new ReflectionParameters (mb);
4051                                 method_parameter_cache [mb] = rp;
4052
4053                                 return (ParameterData) rp;
4054                         }
4055                 }
4056
4057                 /// <summary>
4058                 ///   Determines "better conversion" as specified in 7.4.2.3
4059                 ///
4060                 ///    Returns : 1 if a->p is better
4061                 ///              0 if a->q or neither is better 
4062                 /// </summary>
4063                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4064                 {
4065                         Type argument_type = a.Type;
4066                         Expression argument_expr = a.Expr;
4067
4068                         if (argument_type == null)
4069                                 throw new Exception ("Expression of type " + a.Expr +
4070                                                      " does not resolve its type");
4071
4072                         //
4073                         // This is a special case since csc behaves this way. I can't find
4074                         // it anywhere in the spec but oh well ...
4075                         //
4076                         if (argument_expr is NullLiteral &&
4077                             p == TypeManager.string_type &&
4078                             q == TypeManager.object_type)
4079                                 return 1;
4080                         else if (argument_expr is NullLiteral &&
4081                                  p == TypeManager.object_type &&
4082                                  q == TypeManager.string_type)
4083                                 return 0;
4084                         
4085                         if (p == q)
4086                                 return 0;
4087                         
4088                         if (argument_type == p)
4089                                 return 1;
4090
4091                         if (argument_type == q)
4092                                 return 0;
4093
4094                         //
4095                         // Now probe whether an implicit constant expression conversion
4096                         // can be used.
4097                         //
4098                         // An implicit constant expression conversion permits the following
4099                         // conversions:
4100                         //
4101                         //    * A constant-expression of type `int' can be converted to type
4102                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
4103                         //      of the expression is withing the range of the destination type.
4104                         //
4105                         //    * A constant-expression of type long can be converted to type
4106                         //      ulong, provided the value of the constant expression is not negative
4107                         //
4108                         // FIXME: Note that this assumes that constant folding has
4109                         // taken place.  We dont do constant folding yet.
4110                         //
4111
4112                         if (argument_expr is IntConstant){
4113                                 IntConstant ei = (IntConstant) argument_expr;
4114                                 int value = ei.Value;
4115
4116                                 if (p == TypeManager.sbyte_type){
4117                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
4118                                                 return 1;
4119                                 } else if (p == TypeManager.byte_type){
4120                                         if (q == TypeManager.sbyte_type &&
4121                                             value >= SByte.MinValue && value <= SByte.MaxValue)
4122                                                 return 0;
4123                                         else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
4124                                                 return 1;
4125                                 } else if (p == TypeManager.short_type){
4126                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
4127                                                 return 1;
4128                                 } else if (p == TypeManager.ushort_type){
4129                                         if (q == TypeManager.short_type &&
4130                                             value >= Int16.MinValue && value <= Int16.MaxValue)
4131                                                 return 0;
4132                                         else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
4133                                                 return 1;
4134                                 } else if (p == TypeManager.int32_type){
4135                                         if (value >= Int32.MinValue && value <= Int32.MaxValue)
4136                                                 return 1;
4137                                 } else if (p == TypeManager.uint32_type){
4138                                         //
4139                                         // we can optimize this case: a positive int32
4140                                         // always fits on a uint32
4141                                         //
4142                                         if (value >= 0)
4143                                                 return 1;
4144                                 } else if (p == TypeManager.uint64_type){
4145                                         //
4146                                         // we can optimize this case: a positive int32
4147                                         // always fits on a uint64
4148                                         //
4149
4150                                         //
4151                                         // This special case is needed because csc behaves like this.
4152                                         // int -> uint is better than int -> ulong!
4153                                         //
4154                                         if (q == TypeManager.uint32_type)
4155                                                 return 0;
4156                                         
4157                                         if (q == TypeManager.int64_type)
4158                                                 return 0;
4159                                         else if (value >= 0)
4160                                                 return 1;
4161                                 } else if (p == TypeManager.int64_type){
4162                                         return 1;
4163                                 }
4164                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
4165                                 LongConstant lc = (LongConstant) argument_expr;
4166                                 
4167                                 if (p == TypeManager.uint64_type){
4168                                         if (lc.Value > 0)
4169                                                 return 1;
4170                                 }
4171                         }
4172
4173                         if (q == null) {
4174                                 Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
4175                                 
4176                                 if (tmp != null)
4177                                         return 1;
4178                                 else
4179                                         return 0;
4180                         }
4181
4182                         Expression p_tmp = new EmptyExpression (p);
4183                         Expression q_tmp = new EmptyExpression (q);
4184                         
4185                         if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true &&
4186                             Convert.ImplicitConversionExists (ec, q_tmp, p) == false)
4187                                 return 1;
4188
4189                         if (p == TypeManager.sbyte_type)
4190                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4191                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4192                                         return 1;
4193
4194                         if (p == TypeManager.short_type)
4195                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4196                                     q == TypeManager.uint64_type)
4197                                         return 1;
4198
4199                         if (p == TypeManager.int32_type)
4200                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4201                                         return 1;
4202
4203                         if (p == TypeManager.int64_type)
4204                                 if (q == TypeManager.uint64_type)
4205                                         return 1;
4206
4207                         return 0;
4208                 }
4209                 
4210                 /// <summary>
4211                 ///   Determines "Better function" between candidate
4212                 ///   and the current best match
4213                 /// </summary>
4214                 /// <remarks>
4215                 ///    Returns an integer indicating :
4216                 ///     0 if candidate ain't better
4217                 ///     1 if candidate is better than the current best match
4218                 /// </remarks>
4219                 static int BetterFunction (EmitContext ec, ArrayList args,
4220                                            MethodBase candidate, bool candidate_params,
4221                                            MethodBase best, bool best_params,
4222                                            Location loc)
4223                 {
4224                         ParameterData candidate_pd = GetParameterData (candidate);
4225                         ParameterData best_pd;
4226                         int argument_count;
4227                 
4228                         if (args == null)
4229                                 argument_count = 0;
4230                         else
4231                                 argument_count = args.Count;
4232
4233                         int cand_count = candidate_pd.Count;
4234
4235                         //
4236                         // If there is no best method, than this one
4237                         // is better, however, if we already found a
4238                         // best method, we cant tell. This happens
4239                         // if we have:
4240                         // 
4241                         //
4242                         //      interface IFoo {
4243                         //              void DoIt ();
4244                         //      }
4245                         //      
4246                         //      interface IBar {
4247                         //              void DoIt ();
4248                         //      }
4249                         //      
4250                         //      interface IFooBar : IFoo, IBar {}
4251                         //
4252                         // We cant tell if IFoo.DoIt is better than IBar.DoIt
4253                         //
4254                         // However, we have to consider that
4255                         // Trim (); is better than Trim (params char[] chars);
4256                         if (cand_count == 0 && argument_count == 0)
4257                                 return best == null || best_params ? 1 : 0;
4258
4259                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
4260                                 if (cand_count != argument_count)
4261                                         return 0;
4262
4263                         if (best == null) {
4264                                 int x = 0;
4265
4266                                 if (argument_count == 0 && cand_count == 1 &&
4267                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
4268                                         return 1;
4269                                 
4270                                 for (int j = 0; j < argument_count; ++j) {
4271
4272                                         Argument a = (Argument) args [j];
4273                                         Type t = candidate_pd.ParameterType (j);
4274
4275                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4276                                                 if (candidate_params)
4277                                                         t = TypeManager.GetElementType (t);
4278
4279                                         x = BetterConversion (ec, a, t, null, loc);
4280                                         
4281                                         if (x <= 0)
4282                                                 break;
4283                                 }
4284
4285                                 if (x > 0)
4286                                         return 1;
4287                                 else
4288                                         return 0;
4289                         }
4290
4291                         best_pd = GetParameterData (best);
4292
4293                         int rating1 = 0, rating2 = 0;
4294                         
4295                         for (int j = 0; j < argument_count; ++j) {
4296                                 int x, y;
4297                                 
4298                                 Argument a = (Argument) args [j];
4299
4300                                 Type ct = candidate_pd.ParameterType (j);
4301                                 Type bt = best_pd.ParameterType (j);
4302
4303                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4304                                         if (candidate_params)
4305                                                 ct = TypeManager.GetElementType (ct);
4306
4307                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4308                                         if (best_params)
4309                                                 bt = TypeManager.GetElementType (bt);
4310
4311                                 x = BetterConversion (ec, a, ct, bt, loc);
4312                                 y = BetterConversion (ec, a, bt, ct, loc);
4313
4314                                 if (x < y)
4315                                         return 0;
4316                                 
4317                                 rating1 += x;
4318                                 rating2 += y;
4319                         }
4320
4321                         //
4322                         // If a method (in the normal form) with the
4323                         // same signature as the expanded form of the
4324                         // current best params method already exists,
4325                         // the expanded form is not applicable so we
4326                         // force it to select the candidate
4327                         //
4328                         if (!candidate_params && best_params && cand_count == argument_count)
4329                                 return 1;
4330
4331                         if (rating1 > rating2)
4332                                 return 1;
4333                         else
4334                                 return 0;
4335                 }
4336
4337                 public static string FullMethodDesc (MethodBase mb)
4338                 {
4339                         string ret_type = "";
4340
4341                         if (mb is MethodInfo)
4342                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4343                         
4344                         StringBuilder sb = new StringBuilder (ret_type);
4345                         sb.Append (" ");
4346                         sb.Append (mb.ReflectedType.ToString ());
4347                         sb.Append (".");
4348                         sb.Append (mb.Name);
4349                         
4350                         ParameterData pd = GetParameterData (mb);
4351
4352                         int count = pd.Count;
4353                         sb.Append (" (");
4354                         
4355                         for (int i = count; i > 0; ) {
4356                                 i--;
4357
4358                                 sb.Append (pd.ParameterDesc (count - i - 1));
4359                                 if (i != 0)
4360                                         sb.Append (", ");
4361                         }
4362                         
4363                         sb.Append (")");
4364                         return sb.ToString ();
4365                 }
4366
4367                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4368                 {
4369                         MemberInfo [] miset;
4370                         MethodGroupExpr union;
4371
4372                         if (mg1 == null) {
4373                                 if (mg2 == null)
4374                                         return null;
4375                                 return (MethodGroupExpr) mg2;
4376                         } else {
4377                                 if (mg2 == null)
4378                                         return (MethodGroupExpr) mg1;
4379                         }
4380                         
4381                         MethodGroupExpr left_set = null, right_set = null;
4382                         int length1 = 0, length2 = 0;
4383                         
4384                         left_set = (MethodGroupExpr) mg1;
4385                         length1 = left_set.Methods.Length;
4386                         
4387                         right_set = (MethodGroupExpr) mg2;
4388                         length2 = right_set.Methods.Length;
4389                         
4390                         ArrayList common = new ArrayList ();
4391
4392                         foreach (MethodBase r in right_set.Methods){
4393                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4394                                         common.Add (r);
4395                         }
4396
4397                         miset = new MemberInfo [length1 + length2 - common.Count];
4398                         left_set.Methods.CopyTo (miset, 0);
4399                         
4400                         int k = length1;
4401
4402                         foreach (MethodBase r in right_set.Methods) {
4403                                 if (!common.Contains (r))
4404                                         miset [k++] = r;
4405                         }
4406
4407                         union = new MethodGroupExpr (miset, loc);
4408                         
4409                         return union;
4410                 }
4411
4412                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4413                                                       ArrayList arguments, ref MethodBase candidate)
4414                 {
4415                         if (!me.HasTypeArguments &&
4416                             !InferParamsTypeArguments (ec, arguments, ref candidate))
4417                                 return false;
4418
4419                         return IsParamsMethodApplicable (ec, arguments, candidate);
4420                 }
4421
4422                 /// <summary>
4423                 ///   Determines if the candidate method, if a params method, is applicable
4424                 ///   in its expanded form to the given set of arguments
4425                 /// </summary>
4426                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4427                 {
4428                         int arg_count;
4429                         
4430                         if (arguments == null)
4431                                 arg_count = 0;
4432                         else
4433                                 arg_count = arguments.Count;
4434                         
4435                         ParameterData pd = GetParameterData (candidate);
4436                         
4437                         int pd_count = pd.Count;
4438
4439                         if (pd_count == 0)
4440                                 return false;
4441                         
4442                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
4443                                 return false;
4444                         
4445                         if (pd_count - 1 > arg_count)
4446                                 return false;
4447                         
4448                         if (pd_count == 1 && arg_count == 0)
4449                                 return true;
4450
4451                         //
4452                         // If we have come this far, the case which
4453                         // remains is when the number of parameters is
4454                         // less than or equal to the argument count.
4455                         //
4456                         for (int i = 0; i < pd_count - 1; ++i) {
4457
4458                                 Argument a = (Argument) arguments [i];
4459
4460                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4461                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4462                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4463                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4464
4465                                 if (a_mod == p_mod) {
4466
4467                                         if (a_mod == Parameter.Modifier.NONE)
4468                                                 if (!Convert.ImplicitConversionExists (ec,
4469                                                                                        a.Expr,
4470                                                                                        pd.ParameterType (i)))
4471                                                         return false;
4472                                                                                 
4473                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4474                                                 Type pt = pd.ParameterType (i);
4475
4476                                                 if (!pt.IsByRef)
4477                                                         pt = TypeManager.GetReferenceType (pt);
4478                                                 
4479                                                 if (pt != a.Type)
4480                                                         return false;
4481                                         }
4482                                 } else
4483                                         return false;
4484                                 
4485                         }
4486
4487                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4488
4489                         for (int i = pd_count - 1; i < arg_count; i++) {
4490                                 Argument a = (Argument) arguments [i];
4491                                 
4492                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4493                                         return false;
4494                         }
4495                         
4496                         return true;
4497                 }
4498
4499                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4500                                           ArrayList arguments, ref MethodBase candidate)
4501                 {
4502                         if (!me.HasTypeArguments &&
4503                             !InferTypeArguments (ec, arguments, ref candidate))
4504                                 return false;
4505
4506                         return IsApplicable (ec, arguments, candidate);
4507                 }
4508
4509                 /// <summary>
4510                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4511                 ///   to the given set of arguments
4512                 /// </summary>
4513                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4514                 {
4515                         int arg_count;
4516
4517                         if (arguments == null)
4518                                 arg_count = 0;
4519                         else
4520                                 arg_count = arguments.Count;
4521
4522
4523                         ParameterData pd = GetParameterData (candidate);
4524
4525                         if (arg_count != pd.Count)
4526                                 return false;
4527
4528                         for (int i = arg_count; i > 0; ) {
4529                                 i--;
4530
4531                                 Argument a = (Argument) arguments [i];
4532
4533                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4534                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4535                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4536                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4537
4538
4539                                 if (a_mod == p_mod ||
4540                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4541                                         if (a_mod == Parameter.Modifier.NONE) {
4542                                                 if (!Convert.ImplicitConversionExists (ec,
4543                                                                                        a.Expr,
4544                                                                                        pd.ParameterType (i)))
4545                                                         return false;
4546                                         }
4547                                         
4548                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4549                                                 Type pt = pd.ParameterType (i);
4550
4551                                                 if (!pt.IsByRef)
4552                                                         pt = TypeManager.GetReferenceType (pt);
4553                                                 
4554                                                 if (pt != a.Type)
4555                                                         return false;
4556                                         }
4557                                 } else
4558                                         return false;
4559                         }
4560
4561                         return true;
4562                 }
4563                 
4564                 
4565
4566                 /// <summary>
4567                 ///   Find the Applicable Function Members (7.4.2.1)
4568                 ///
4569                 ///   me: Method Group expression with the members to select.
4570                 ///       it might contain constructors or methods (or anything
4571                 ///       that maps to a method).
4572                 ///
4573                 ///   Arguments: ArrayList containing resolved Argument objects.
4574                 ///
4575                 ///   loc: The location if we want an error to be reported, or a Null
4576                 ///        location for "probing" purposes.
4577                 ///
4578                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4579                 ///            that is the best match of me on Arguments.
4580                 ///
4581                 /// </summary>
4582                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4583                                                           ArrayList Arguments, bool may_fail,
4584                                                           Location loc)
4585                 {
4586                         MethodBase method = null;
4587                         Type applicable_type = null;
4588                         int argument_count;
4589                         ArrayList candidates = new ArrayList ();
4590
4591                         //
4592                         // Used to keep a map between the candidate
4593                         // and whether it is being considered in its
4594                         // normal or expanded form
4595                         //
4596                         Hashtable candidate_to_form = new PtrHashtable ();
4597
4598
4599                         //
4600                         // First we construct the set of applicable methods
4601                         //
4602                         // We start at the top of the type hierarchy and
4603                         // go down to find applicable methods
4604                         //
4605                         applicable_type = me.DeclaringType;
4606                         
4607                         if (me.Name == "Invoke" && TypeManager.IsDelegateType (applicable_type)) {
4608                                 Error_InvokeOnDelegate (loc);
4609                                 return null;
4610                         }
4611
4612                         bool found_applicable = false;
4613
4614                         MethodBase[] methods = me.Methods;
4615
4616                         for (int i = 0; i < methods.Length; i++) {
4617                                 Type decl_type = methods [i].DeclaringType;
4618
4619                                 //
4620                                 // If we have already found an applicable method
4621                                 // we eliminate all base types (Section 14.5.5.1)
4622                                 //
4623                                 if (decl_type != applicable_type &&
4624                                     (applicable_type.IsSubclassOf (decl_type) ||
4625                                      TypeManager.ImplementsInterface (applicable_type, decl_type)) &&
4626                                     found_applicable)
4627                                         continue;
4628
4629                                 // Check if candidate is applicable (section 14.4.2.1)
4630                                 if (IsApplicable (ec, me, Arguments, ref methods [i])) {
4631                                         // Candidate is applicable in normal form
4632                                         MethodBase candidate = methods [i];
4633                                         candidates.Add (candidate);
4634                                         applicable_type = candidate.DeclaringType;
4635                                         found_applicable = true;
4636                                         candidate_to_form [candidate] = false;
4637                                 } else if (IsParamsMethodApplicable (ec, me, Arguments, ref methods [i])) {
4638                                         // Candidate is applicable in expanded form
4639                                         MethodBase candidate = methods [i];
4640                                         candidates.Add (candidate);
4641                                         applicable_type = candidate.DeclaringType;
4642                                         found_applicable = true; 
4643                                         candidate_to_form [candidate] = true;
4644                                 }
4645                         }
4646
4647                         if (Arguments == null)
4648                                 argument_count = 0;
4649                         else
4650                                 argument_count = Arguments.Count;
4651
4652                         //
4653                         // Now we actually find the best method
4654                         //
4655                         int candidate_top = candidates.Count;
4656                         for (int ix = 0; ix < candidate_top; ix++){
4657                                 MethodBase candidate = (MethodBase) candidates [ix];
4658                                 
4659                                 bool cand_params = (bool) candidate_to_form [candidate];
4660                                 bool method_params = false;
4661                                 
4662                                 if (method != null)
4663                                         method_params = (bool) candidate_to_form [method];
4664                                 
4665                                 int x = BetterFunction (ec, Arguments,
4666                                                         candidate, cand_params,
4667                                                         method, method_params,
4668                                                         loc);
4669                                 if (x == 0)
4670                                         continue;
4671                                 
4672                                 method = candidate;
4673                         }
4674
4675                         if (method == null) {
4676                                 int errors = Report.Errors;
4677
4678                                 //
4679                                 // Okay so we have failed to find anything so we
4680                                 // return by providing info about the closest match
4681                                 //
4682                                 for (int i = 0; i < methods.Length; ++i) {
4683
4684                                         MethodBase c = methods [i];
4685                                         if (c == null)
4686                                                 continue;
4687
4688                                         ParameterData pd = GetParameterData (c);
4689                                         if (pd.Count != argument_count)
4690                                                 continue;
4691
4692                                         if (!InferTypeArguments (ec, Arguments, ref c))
4693                                                 continue;
4694
4695                                         VerifyArgumentsCompat (ec, Arguments, argument_count,
4696                                                                c, false, null, loc);
4697                                         break;
4698                                 }
4699
4700                                 if (Report.Errors > errors)
4701                                         return null;
4702
4703                                 string report_name = me.Name;
4704                                 if (report_name == ".ctor")
4705                                         report_name = me.DeclaringType.ToString ();
4706                                         
4707                                 for (int i = 0; i < methods.Length; ++i) {
4708
4709                                         MethodBase c = methods [i];
4710                                         if (c == null)
4711                                                 continue;
4712
4713                                         ParameterData pd = GetParameterData (c);
4714                                         if (pd.Count != argument_count)
4715                                                 continue;
4716
4717                                         if (InferTypeArguments (ec, Arguments, ref c))
4718                                                 continue;
4719
4720                                         Report.Error (411, loc, "The type arguments for " +
4721                                                       "method `{0}' cannot be infered from " +
4722                                                       "the usage. Try specifying the type " +
4723                                                       "arguments explicitly.", report_name);
4724                                         break;
4725                                 }
4726
4727                                 if (!may_fail && (errors == Report.Errors))
4728                                         Error_WrongNumArguments (loc, report_name,
4729                                                                  argument_count);
4730                                 
4731                                 return null;
4732                         }
4733
4734                         //
4735                         // Now check that there are no ambiguities i.e the selected method
4736                         // should be better than all the others
4737                         //
4738                         bool best_params = (bool) candidate_to_form [method];
4739
4740                         for (int ix = 0; ix < candidate_top; ix++){
4741                                 MethodBase candidate = (MethodBase) candidates [ix];
4742
4743                                 if (candidate == method)
4744                                         continue;
4745                                                
4746                                 //
4747                                 // If a normal method is applicable in
4748                                 // the sense that it has the same
4749                                 // number of arguments, then the
4750                                 // expanded params method is never
4751                                 // applicable so we debar the params
4752                                 // method.
4753                                 //
4754                                 if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
4755                                      IsApplicable (ec, Arguments, method)))
4756                                         continue;
4757                                 
4758                                 bool cand_params = (bool) candidate_to_form [candidate];
4759                                 int x = BetterFunction (ec, Arguments,
4760                                                         method, best_params,
4761                                                         candidate, cand_params,
4762                                                         loc);
4763
4764                                 if (x != 1) {
4765                                         Report.Error (
4766                                                 121, loc,
4767                                                 "Ambiguous call when selecting function due to implicit casts");
4768                                         return null;
4769                                 }
4770                         }
4771
4772                         //
4773                         // And now check if the arguments are all
4774                         // compatible, perform conversions if
4775                         // necessary etc. and return if everything is
4776                         // all right
4777                         //
4778                         if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4779                                                     best_params, null, loc))
4780                                 return null;
4781
4782                         return method;
4783                 }
4784
4785                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4786                 {
4787                         Report.Error (1501, loc,
4788                                       "No overload for method `" + name + "' takes `" +
4789                                       arg_count + "' arguments");
4790                 }
4791
4792                 static void Error_InvokeOnDelegate (Location loc)
4793                 {
4794                         Report.Error (1533, loc,
4795                                       "Invoke cannot be called directly on a delegate");
4796                 }
4797                         
4798                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4799                                                     Type delegate_type, string arg_sig, string par_desc)
4800                 {
4801                         if (delegate_type == null) 
4802                                 Report.Error (1502, loc,
4803                                               "The best overloaded match for method '" +
4804                                               FullMethodDesc (method) +
4805                                               "' has some invalid arguments");
4806                         else
4807                                 Report.Error (1594, loc,
4808                                               "Delegate '" + delegate_type.ToString () +
4809                                               "' has some invalid arguments.");
4810                         Report.Error (1503, loc,
4811                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4812                                                      idx, arg_sig, par_desc));
4813                 }
4814                 
4815                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4816                                                           int argument_count,
4817                                                           MethodBase method, 
4818                                                           bool chose_params_expanded,
4819                                                           Type delegate_type,
4820                                                           Location loc)
4821                 {
4822                         ParameterData pd = GetParameterData (method);
4823                         int pd_count = pd.Count;
4824                         
4825                         for (int j = 0; j < argument_count; j++) {
4826                                 Argument a = (Argument) Arguments [j];
4827                                 Expression a_expr = a.Expr;
4828                                 Type parameter_type = pd.ParameterType (j);
4829                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4830                                 
4831                                 if (pm == Parameter.Modifier.PARAMS){
4832                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4833                                                 if (!Location.IsNull (loc))
4834                                                         Error_InvalidArguments (
4835                                                                 loc, j, method, delegate_type,
4836                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4837                                                 return false;
4838                                         }
4839
4840                                         if (chose_params_expanded)
4841                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4842                                 } else {
4843                                         //
4844                                         // Check modifiers
4845                                         //
4846                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4847                                                 if (!Location.IsNull (loc))
4848                                                         Error_InvalidArguments (
4849                                                                 loc, j, method, delegate_type,
4850                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4851                                                 return false;
4852                                         }
4853                                 }
4854
4855                                 //
4856                                 // Check Type
4857                                 //
4858                                 if (a.Type != parameter_type){
4859                                         Expression conv;
4860                                         
4861                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
4862
4863                                         if (conv == null) {
4864                                                 if (!Location.IsNull (loc)) 
4865                                                         Error_InvalidArguments (
4866                                                                 loc, j, method, delegate_type,
4867                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4868                                                 return false;
4869                                         }
4870                                         
4871                                         //
4872                                         // Update the argument with the implicit conversion
4873                                         //
4874                                         if (a_expr != conv)
4875                                                 a.Expr = conv;
4876                                 }
4877
4878                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4879                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4880                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4881                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4882                                 
4883                                 if (a_mod != p_mod &&
4884                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4885                                         if (!Location.IsNull (loc)) {
4886                                                 Report.Error (1502, loc,
4887                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
4888                                                        "' has some invalid arguments");
4889                                                 Report.Error (1503, loc,
4890                                                        "Argument " + (j+1) +
4891                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
4892                                                        + "' to '" + pd.ParameterDesc (j) + "'");
4893                                         }
4894                                         
4895                                         return false;
4896                                 }
4897                         }
4898
4899                         return true;
4900                 }
4901
4902                 static bool InferType (Type pt, Type at, ref Type[] infered)
4903                 {
4904                         if (!pt.ContainsGenericParameters)
4905                                 return true;
4906
4907                         if (pt.IsGenericParameter) {
4908                                 int pos = pt.GenericParameterPosition;
4909
4910                                 if (infered [pos] == null) {
4911                                         Type check = at;
4912                                         while (check.IsArray)
4913                                                 check = check.GetElementType ();
4914
4915                                         if (pt.Equals (check))
4916                                                 return false;
4917
4918                                         infered [pos] = at;
4919                                         return true;
4920                                 }
4921
4922                                 if (infered [pos] != at)
4923                                         return false;
4924
4925                                 return true;
4926                         }
4927
4928                         if (at.IsArray) {
4929                                 if (!pt.IsArray ||
4930                                     (at.GetArrayRank () != pt.GetArrayRank ()))
4931                                         return false;
4932
4933                                 return InferType (pt.GetElementType (), at.GetElementType (),
4934                                                   ref infered);
4935                         }
4936
4937                         if (pt.IsArray) {
4938                                 if (!at.IsArray ||
4939                                     (pt.GetArrayRank () != at.GetArrayRank ()))
4940                                         return false;
4941
4942                                 return InferType (pt.GetElementType (), at.GetElementType (),
4943                                                   ref infered);
4944                         }
4945
4946                         if (!at.IsGenericInstance)
4947                                 return false;
4948
4949                         Type[] at_args = at.GetGenericArguments ();
4950                         Type[] pt_args = pt.GetGenericArguments ();
4951
4952                         if (at_args.Length != pt_args.Length)
4953                                 return false;
4954
4955                         Type[] infered_types = new Type [at_args.Length];
4956
4957                         for (int i = 0; i < at_args.Length; i++)
4958                                 if (!InferType (pt_args [i], at_args [i], ref infered_types))
4959                                         return false;
4960
4961                         for (int i = 0; i < infered_types.Length; i++)
4962                                 if (infered_types [i] == null)
4963                                         return false;
4964
4965                         for (int i = 0; i < infered_types.Length; i++) {
4966                                 if (infered [i] == null) {
4967                                         infered [i] = infered_types [i];
4968                                         continue;
4969                                 }
4970
4971                                 if (infered [i] != infered_types [i])
4972                                         return false;
4973                         }
4974
4975                         return true;
4976                 }
4977
4978                 static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
4979                                                       ref MethodBase method)
4980                 {
4981                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
4982                                 return true;
4983
4984                         int arg_count;
4985                         
4986                         if (arguments == null)
4987                                 arg_count = 0;
4988                         else
4989                                 arg_count = arguments.Count;
4990                         
4991                         ParameterData pd = GetParameterData (method);
4992
4993                         int pd_count = pd.Count;
4994
4995                         if (pd_count == 0)
4996                                 return false;
4997                         
4998                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
4999                                 return false;
5000                         
5001                         if (pd_count - 1 > arg_count)
5002                                 return false;
5003                         
5004                         if (pd_count == 1 && arg_count == 0)
5005                                 return true;
5006
5007                         Type[] method_args = method.GetGenericParameters ();
5008                         Type[] infered_types = new Type [method_args.Length];
5009
5010                         //
5011                         // If we have come this far, the case which
5012                         // remains is when the number of parameters is
5013                         // less than or equal to the argument count.
5014                         //
5015                         for (int i = 0; i < pd_count - 1; ++i) {
5016                                 Argument a = (Argument) arguments [i];
5017
5018                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5019                                         continue;
5020
5021                                 Type pt = pd.ParameterType (i);
5022                                 Type at = a.Type;
5023
5024                                 if (!InferType (pt, at, ref infered_types))
5025                                         return false;
5026                         }
5027
5028                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
5029
5030                         for (int i = pd_count - 1; i < arg_count; i++) {
5031                                 Argument a = (Argument) arguments [i];
5032
5033                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5034                                         continue;
5035
5036                                 if (!InferType (element_type, a.Type, ref infered_types))
5037                                         return false;
5038                         }
5039
5040                         for (int i = 0; i < infered_types.Length; i++)
5041                                 if (infered_types [i] == null)
5042                                         return false;
5043
5044                         method = method.BindGenericParameters (infered_types);
5045                         return true;
5046                 }
5047
5048                 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types,
5049                                                        ref Type[] infered_types)
5050                 {
5051                         for (int i = 0; i < arg_types.Length; i++) {
5052                                 if (arg_types [i] == null)
5053                                         continue;
5054
5055                                 if (!InferType (param_types [i], arg_types [i],
5056                                                 ref infered_types))
5057                                         return false;
5058                         }
5059
5060                         for (int i = 0; i < infered_types.Length; i++)
5061                                 if (infered_types [i] == null)
5062                                         return false;
5063
5064                         return true;
5065                 }
5066
5067                 static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
5068                                                 ref MethodBase method)
5069                 {
5070                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
5071                                 return true;
5072
5073                         ParameterData pd = GetParameterData (method);
5074                         if (arguments.Count != pd.Count)
5075                                 return false;
5076
5077                         Type[] method_args = method.GetGenericParameters ();
5078                         Type[] infered_types = new Type [method_args.Length];
5079
5080                         Type[] param_types = new Type [pd.Count];
5081                         Type[] arg_types = new Type [pd.Count];
5082
5083                         for (int i = 0; i < arguments.Count; i++) {
5084                                 param_types [i] = pd.ParameterType (i);
5085
5086                                 Argument a = (Argument) arguments [i];
5087                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5088                                         continue;
5089
5090                                 arg_types [i] = a.Type;
5091                         }
5092
5093                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5094                                 return false;
5095
5096                         method = method.BindGenericParameters (infered_types);
5097                         return true;
5098                 }
5099
5100                 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
5101                                                        ref MethodBase method)
5102                 {
5103                         if (!TypeManager.IsGenericMethod (method))
5104                                 return true;
5105
5106                         ParameterData pd = GetParameterData (method);
5107                         if (apd.Count != pd.Count)
5108                                 return false;
5109
5110                         Type[] method_args = method.GetGenericParameters ();
5111                         Type[] infered_types = new Type [method_args.Length];
5112
5113                         Type[] param_types = new Type [pd.Count];
5114                         Type[] arg_types = new Type [pd.Count];
5115
5116                         for (int i = 0; i < apd.Count; i++) {
5117                                 param_types [i] = pd.ParameterType (i);
5118                                 arg_types [i] = apd.ParameterType (i);
5119                         }
5120
5121                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5122                                 return false;
5123
5124                         method = method.BindGenericParameters (infered_types);
5125                         return true;
5126                 }
5127
5128                 public override Expression DoResolve (EmitContext ec)
5129                 {
5130                         //
5131                         // First, resolve the expression that is used to
5132                         // trigger the invocation
5133                         //
5134                         if (expr is BaseAccess)
5135                                 is_base = true;
5136
5137                         if (expr is ConstructedType)
5138                                 expr = ((ConstructedType) expr).GetMemberAccess (ec);
5139
5140                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5141                         if (expr == null)
5142                                 return null;
5143
5144                         if (!(expr is MethodGroupExpr)) {
5145                                 Type expr_type = expr.Type;
5146
5147                                 if (expr_type != null){
5148                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5149                                         if (IsDelegate)
5150                                                 return (new DelegateInvocation (
5151                                                         this.expr, Arguments, loc)).Resolve (ec);
5152                                 }
5153                         }
5154
5155                         if (!(expr is MethodGroupExpr)){
5156                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
5157                                 return null;
5158                         }
5159
5160                         //
5161                         // Next, evaluate all the expressions in the argument list
5162                         //
5163                         if (Arguments != null){
5164                                 foreach (Argument a in Arguments){
5165                                         if (!a.Resolve (ec, loc))
5166                                                 return null;
5167                                 }
5168                         }
5169
5170                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5171                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5172
5173                         if (method == null)
5174                                 return null;
5175
5176                         MethodInfo mi = method as MethodInfo;
5177                         if (mi != null) {
5178                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5179                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
5180                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5181                         }
5182
5183                         if (type.IsPointer){
5184                                 if (!ec.InUnsafe){
5185                                         UnsafeError (loc);
5186                                         return null;
5187                                 }
5188                         }
5189                         
5190                         //
5191                         // Only base will allow this invocation to happen.
5192                         //
5193                         if (is_base && method.IsAbstract){
5194                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5195                                               FullMethodDesc (method));
5196                                 return null;
5197                         }
5198
5199                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
5200                                 if (TypeManager.IsSpecialMethod (method))
5201                                         Report.Error (571, loc, method.Name + ": can not call operator or accessor");
5202                         }
5203                         
5204                         eclass = ExprClass.Value;
5205                         return this;
5206                 }
5207
5208                 // <summary>
5209                 //   Emits the list of arguments as an array
5210                 // </summary>
5211                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5212                 {
5213                         ILGenerator ig = ec.ig;
5214                         int count = arguments.Count - idx;
5215                         Argument a = (Argument) arguments [idx];
5216                         Type t = a.Expr.Type;
5217                         string array_type = t.FullName + "[]";
5218                         LocalBuilder array;
5219
5220                         array = ig.DeclareLocal (TypeManager.LookupType (array_type));
5221                         IntConstant.EmitInt (ig, count);
5222                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5223                         ig.Emit (OpCodes.Stloc, array);
5224
5225                         int top = arguments.Count;
5226                         for (int j = idx; j < top; j++){
5227                                 a = (Argument) arguments [j];
5228                                 
5229                                 ig.Emit (OpCodes.Ldloc, array);
5230                                 IntConstant.EmitInt (ig, j - idx);
5231
5232                                 bool is_stobj, has_type_arg;
5233                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5234                                 if (is_stobj)
5235                                         ig.Emit (OpCodes.Ldelema, t);
5236
5237                                 a.Emit (ec);
5238
5239                                 if (has_type_arg)
5240                                         ig.Emit (op, t);
5241                                 else
5242                                         ig.Emit (op);
5243                         }
5244                         ig.Emit (OpCodes.Ldloc, array);
5245                 }
5246                 
5247                 /// <summary>
5248                 ///   Emits a list of resolved Arguments that are in the arguments
5249                 ///   ArrayList.
5250                 /// 
5251                 ///   The MethodBase argument might be null if the
5252                 ///   emission of the arguments is known not to contain
5253                 ///   a `params' field (for example in constructors or other routines
5254                 ///   that keep their arguments in this structure)
5255                 /// </summary>
5256                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
5257                 {
5258                         ParameterData pd;
5259                         if (mb != null)
5260                                 pd = GetParameterData (mb);
5261                         else
5262                                 pd = null;
5263
5264                         //
5265                         // If we are calling a params method with no arguments, special case it
5266                         //
5267                         if (arguments == null){
5268                                 if (pd != null && pd.Count > 0 &&
5269                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5270                                         ILGenerator ig = ec.ig;
5271
5272                                         IntConstant.EmitInt (ig, 0);
5273                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5274                                 }
5275
5276                                 return;
5277                         }
5278
5279                         int top = arguments.Count;
5280
5281                         for (int i = 0; i < top; i++){
5282                                 Argument a = (Argument) arguments [i];
5283
5284                                 if (pd != null){
5285                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5286                                                 //
5287                                                 // Special case if we are passing the same data as the
5288                                                 // params argument, do not put it in an array.
5289                                                 //
5290                                                 if (pd.ParameterType (i) == a.Type)
5291                                                         a.Emit (ec);
5292                                                 else
5293                                                         EmitParams (ec, i, arguments);
5294                                                 return;
5295                                         }
5296                                 }
5297                                             
5298                                 a.Emit (ec);
5299                         }
5300
5301                         if (pd != null && pd.Count > top &&
5302                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5303                                 ILGenerator ig = ec.ig;
5304
5305                                 IntConstant.EmitInt (ig, 0);
5306                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5307                         }
5308                 }
5309
5310                 /// <remarks>
5311                 ///   is_base tells whether we want to force the use of the `call'
5312                 ///   opcode instead of using callvirt.  Call is required to call
5313                 ///   a specific method, while callvirt will always use the most
5314                 ///   recent method in the vtable.
5315                 ///
5316                 ///   is_static tells whether this is an invocation on a static method
5317                 ///
5318                 ///   instance_expr is an expression that represents the instance
5319                 ///   it must be non-null if is_static is false.
5320                 ///
5321                 ///   method is the method to invoke.
5322                 ///
5323                 ///   Arguments is the list of arguments to pass to the method or constructor.
5324                 /// </remarks>
5325                 public static void EmitCall (EmitContext ec, bool is_base,
5326                                              bool is_static, Expression instance_expr,
5327                                              MethodBase method, ArrayList Arguments, Location loc)
5328                 {
5329                         ILGenerator ig = ec.ig;
5330                         bool struct_call = false;
5331                         bool this_call = false;
5332
5333                         Type decl_type = method.DeclaringType;
5334
5335                         if (!RootContext.StdLib) {
5336                                 // Replace any calls to the system's System.Array type with calls to
5337                                 // the newly created one.
5338                                 if (method == TypeManager.system_int_array_get_length)
5339                                         method = TypeManager.int_array_get_length;
5340                                 else if (method == TypeManager.system_int_array_get_rank)
5341                                         method = TypeManager.int_array_get_rank;
5342                                 else if (method == TypeManager.system_object_array_clone)
5343                                         method = TypeManager.object_array_clone;
5344                                 else if (method == TypeManager.system_int_array_get_length_int)
5345                                         method = TypeManager.int_array_get_length_int;
5346                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5347                                         method = TypeManager.int_array_get_lower_bound_int;
5348                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5349                                         method = TypeManager.int_array_get_upper_bound_int;
5350                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5351                                         method = TypeManager.void_array_copyto_array_int;
5352                         }
5353
5354                         //
5355                         // This checks the `ConditionalAttribute' on the method, and the
5356                         // ObsoleteAttribute
5357                         //
5358                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
5359                         if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
5360                                 return;
5361                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
5362                                 return;
5363                         
5364                         if (!is_static){
5365                                 if (TypeManager.IsValueType (decl_type))
5366                                         struct_call = true;
5367                                 //
5368                                 // If this is ourselves, push "this"
5369                                 //
5370                                 if (instance_expr == null){
5371                                         this_call = true;
5372                                         ig.Emit (OpCodes.Ldarg_0);
5373                                 } else {
5374                                         //
5375                                         // Push the instance expression
5376                                         //
5377                                         if (TypeManager.IsValueType (instance_expr.Type)){
5378                                                 //
5379                                                 // Special case: calls to a function declared in a 
5380                                                 // reference-type with a value-type argument need
5381                                                 // to have their value boxed.  
5382
5383                                                 if (!instance_expr.Type.IsGenericParameter)
5384                                                         struct_call = true;
5385                                                 if (TypeManager.IsValueType (decl_type)){
5386                                                         //
5387                                                         // If the expression implements IMemoryLocation, then
5388                                                         // we can optimize and use AddressOf on the
5389                                                         // return.
5390                                                         //
5391                                                         // If not we have to use some temporary storage for
5392                                                         // it.
5393                                                         if (instance_expr is IMemoryLocation){
5394                                                                 ((IMemoryLocation)instance_expr).
5395                                                                         AddressOf (ec, AddressOp.LoadStore);
5396                                                         }
5397                                                         else {
5398                                                                 Type t = instance_expr.Type;
5399                                                                 
5400                                                                 instance_expr.Emit (ec);
5401                                                                 LocalBuilder temp = ig.DeclareLocal (t);
5402                                                                 ig.Emit (OpCodes.Stloc, temp);
5403                                                                 ig.Emit (OpCodes.Ldloca, temp);
5404                                                         }
5405                                                 } else {
5406                                                         instance_expr.Emit (ec);
5407                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5408                                                 } 
5409                                         } else
5410                                                 instance_expr.Emit (ec);
5411                                 }
5412                         }
5413
5414                         EmitArguments (ec, method, Arguments);
5415                         //
5416                         // If you have:
5417                         // this.DoFoo ();
5418                         // and DoFoo is not virtual, you can omit the callvirt,
5419                         // because you don't need the null checking behavior.
5420                         //
5421                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)){
5422                                 if (method is MethodInfo) {
5423                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
5424                                 } else
5425                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5426                         } else {
5427                                 if (method is MethodInfo)
5428                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
5429                                 else
5430                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
5431                         }
5432                 }
5433                 
5434                 public override void Emit (EmitContext ec)
5435                 {
5436                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5437
5438                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5439                 }
5440                 
5441                 public override void EmitStatement (EmitContext ec)
5442                 {
5443                         Emit (ec);
5444
5445                         // 
5446                         // Pop the return value if there is one
5447                         //
5448                         if (method is MethodInfo){
5449                                 Type ret = ((MethodInfo)method).ReturnType;
5450                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5451                                         ec.ig.Emit (OpCodes.Pop);
5452                         }
5453                 }
5454         }
5455
5456         public class InvocationOrCast : ExpressionStatement
5457         {
5458                 Expression expr;
5459                 Expression argument;
5460
5461                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5462                 {
5463                         this.expr = expr;
5464                         this.argument = argument;
5465                         this.loc = loc;
5466                 }
5467
5468                 public override Expression DoResolve (EmitContext ec)
5469                 {
5470                         //
5471                         // First try to resolve it as a cast.
5472                         //
5473                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5474                         if (type != null) {
5475                                 Cast cast = new Cast (new TypeExpression (type, loc), argument, loc);
5476                                 return cast.Resolve (ec);
5477                         }
5478
5479                         //
5480                         // This can either be a type or a delegate invocation.
5481                         // Let's just resolve it and see what we'll get.
5482                         //
5483                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5484                         if (expr == null)
5485                                 return null;
5486
5487                         //
5488                         // Ok, so it's a Cast.
5489                         //
5490                         if (expr.eclass == ExprClass.Type) {
5491                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5492                                 return cast.Resolve (ec);
5493                         }
5494
5495                         //
5496                         // It's a delegate invocation.
5497                         //
5498                         if (!TypeManager.IsDelegateType (expr.Type)) {
5499                                 Error (149, "Method name expected");
5500                                 return null;
5501                         }
5502
5503                         ArrayList args = new ArrayList ();
5504                         args.Add (new Argument (argument, Argument.AType.Expression));
5505                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5506                         return invocation.Resolve (ec);
5507                 }
5508
5509                 void error201 ()
5510                 {
5511                         Error (201, "Only assignment, call, increment, decrement and new object " +
5512                                "expressions can be used as a statement");
5513                 }
5514
5515                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5516                 {
5517                         //
5518                         // First try to resolve it as a cast.
5519                         //
5520                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5521                         if (type != null) {
5522                                 error201 ();
5523                                 return null;
5524                         }
5525
5526                         //
5527                         // This can either be a type or a delegate invocation.
5528                         // Let's just resolve it and see what we'll get.
5529                         //
5530                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5531                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5532                                 error201 ();
5533                                 return null;
5534                         }
5535
5536                         //
5537                         // It's a delegate invocation.
5538                         //
5539                         if (!TypeManager.IsDelegateType (expr.Type)) {
5540                                 Error (149, "Method name expected");
5541                                 return null;
5542                         }
5543
5544                         ArrayList args = new ArrayList ();
5545                         args.Add (new Argument (argument, Argument.AType.Expression));
5546                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5547                         return invocation.ResolveStatement (ec);
5548                 }
5549
5550                 public override void Emit (EmitContext ec)
5551                 {
5552                         throw new Exception ("Cannot happen");
5553                 }
5554
5555                 public override void EmitStatement (EmitContext ec)
5556                 {
5557                         throw new Exception ("Cannot happen");
5558                 }
5559         }
5560
5561         //
5562         // This class is used to "disable" the code generation for the
5563         // temporary variable when initializing value types.
5564         //
5565         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5566                 public void AddressOf (EmitContext ec, AddressOp Mode)
5567                 {
5568                         // nothing
5569                 }
5570         }
5571         
5572         /// <summary>
5573         ///    Implements the new expression 
5574         /// </summary>
5575         public class New : ExpressionStatement, IMemoryLocation {
5576                 public readonly ArrayList Arguments;
5577
5578                 //
5579                 // During bootstrap, it contains the RequestedType,
5580                 // but if `type' is not null, it *might* contain a NewDelegate
5581                 // (because of field multi-initialization)
5582                 //
5583                 public Expression RequestedType;
5584
5585                 MethodBase method = null;
5586
5587                 //
5588                 // If set, the new expression is for a value_target, and
5589                 // we will not leave anything on the stack.
5590                 //
5591                 Expression value_target;
5592                 bool value_target_set = false;
5593                 
5594                 public New (Expression requested_type, ArrayList arguments, Location l)
5595                 {
5596                         RequestedType = requested_type;
5597                         Arguments = arguments;
5598                         loc = l;
5599                 }
5600
5601                 public bool SetValueTypeVariable (Expression value)
5602                 {
5603                         value_target = value;
5604                         value_target_set = true;
5605                         if (!(value_target is IMemoryLocation)){
5606                                 Error_UnexpectedKind ("variable");
5607                                 return false;
5608                         }
5609                         return true;
5610                 }
5611
5612                 //
5613                 // This function is used to disable the following code sequence for
5614                 // value type initialization:
5615                 //
5616                 // AddressOf (temporary)
5617                 // Construct/Init
5618                 // LoadTemporary
5619                 //
5620                 // Instead the provide will have provided us with the address on the
5621                 // stack to store the results.
5622                 //
5623                 static Expression MyEmptyExpression;
5624                 
5625                 public void DisableTemporaryValueType ()
5626                 {
5627                         if (MyEmptyExpression == null)
5628                                 MyEmptyExpression = new EmptyAddressOf ();
5629
5630                         //
5631                         // To enable this, look into:
5632                         // test-34 and test-89 and self bootstrapping.
5633                         //
5634                         // For instance, we can avoid a copy by using `newobj'
5635                         // instead of Call + Push-temp on value types.
5636 //                      value_target = MyEmptyExpression;
5637                 }
5638
5639                 public override Expression DoResolve (EmitContext ec)
5640                 {
5641                         //
5642                         // The New DoResolve might be called twice when initializing field
5643                         // expressions (see EmitFieldInitializers, the call to
5644                         // GetInitializerExpression will perform a resolve on the expression,
5645                         // and later the assign will trigger another resolution
5646                         //
5647                         // This leads to bugs (#37014)
5648                         //
5649                         if (type != null){
5650                                 if (RequestedType is NewDelegate)
5651                                         return RequestedType;
5652                                 return this;
5653                         }
5654                         
5655                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5656                         
5657                         if (type == null)
5658                                 return null;
5659                         
5660                         bool IsDelegate = TypeManager.IsDelegateType (type);
5661                         
5662                         if (IsDelegate){
5663                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5664                                 if (RequestedType != null)
5665                                         if (!(RequestedType is NewDelegate))
5666                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5667                                 return RequestedType;
5668                         }
5669
5670                         if (type.IsInterface || type.IsAbstract){
5671                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5672                                 return null;
5673                         }
5674                         
5675                         bool is_struct = type.IsValueType;
5676                         eclass = ExprClass.Value;
5677
5678                         //
5679                         // SRE returns a match for .ctor () on structs (the object constructor), 
5680                         // so we have to manually ignore it.
5681                         //
5682                         if (is_struct && Arguments == null)
5683                                 return this;
5684                         
5685                         Expression ml;
5686                         ml = MemberLookupFinal (ec, null, type, ".ctor", 0,
5687                                                 MemberTypes.Constructor,
5688                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5689
5690                         if (ml == null)
5691                                 return null;
5692                         
5693                         if (! (ml is MethodGroupExpr)){
5694                                 if (!is_struct){
5695                                         ml.Error_UnexpectedKind ("method group");
5696                                         return null;
5697                                 }
5698                         }
5699
5700                         if (ml != null) {
5701                                 if (Arguments != null){
5702                                         foreach (Argument a in Arguments){
5703                                                 if (!a.Resolve (ec, loc))
5704                                                         return null;
5705                                         }
5706                                 }
5707
5708                                 method = Invocation.OverloadResolve (
5709                                         ec, (MethodGroupExpr) ml, Arguments, false, loc);
5710                                 
5711                         }
5712
5713                         if (method == null) { 
5714                                 if (!is_struct || Arguments.Count > 0) {
5715                                         Error (1501, String.Format (
5716                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5717                                             TypeManager.CSharpName (type)));
5718                                         return null;
5719                                 }
5720                         }
5721
5722                         return this;
5723                 }
5724
5725                 //
5726                 // This DoEmit can be invoked in two contexts:
5727                 //    * As a mechanism that will leave a value on the stack (new object)
5728                 //    * As one that wont (init struct)
5729                 //
5730                 // You can control whether a value is required on the stack by passing
5731                 // need_value_on_stack.  The code *might* leave a value on the stack
5732                 // so it must be popped manually
5733                 //
5734                 // If we are dealing with a ValueType, we have a few
5735                 // situations to deal with:
5736                 //
5737                 //    * The target is a ValueType, and we have been provided
5738                 //      the instance (this is easy, we are being assigned).
5739                 //
5740                 //    * The target of New is being passed as an argument,
5741                 //      to a boxing operation or a function that takes a
5742                 //      ValueType.
5743                 //
5744                 //      In this case, we need to create a temporary variable
5745                 //      that is the argument of New.
5746                 //
5747                 // Returns whether a value is left on the stack
5748                 //
5749                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5750                 {
5751                         bool is_value_type = type.IsValueType;
5752                         ILGenerator ig = ec.ig;
5753
5754                         if (is_value_type){
5755                                 IMemoryLocation ml;
5756
5757                                 // Allow DoEmit() to be called multiple times.
5758                                 // We need to create a new LocalTemporary each time since
5759                                 // you can't share LocalBuilders among ILGeneators.
5760                                 if (!value_target_set)
5761                                         value_target = new LocalTemporary (ec, type);
5762
5763                                 ml = (IMemoryLocation) value_target;
5764                                 ml.AddressOf (ec, AddressOp.Store);
5765                         }
5766
5767                         if (method != null)
5768                                 Invocation.EmitArguments (ec, method, Arguments);
5769
5770                         if (is_value_type){
5771                                 if (method == null)
5772                                         ig.Emit (OpCodes.Initobj, type);
5773                                 else 
5774                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5775                                 if (need_value_on_stack){
5776                                         value_target.Emit (ec);
5777                                         return true;
5778                                 }
5779                                 return false;
5780                         } else {
5781                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5782                                 return true;
5783                         }
5784                 }
5785
5786                 public override void Emit (EmitContext ec)
5787                 {
5788                         DoEmit (ec, true);
5789                 }
5790                 
5791                 public override void EmitStatement (EmitContext ec)
5792                 {
5793                         if (DoEmit (ec, false))
5794                                 ec.ig.Emit (OpCodes.Pop);
5795                 }
5796
5797                 public void AddressOf (EmitContext ec, AddressOp Mode)
5798                 {
5799                         if (!type.IsValueType){
5800                                 //
5801                                 // We throw an exception.  So far, I believe we only need to support
5802                                 // value types:
5803                                 // foreach (int j in new StructType ())
5804                                 // see bug 42390
5805                                 //
5806                                 throw new Exception ("AddressOf should not be used for classes");
5807                         }
5808
5809                         if (!value_target_set)
5810                                 value_target = new LocalTemporary (ec, type);
5811                                         
5812                         IMemoryLocation ml = (IMemoryLocation) value_target;
5813                         ml.AddressOf (ec, AddressOp.Store);
5814                         if (method != null)
5815                                 Invocation.EmitArguments (ec, method, Arguments);
5816
5817                         if (method == null)
5818                                 ec.ig.Emit (OpCodes.Initobj, type);
5819                         else 
5820                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5821                         
5822                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5823                 }
5824         }
5825
5826         /// <summary>
5827         ///   14.5.10.2: Represents an array creation expression.
5828         /// </summary>
5829         ///
5830         /// <remarks>
5831         ///   There are two possible scenarios here: one is an array creation
5832         ///   expression that specifies the dimensions and optionally the
5833         ///   initialization data and the other which does not need dimensions
5834         ///   specified but where initialization data is mandatory.
5835         /// </remarks>
5836         public class ArrayCreation : ExpressionStatement {
5837                 Expression requested_base_type;
5838                 ArrayList initializers;
5839
5840                 //
5841                 // The list of Argument types.
5842                 // This is used to construct the `newarray' or constructor signature
5843                 //
5844                 ArrayList arguments;
5845
5846                 //
5847                 // Method used to create the array object.
5848                 //
5849                 MethodBase new_method = null;
5850                 
5851                 Type array_element_type;
5852                 Type underlying_type;
5853                 bool is_one_dimensional = false;
5854                 bool is_builtin_type = false;
5855                 bool expect_initializers = false;
5856                 int num_arguments = 0;
5857                 int dimensions = 0;
5858                 string rank;
5859
5860                 ArrayList array_data;
5861
5862                 Hashtable bounds;
5863
5864                 //
5865                 // The number of array initializers that we can handle
5866                 // via the InitializeArray method - through EmitStaticInitializers
5867                 //
5868                 int num_automatic_initializers;
5869
5870                 const int max_automatic_initializers = 6;
5871                 
5872                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5873                 {
5874                         this.requested_base_type = requested_base_type;
5875                         this.initializers = initializers;
5876                         this.rank = rank;
5877                         loc = l;
5878
5879                         arguments = new ArrayList ();
5880
5881                         foreach (Expression e in exprs) {
5882                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5883                                 num_arguments++;
5884                         }
5885                 }
5886
5887                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5888                 {
5889                         this.requested_base_type = requested_base_type;
5890                         this.initializers = initializers;
5891                         this.rank = rank;
5892                         loc = l;
5893
5894                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5895                         //
5896                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5897                         //
5898                         //dimensions = tmp.Length - 1;
5899                         expect_initializers = true;
5900                 }
5901
5902                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5903                 {
5904                         StringBuilder sb = new StringBuilder (rank);
5905                         
5906                         sb.Append ("[");
5907                         for (int i = 1; i < idx_count; i++)
5908                                 sb.Append (",");
5909                         
5910                         sb.Append ("]");
5911
5912                         return new ComposedCast (base_type, sb.ToString (), loc);
5913                 }
5914
5915                 void Error_IncorrectArrayInitializer ()
5916                 {
5917                         Error (178, "Incorrectly structured array initializer");
5918                 }
5919                 
5920                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5921                 {
5922                         if (specified_dims) { 
5923                                 Argument a = (Argument) arguments [idx];
5924                                 
5925                                 if (!a.Resolve (ec, loc))
5926                                         return false;
5927                                 
5928                                 if (!(a.Expr is Constant)) {
5929                                         Error (150, "A constant value is expected");
5930                                         return false;
5931                                 }
5932                                 
5933                                 int value = (int) ((Constant) a.Expr).GetValue ();
5934                                 
5935                                 if (value != probe.Count) {
5936                                         Error_IncorrectArrayInitializer ();
5937                                         return false;
5938                                 }
5939                                 
5940                                 bounds [idx] = value;
5941                         }
5942
5943                         int child_bounds = -1;
5944                         foreach (object o in probe) {
5945                                 if (o is ArrayList) {
5946                                         int current_bounds = ((ArrayList) o).Count;
5947                                         
5948                                         if (child_bounds == -1) 
5949                                                 child_bounds = current_bounds;
5950
5951                                         else if (child_bounds != current_bounds){
5952                                                 Error_IncorrectArrayInitializer ();
5953                                                 return false;
5954                                         }
5955                                         if (specified_dims && (idx + 1 >= arguments.Count)){
5956                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5957                                                 return false;
5958                                         }
5959                                         
5960                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5961                                         if (!ret)
5962                                                 return false;
5963                                 } else {
5964                                         if (child_bounds != -1){
5965                                                 Error_IncorrectArrayInitializer ();
5966                                                 return false;
5967                                         }
5968                                         
5969                                         Expression tmp = (Expression) o;
5970                                         tmp = tmp.Resolve (ec);
5971                                         if (tmp == null)
5972                                                 continue;
5973
5974                                         // Console.WriteLine ("I got: " + tmp);
5975                                         // Handle initialization from vars, fields etc.
5976
5977                                         Expression conv = Convert.ImplicitConversionRequired (
5978                                                 ec, tmp, underlying_type, loc);
5979                                         
5980                                         if (conv == null) 
5981                                                 return false;
5982
5983                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
5984                                                 // These are subclasses of Constant that can appear as elements of an
5985                                                 // array that cannot be statically initialized (with num_automatic_initializers
5986                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
5987                                                 array_data.Add (conv);
5988                                         } else if (conv is Constant) {
5989                                                 // These are the types of Constant that can appear in arrays that can be
5990                                                 // statically allocated.
5991                                                 array_data.Add (conv);
5992                                                 num_automatic_initializers++;
5993                                         } else
5994                                                 array_data.Add (conv);
5995                                 }
5996                         }
5997
5998                         return true;
5999                 }
6000                 
6001                 public void UpdateIndices (EmitContext ec)
6002                 {
6003                         int i = 0;
6004                         for (ArrayList probe = initializers; probe != null;) {
6005                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6006                                         Expression e = new IntConstant (probe.Count);
6007                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6008
6009                                         bounds [i++] =  probe.Count;
6010                                         
6011                                         probe = (ArrayList) probe [0];
6012                                         
6013                                 } else {
6014                                         Expression e = new IntConstant (probe.Count);
6015                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6016
6017                                         bounds [i++] = probe.Count;
6018                                         probe = null;
6019                                 }
6020                         }
6021
6022                 }
6023                 
6024                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6025                 {
6026                         if (initializers == null) {
6027                                 if (expect_initializers)
6028                                         return false;
6029                                 else
6030                                         return true;
6031                         }
6032                         
6033                         if (underlying_type == null)
6034                                 return false;
6035                         
6036                         //
6037                         // We use this to store all the date values in the order in which we
6038                         // will need to store them in the byte blob later
6039                         //
6040                         array_data = new ArrayList ();
6041                         bounds = new Hashtable ();
6042                         
6043                         bool ret;
6044
6045                         if (arguments != null) {
6046                                 ret = CheckIndices (ec, initializers, 0, true);
6047                                 return ret;
6048                         } else {
6049                                 arguments = new ArrayList ();
6050
6051                                 ret = CheckIndices (ec, initializers, 0, false);
6052                                 
6053                                 if (!ret)
6054                                         return false;
6055                                 
6056                                 UpdateIndices (ec);
6057                                 
6058                                 if (arguments.Count != dimensions) {
6059                                         Error_IncorrectArrayInitializer ();
6060                                         return false;
6061                                 }
6062
6063                                 return ret;
6064                         }
6065                 }
6066
6067                 void Error_NegativeArrayIndex ()
6068                 {
6069                         Error (284, "Can not create array with a negative size");
6070                 }
6071                 
6072                 //
6073                 // Converts `source' to an int, uint, long or ulong.
6074                 //
6075                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6076                 {
6077                         Expression target;
6078                         
6079                         bool old_checked = ec.CheckState;
6080                         ec.CheckState = true;
6081                         
6082                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6083                         if (target == null){
6084                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6085                                 if (target == null){
6086                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6087                                         if (target == null){
6088                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6089                                                 if (target == null)
6090                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6091                                         }
6092                                 }
6093                         } 
6094                         ec.CheckState = old_checked;
6095
6096                         //
6097                         // Only positive constants are allowed at compile time
6098                         //
6099                         if (target is Constant){
6100                                 if (target is IntConstant){
6101                                         if (((IntConstant) target).Value < 0){
6102                                                 Error_NegativeArrayIndex ();
6103                                                 return null;
6104                                         }
6105                                 }
6106
6107                                 if (target is LongConstant){
6108                                         if (((LongConstant) target).Value < 0){
6109                                                 Error_NegativeArrayIndex ();
6110                                                 return null;
6111                                         }
6112                                 }
6113                                 
6114                         }
6115
6116                         return target;
6117                 }
6118
6119                 //
6120                 // Creates the type of the array
6121                 //
6122                 bool LookupType (EmitContext ec)
6123                 {
6124                         StringBuilder array_qualifier = new StringBuilder (rank);
6125
6126                         //
6127                         // `In the first form allocates an array instace of the type that results
6128                         // from deleting each of the individual expression from the expression list'
6129                         //
6130                         if (num_arguments > 0) {
6131                                 array_qualifier.Append ("[");
6132                                 for (int i = num_arguments-1; i > 0; i--)
6133                                         array_qualifier.Append (",");
6134                                 array_qualifier.Append ("]");                           
6135                         }
6136
6137                         //
6138                         // Lookup the type
6139                         //
6140                         Expression array_type_expr;
6141                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6142                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
6143
6144                         if (type == null)
6145                                 return false;
6146
6147                         underlying_type = type;
6148                         if (underlying_type.IsArray)
6149                                 underlying_type = TypeManager.GetElementType (underlying_type);
6150                         dimensions = type.GetArrayRank ();
6151
6152                         return true;
6153                 }
6154                 
6155                 public override Expression DoResolve (EmitContext ec)
6156                 {
6157                         int arg_count;
6158
6159                         if (!LookupType (ec))
6160                                 return null;
6161                         
6162                         //
6163                         // First step is to validate the initializers and fill
6164                         // in any missing bits
6165                         //
6166                         if (!ValidateInitializers (ec, type))
6167                                 return null;
6168
6169                         if (arguments == null)
6170                                 arg_count = 0;
6171                         else {
6172                                 arg_count = arguments.Count;
6173                                 foreach (Argument a in arguments){
6174                                         if (!a.Resolve (ec, loc))
6175                                                 return null;
6176
6177                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6178                                         if (real_arg == null)
6179                                                 return null;
6180
6181                                         a.Expr = real_arg;
6182                                 }
6183                         }
6184                         
6185                         array_element_type = TypeManager.GetElementType (type);
6186
6187                         if (arg_count == 1) {
6188                                 is_one_dimensional = true;
6189                                 eclass = ExprClass.Value;
6190                                 return this;
6191                         }
6192
6193                         is_builtin_type = TypeManager.IsBuiltinType (type);
6194
6195                         if (is_builtin_type) {
6196                                 Expression ml;
6197                                 
6198                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6199                                                    AllBindingFlags, loc);
6200                                 
6201                                 if (!(ml is MethodGroupExpr)) {
6202                                         ml.Error_UnexpectedKind ("method group");
6203                                         return null;
6204                                 }
6205                                 
6206                                 if (ml == null) {
6207                                         Error (-6, "New invocation: Can not find a constructor for " +
6208                                                       "this argument list");
6209                                         return null;
6210                                 }
6211                                 
6212                                 new_method = Invocation.OverloadResolve (
6213                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6214
6215                                 if (new_method == null) {
6216                                         Error (-6, "New invocation: Can not find a constructor for " +
6217                                                       "this argument list");
6218                                         return null;
6219                                 }
6220                                 
6221                                 eclass = ExprClass.Value;
6222                                 return this;
6223                         } else {
6224                                 ModuleBuilder mb = CodeGen.Module.Builder;
6225                                 ArrayList args = new ArrayList ();
6226                                 
6227                                 if (arguments != null) {
6228                                         for (int i = 0; i < arg_count; i++)
6229                                                 args.Add (TypeManager.int32_type);
6230                                 }
6231                                 
6232                                 Type [] arg_types = null;
6233
6234                                 if (args.Count > 0)
6235                                         arg_types = new Type [args.Count];
6236                                 
6237                                 args.CopyTo (arg_types, 0);
6238                                 
6239                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6240                                                             arg_types);
6241
6242                                 if (new_method == null) {
6243                                         Error (-6, "New invocation: Can not find a constructor for " +
6244                                                       "this argument list");
6245                                         return null;
6246                                 }
6247                                 
6248                                 eclass = ExprClass.Value;
6249                                 return this;
6250                         }
6251                 }
6252
6253                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6254                 {
6255                         int factor;
6256                         byte [] data;
6257                         byte [] element;
6258                         int count = array_data.Count;
6259
6260                         if (underlying_type.IsEnum)
6261                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6262                         
6263                         factor = GetTypeSize (underlying_type);
6264                         if (factor == 0)
6265                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6266
6267                         data = new byte [(count * factor + 4) & ~3];
6268                         int idx = 0;
6269                         
6270                         for (int i = 0; i < count; ++i) {
6271                                 object v = array_data [i];
6272
6273                                 if (v is EnumConstant)
6274                                         v = ((EnumConstant) v).Child;
6275                                 
6276                                 if (v is Constant && !(v is StringConstant))
6277                                         v = ((Constant) v).GetValue ();
6278                                 else {
6279                                         idx += factor;
6280                                         continue;
6281                                 }
6282                                 
6283                                 if (underlying_type == TypeManager.int64_type){
6284                                         if (!(v is Expression)){
6285                                                 long val = (long) v;
6286                                                 
6287                                                 for (int j = 0; j < factor; ++j) {
6288                                                         data [idx + j] = (byte) (val & 0xFF);
6289                                                         val = (val >> 8);
6290                                                 }
6291                                         }
6292                                 } else if (underlying_type == TypeManager.uint64_type){
6293                                         if (!(v is Expression)){
6294                                                 ulong val = (ulong) v;
6295
6296                                                 for (int j = 0; j < factor; ++j) {
6297                                                         data [idx + j] = (byte) (val & 0xFF);
6298                                                         val = (val >> 8);
6299                                                 }
6300                                         }
6301                                 } else if (underlying_type == TypeManager.float_type) {
6302                                         if (!(v is Expression)){
6303                                                 element = BitConverter.GetBytes ((float) v);
6304                                                         
6305                                                 for (int j = 0; j < factor; ++j)
6306                                                         data [idx + j] = element [j];
6307                                         }
6308                                 } else if (underlying_type == TypeManager.double_type) {
6309                                         if (!(v is Expression)){
6310                                                 element = BitConverter.GetBytes ((double) v);
6311
6312                                                 for (int j = 0; j < factor; ++j)
6313                                                         data [idx + j] = element [j];
6314                                         }
6315                                 } else if (underlying_type == TypeManager.char_type){
6316                                         if (!(v is Expression)){
6317                                                 int val = (int) ((char) v);
6318                                                 
6319                                                 data [idx] = (byte) (val & 0xff);
6320                                                 data [idx+1] = (byte) (val >> 8);
6321                                         }
6322                                 } else if (underlying_type == TypeManager.short_type){
6323                                         if (!(v is Expression)){
6324                                                 int val = (int) ((short) v);
6325                                         
6326                                                 data [idx] = (byte) (val & 0xff);
6327                                                 data [idx+1] = (byte) (val >> 8);
6328                                         }
6329                                 } else if (underlying_type == TypeManager.ushort_type){
6330                                         if (!(v is Expression)){
6331                                                 int val = (int) ((ushort) v);
6332                                         
6333                                                 data [idx] = (byte) (val & 0xff);
6334                                                 data [idx+1] = (byte) (val >> 8);
6335                                         }
6336                                 } else if (underlying_type == TypeManager.int32_type) {
6337                                         if (!(v is Expression)){
6338                                                 int val = (int) v;
6339                                         
6340                                                 data [idx]   = (byte) (val & 0xff);
6341                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6342                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6343                                                 data [idx+3] = (byte) (val >> 24);
6344                                         }
6345                                 } else if (underlying_type == TypeManager.uint32_type) {
6346                                         if (!(v is Expression)){
6347                                                 uint val = (uint) v;
6348                                         
6349                                                 data [idx]   = (byte) (val & 0xff);
6350                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6351                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6352                                                 data [idx+3] = (byte) (val >> 24);
6353                                         }
6354                                 } else if (underlying_type == TypeManager.sbyte_type) {
6355                                         if (!(v is Expression)){
6356                                                 sbyte val = (sbyte) v;
6357                                                 data [idx] = (byte) val;
6358                                         }
6359                                 } else if (underlying_type == TypeManager.byte_type) {
6360                                         if (!(v is Expression)){
6361                                                 byte val = (byte) v;
6362                                                 data [idx] = (byte) val;
6363                                         }
6364                                 } else if (underlying_type == TypeManager.bool_type) {
6365                                         if (!(v is Expression)){
6366                                                 bool val = (bool) v;
6367                                                 data [idx] = (byte) (val ? 1 : 0);
6368                                         }
6369                                 } else if (underlying_type == TypeManager.decimal_type){
6370                                         if (!(v is Expression)){
6371                                                 int [] bits = Decimal.GetBits ((decimal) v);
6372                                                 int p = idx;
6373
6374                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6375                                                 int [] nbits = new int [4];
6376                                                 nbits [0] = bits [3];
6377                                                 nbits [1] = bits [2];
6378                                                 nbits [2] = bits [0];
6379                                                 nbits [3] = bits [1];
6380                                                 
6381                                                 for (int j = 0; j < 4; j++){
6382                                                         data [p++] = (byte) (nbits [j] & 0xff);
6383                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6384                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6385                                                         data [p++] = (byte) (nbits [j] >> 24);
6386                                                 }
6387                                         }
6388                                 } else
6389                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6390
6391                                 idx += factor;
6392                         }
6393
6394                         return data;
6395                 }
6396
6397                 //
6398                 // Emits the initializers for the array
6399                 //
6400                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
6401                 {
6402                         //
6403                         // First, the static data
6404                         //
6405                         FieldBuilder fb;
6406                         ILGenerator ig = ec.ig;
6407                         
6408                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6409
6410                         fb = RootContext.MakeStaticData (data);
6411
6412                         if (is_expression)
6413                                 ig.Emit (OpCodes.Dup);
6414                         ig.Emit (OpCodes.Ldtoken, fb);
6415                         ig.Emit (OpCodes.Call,
6416                                  TypeManager.void_initializearray_array_fieldhandle);
6417                 }
6418
6419                 //
6420                 // Emits pieces of the array that can not be computed at compile
6421                 // time (variables and string locations).
6422                 //
6423                 // This always expect the top value on the stack to be the array
6424                 //
6425                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
6426                 {
6427                         ILGenerator ig = ec.ig;
6428                         int dims = bounds.Count;
6429                         int [] current_pos = new int [dims];
6430                         int top = array_data.Count;
6431                         LocalBuilder temp = ig.DeclareLocal (type);
6432
6433                         ig.Emit (OpCodes.Stloc, temp);
6434
6435                         MethodInfo set = null;
6436
6437                         if (dims != 1){
6438                                 Type [] args;
6439                                 ModuleBuilder mb = null;
6440                                 mb = CodeGen.Module.Builder;
6441                                 args = new Type [dims + 1];
6442
6443                                 int j;
6444                                 for (j = 0; j < dims; j++)
6445                                         args [j] = TypeManager.int32_type;
6446
6447                                 args [j] = array_element_type;
6448                                 
6449                                 set = mb.GetArrayMethod (
6450                                         type, "Set",
6451                                         CallingConventions.HasThis | CallingConventions.Standard,
6452                                         TypeManager.void_type, args);
6453                         }
6454                         
6455                         for (int i = 0; i < top; i++){
6456
6457                                 Expression e = null;
6458
6459                                 if (array_data [i] is Expression)
6460                                         e = (Expression) array_data [i];
6461
6462                                 if (e != null) {
6463                                         //
6464                                         // Basically we do this for string literals and
6465                                         // other non-literal expressions
6466                                         //
6467                                         if (e is EnumConstant){
6468                                                 e = ((EnumConstant) e).Child;
6469                                         }
6470                                         
6471                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6472                                             num_automatic_initializers <= max_automatic_initializers) {
6473                                                 Type etype = e.Type;
6474                                                 
6475                                                 ig.Emit (OpCodes.Ldloc, temp);
6476
6477                                                 for (int idx = 0; idx < dims; idx++) 
6478                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6479
6480                                                 //
6481                                                 // If we are dealing with a struct, get the
6482                                                 // address of it, so we can store it.
6483                                                 //
6484                                                 if ((dims == 1) && 
6485                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6486                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6487                                                      etype == TypeManager.decimal_type)) {
6488                                                         if (e is New){
6489                                                                 New n = (New) e;
6490
6491                                                                 //
6492                                                                 // Let new know that we are providing
6493                                                                 // the address where to store the results
6494                                                                 //
6495                                                                 n.DisableTemporaryValueType ();
6496                                                         }
6497
6498                                                         ig.Emit (OpCodes.Ldelema, etype);
6499                                                 }
6500
6501                                                 e.Emit (ec);
6502
6503                                                 if (dims == 1)
6504                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
6505                                                 else 
6506                                                         ig.Emit (OpCodes.Call, set);
6507                                                 
6508                                         }
6509                                 }
6510                                 
6511                                 //
6512                                 // Advance counter
6513                                 //
6514                                 for (int j = dims - 1; j >= 0; j--){
6515                                         current_pos [j]++;
6516                                         if (current_pos [j] < (int) bounds [j])
6517                                                 break;
6518                                         current_pos [j] = 0;
6519                                 }
6520                         }
6521
6522                         if (is_expression)
6523                                 ig.Emit (OpCodes.Ldloc, temp);
6524                 }
6525
6526                 void EmitArrayArguments (EmitContext ec)
6527                 {
6528                         ILGenerator ig = ec.ig;
6529                         
6530                         foreach (Argument a in arguments) {
6531                                 Type atype = a.Type;
6532                                 a.Emit (ec);
6533
6534                                 if (atype == TypeManager.uint64_type)
6535                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6536                                 else if (atype == TypeManager.int64_type)
6537                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6538                         }
6539                 }
6540                 
6541                 void DoEmit (EmitContext ec, bool is_statement)
6542                 {
6543                         ILGenerator ig = ec.ig;
6544                         
6545                         EmitArrayArguments (ec);
6546                         if (is_one_dimensional)
6547                                 ig.Emit (OpCodes.Newarr, array_element_type);
6548                         else {
6549                                 if (is_builtin_type) 
6550                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6551                                 else 
6552                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6553                         }
6554                         
6555                         if (initializers != null){
6556                                 //
6557                                 // FIXME: Set this variable correctly.
6558                                 // 
6559                                 bool dynamic_initializers = true;
6560
6561                                 // This will never be true for array types that cannot be statically
6562                                 // initialized. num_automatic_initializers will always be zero.  See
6563                                 // CheckIndices.
6564                                         if (num_automatic_initializers > max_automatic_initializers)
6565                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
6566                                 
6567                                 if (dynamic_initializers)
6568                                         EmitDynamicInitializers (ec, !is_statement);
6569                         }
6570                 }
6571                 
6572                 public override void Emit (EmitContext ec)
6573                 {
6574                         DoEmit (ec, false);
6575                 }
6576
6577                 public override void EmitStatement (EmitContext ec)
6578                 {
6579                         DoEmit (ec, true);
6580                 }
6581
6582                 public object EncodeAsAttribute ()
6583                 {
6584                         if (!is_one_dimensional){
6585                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6586                                 return null;
6587                         }
6588
6589                         if (array_data == null){
6590                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6591                                 return null;
6592                         }
6593                         
6594                         object [] ret = new object [array_data.Count];
6595                         int i = 0;
6596                         foreach (Expression e in array_data){
6597                                 object v;
6598                                 
6599                                 if (e is NullLiteral)
6600                                         v = null;
6601                                 else {
6602                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
6603                                                 return null;
6604                                 }
6605                                 ret [i++] = v;
6606                         }
6607                         return ret;
6608                 }
6609
6610                 public Expression TurnIntoConstant ()
6611                 {
6612                         //
6613                         // Should use something like the above attribute thing.
6614                         // It should return a subclass of Constant that just returns
6615                         // the computed value of the array
6616                         //
6617                         throw new Exception ("Does not support yet Turning array into a Constant");
6618                 }
6619         }
6620         
6621         /// <summary>
6622         ///   Represents the `this' construct
6623         /// </summary>
6624         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6625
6626                 Block block;
6627                 VariableInfo variable_info;
6628                 
6629                 public This (Block block, Location loc)
6630                 {
6631                         this.loc = loc;
6632                         this.block = block;
6633                 }
6634
6635                 public This (Location loc)
6636                 {
6637                         this.loc = loc;
6638                 }
6639
6640                 public VariableInfo VariableInfo {
6641                         get { return variable_info; }
6642                 }
6643
6644                 public bool VerifyFixed (bool is_expression)
6645                 {
6646                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6647                                 return false;
6648                         else
6649                                 return variable_info.LocalInfo.IsFixed;
6650                 }
6651
6652                 public bool ResolveBase (EmitContext ec)
6653                 {
6654                         eclass = ExprClass.Variable;
6655
6656                         if (ec.TypeContainer.CurrentType != null)
6657                                 type = ec.TypeContainer.CurrentType.ResolveType (ec);
6658                         else
6659                                 type = ec.ContainerType;
6660
6661                         if (ec.IsStatic) {
6662                                 Error (26, "Keyword this not valid in static code");
6663                                 return false;
6664                         }
6665
6666                         if ((block != null) && (block.ThisVariable != null))
6667                                 variable_info = block.ThisVariable.VariableInfo;
6668
6669                         return true;
6670                 }
6671
6672                 public override Expression DoResolve (EmitContext ec)
6673                 {
6674                         if (!ResolveBase (ec))
6675                                 return null;
6676
6677                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6678                                 Error (188, "The this object cannot be used before all " +
6679                                        "of its fields are assigned to");
6680                                 variable_info.SetAssigned (ec);
6681                                 return this;
6682                         }
6683
6684                         if (ec.IsFieldInitializer) {
6685                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6686                                        "a method or a property.");
6687                                 return null;
6688                         }
6689
6690                         return this;
6691                 }
6692
6693                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6694                 {
6695                         if (!ResolveBase (ec))
6696                                 return null;
6697
6698                         if (variable_info != null)
6699                                 variable_info.SetAssigned (ec);
6700                         
6701                         if (ec.TypeContainer is Class){
6702                                 Error (1604, "Cannot assign to `this'");
6703                                 return null;
6704                         }
6705
6706                         return this;
6707                 }
6708
6709                 public override void Emit (EmitContext ec)
6710                 {
6711                         ILGenerator ig = ec.ig;
6712                         
6713                         ig.Emit (OpCodes.Ldarg_0);
6714                         if (ec.TypeContainer is Struct)
6715                                 ig.Emit (OpCodes.Ldobj, type);
6716                 }
6717
6718                 public void EmitAssign (EmitContext ec, Expression source)
6719                 {
6720                         ILGenerator ig = ec.ig;
6721                         
6722                         if (ec.TypeContainer is Struct){
6723                                 ig.Emit (OpCodes.Ldarg_0);
6724                                 source.Emit (ec);
6725                                 ig.Emit (OpCodes.Stobj, type);
6726                         } else {
6727                                 source.Emit (ec);
6728                                 ig.Emit (OpCodes.Starg, 0);
6729                         }
6730                 }
6731
6732                 public void AddressOf (EmitContext ec, AddressOp mode)
6733                 {
6734                         ec.ig.Emit (OpCodes.Ldarg_0);
6735
6736                         // FIMXE
6737                         // FIGURE OUT WHY LDARG_S does not work
6738                         //
6739                         // consider: struct X { int val; int P { set { val = value; }}}
6740                         //
6741                         // Yes, this looks very bad. Look at `NOTAS' for
6742                         // an explanation.
6743                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6744                 }
6745         }
6746
6747         //
6748         // This produces the value that renders an instance, used by the iterators code
6749         //
6750         public class ProxyInstance : Expression, IMemoryLocation  {
6751                 public override Expression DoResolve (EmitContext ec)
6752                 {
6753                         eclass = ExprClass.Variable;
6754                         type = ec.ContainerType;
6755                         return this;
6756                 }
6757                 
6758                 public override void Emit (EmitContext ec)
6759                 {
6760                         ec.ig.Emit (OpCodes.Ldarg_0);
6761
6762                 }
6763                 
6764                 public void AddressOf (EmitContext ec, AddressOp mode)
6765                 {
6766                         ec.ig.Emit (OpCodes.Ldarg_0);
6767                 }
6768         }
6769
6770         /// <summary>
6771         ///   Implements the typeof operator
6772         /// </summary>
6773         public class TypeOf : Expression {
6774                 public readonly Expression QueriedType;
6775                 protected Type typearg;
6776                 
6777                 public TypeOf (Expression queried_type, Location l)
6778                 {
6779                         QueriedType = queried_type;
6780                         loc = l;
6781                 }
6782
6783                 public override Expression DoResolve (EmitContext ec)
6784                 {
6785                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6786
6787                         if (typearg == null)
6788                                 return null;
6789
6790                         if (typearg == TypeManager.void_type) {
6791                                 Error (673, "System.Void cannot be used from C# - " +
6792                                        "use typeof (void) to get the void type object");
6793                                 return null;
6794                         }
6795
6796                         type = TypeManager.type_type;
6797                         eclass = ExprClass.Type;
6798                         return this;
6799                 }
6800
6801                 public override void Emit (EmitContext ec)
6802                 {
6803                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6804                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6805                 }
6806
6807                 public Type TypeArg { 
6808                         get { return typearg; }
6809                 }
6810         }
6811
6812         /// <summary>
6813         ///   Implements the `typeof (void)' operator
6814         /// </summary>
6815         public class TypeOfVoid : TypeOf {
6816                 public TypeOfVoid (Location l) : base (null, l)
6817                 {
6818                         loc = l;
6819                 }
6820
6821                 public override Expression DoResolve (EmitContext ec)
6822                 {
6823                         type = TypeManager.type_type;
6824                         typearg = TypeManager.void_type;
6825                         eclass = ExprClass.Type;
6826                         return this;
6827                 }
6828         }
6829
6830         /// <summary>
6831         ///   Implements the sizeof expression
6832         /// </summary>
6833         public class SizeOf : Expression {
6834                 public Expression QueriedType;
6835                 Type type_queried;
6836                 
6837                 public SizeOf (Expression queried_type, Location l)
6838                 {
6839                         this.QueriedType = queried_type;
6840                         loc = l;
6841                 }
6842
6843                 public override Expression DoResolve (EmitContext ec)
6844                 {
6845                         if (!ec.InUnsafe) {
6846                                 Report.Error (
6847                                         233, loc, "Sizeof may only be used in an unsafe context " +
6848                                         "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
6849                                 return null;
6850                         }
6851                                 
6852                         QueriedType = ec.DeclSpace.ResolveTypeExpr (QueriedType, false, loc);
6853                         if (QueriedType == null || QueriedType.Type == null)
6854                                 return null;
6855
6856                         if (QueriedType is TypeParameterExpr){
6857                                 ((TypeParameterExpr)QueriedType).Error_CannotUseAsUnmanagedType (loc);
6858                                 return null;
6859                         }
6860
6861                         type_queried = QueriedType.Type;
6862                         if (!TypeManager.IsUnmanagedType (type_queried)){
6863                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6864                                 return null;
6865                         }
6866                         
6867                         type = TypeManager.int32_type;
6868                         eclass = ExprClass.Value;
6869                         return this;
6870                 }
6871
6872                 public override void Emit (EmitContext ec)
6873                 {
6874                         int size = GetTypeSize (type_queried);
6875
6876                         if (size == 0)
6877                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6878                         else
6879                                 IntConstant.EmitInt (ec.ig, size);
6880                 }
6881         }
6882
6883         /// <summary>
6884         ///   Implements the member access expression
6885         /// </summary>
6886         public class MemberAccess : Expression {
6887                 public readonly string Identifier;
6888                 public readonly int NumTypeArguments;
6889                 protected Expression expr;
6890                 
6891                 public MemberAccess (Expression expr, string id, Location l)
6892                 {
6893                         this.expr = expr;
6894                         Identifier = id;
6895                         loc = l;
6896                 }
6897
6898                 protected MemberAccess (Expression expr, string id, int num_type_args,
6899                                         Location l)
6900                         : this (expr, id, l)
6901                 {
6902                         NumTypeArguments = num_type_args;
6903                 }
6904
6905                 public Expression Expr {
6906                         get {
6907                                 return expr;
6908                         }
6909                 }
6910
6911                 static void error176 (Location loc, string name)
6912                 {
6913                         Report.Error (176, loc, "Static member `" +
6914                                       name + "' cannot be accessed " +
6915                                       "with an instance reference, qualify with a " +
6916                                       "type name instead");
6917                 }
6918
6919                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6920                 {
6921                         if (left_original == null)
6922                                 return false;
6923
6924                         if (!(left_original is SimpleName))
6925                                 return false;
6926
6927                         SimpleName sn = (SimpleName) left_original;
6928
6929                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6930                         if (t != null)
6931                                 return true;
6932
6933                         return false;
6934                 }
6935                 
6936                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6937                                                               Expression left, Location loc,
6938                                                               Expression left_original)
6939                 {
6940                         bool left_is_type, left_is_explicit;
6941
6942                         // If `left' is null, then we're called from SimpleNameResolve and this is
6943                         // a member in the currently defining class.
6944                         if (left == null) {
6945                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6946                                 left_is_explicit = false;
6947
6948                                 // Implicitly default to `this' unless we're static.
6949                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6950                                         left = ec.GetThis (loc);
6951                         } else {
6952                                 left_is_type = left is TypeExpr;
6953                                 left_is_explicit = true;
6954                         }
6955
6956                         if (member_lookup is FieldExpr){
6957                                 FieldExpr fe = (FieldExpr) member_lookup;
6958                                 FieldInfo fi = fe.FieldInfo;
6959                                 Type decl_type = fi.DeclaringType;
6960
6961                                 if (fi is FieldBuilder) {
6962                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6963                                         
6964                                         if (c != null) {
6965                                                 object o = c.LookupConstantValue ();
6966                                                 if (o == null)
6967                                                         return null;
6968                                                 
6969                                                 object real_value = ((Constant) c.Expr).GetValue ();
6970
6971                                                 return Constantify (real_value, fi.FieldType);
6972                                         }
6973                                 }
6974
6975                                 if (fi.IsLiteral) {
6976                                         Type t = fi.FieldType;
6977                                         
6978                                         object o;
6979
6980                                         if (fi is FieldBuilder)
6981                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
6982                                         else
6983                                                 o = fi.GetValue (fi);
6984                                         
6985                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6986                                                 if (left_is_explicit && !left_is_type &&
6987                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {
6988                                                         error176 (loc, fe.FieldInfo.Name);
6989                                                         return null;
6990                                                 }                                       
6991                                                 
6992                                                 Expression enum_member = MemberLookup (
6993                                                         ec, decl_type, "value__", MemberTypes.Field,
6994                                                         AllBindingFlags, loc); 
6995
6996                                                 Enum en = TypeManager.LookupEnum (decl_type);
6997
6998                                                 Constant c;
6999                                                 if (en != null)
7000                                                         c = Constantify (o, en.UnderlyingType);
7001                                                 else 
7002                                                         c = Constantify (o, enum_member.Type);
7003                                                 
7004                                                 return new EnumConstant (c, decl_type);
7005                                         }
7006                                         
7007                                         Expression exp = Constantify (o, t);
7008
7009                                         if (left_is_explicit && !left_is_type) {
7010                                                 error176 (loc, fe.FieldInfo.Name);
7011                                                 return null;
7012                                         }
7013                                         
7014                                         return exp;
7015                                 }
7016
7017                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
7018                                         UnsafeError (loc);
7019                                         return null;
7020                                 }
7021                         }
7022
7023                         if (member_lookup is EventExpr) {
7024                                 EventExpr ee = (EventExpr) member_lookup;
7025                                 
7026                                 //
7027                                 // If the event is local to this class, we transform ourselves into
7028                                 // a FieldExpr
7029                                 //
7030
7031                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7032                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7033                                         MemberInfo mi = GetFieldFromEvent (ee);
7034
7035                                         if (mi == null) {
7036                                                 //
7037                                                 // If this happens, then we have an event with its own
7038                                                 // accessors and private field etc so there's no need
7039                                                 // to transform ourselves.
7040                                                 //
7041                                                 return ee;
7042                                         }
7043
7044                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7045                                         
7046                                         if (ml == null) {
7047                                                 Report.Error (-200, loc, "Internal error!!");
7048                                                 return null;
7049                                         }
7050
7051                                         if (!left_is_explicit)
7052                                                 left = null;
7053                                         
7054                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7055                                 }
7056                         }
7057
7058                         if (member_lookup is IMemberExpr) {
7059                                 IMemberExpr me = (IMemberExpr) member_lookup;
7060
7061                                 if (left_is_type){
7062                                         MethodGroupExpr mg = me as MethodGroupExpr;
7063                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7064                                                 mg.IsExplicitImpl = left_is_explicit;
7065
7066                                         if (!me.IsStatic){
7067                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7068                                                     IdenticalNameAndTypeName (ec, left_original, loc))
7069                                                         return member_lookup;
7070
7071                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7072                                                 return null;
7073                                         }
7074
7075                                 } else {
7076                                         if (!me.IsInstance){
7077                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
7078                                                         return member_lookup;
7079
7080                                                 if (left_is_explicit) {
7081                                                         error176 (loc, me.Name);
7082                                                         return null;
7083                                                 }
7084                                         }
7085
7086                                         //
7087                                         // Since we can not check for instance objects in SimpleName,
7088                                         // becaue of the rule that allows types and variables to share
7089                                         // the name (as long as they can be de-ambiguated later, see 
7090                                         // IdenticalNameAndTypeName), we have to check whether left 
7091                                         // is an instance variable in a static context
7092                                         //
7093                                         // However, if the left-hand value is explicitly given, then
7094                                         // it is already our instance expression, so we aren't in
7095                                         // static context.
7096                                         //
7097
7098                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7099                                                 IMemberExpr mexp = (IMemberExpr) left;
7100
7101                                                 if (!mexp.IsStatic){
7102                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7103                                                         return null;
7104                                                 }
7105                                         }
7106
7107                                         me.InstanceExpression = left;
7108                                 }
7109
7110                                 return member_lookup;
7111                         }
7112
7113                         Console.WriteLine ("Left is: " + left);
7114                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7115                         Environment.Exit (0);
7116                         return null;
7117                 }
7118                 
7119                 public virtual Expression DoResolve (EmitContext ec, Expression right_side,
7120                                                      ResolveFlags flags)
7121                 {
7122                         if (type != null)
7123                                 throw new Exception ();
7124
7125                         //
7126                         // Resolve the expression with flow analysis turned off, we'll do the definite
7127                         // assignment checks later.  This is because we don't know yet what the expression
7128                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7129                         // definite assignment check on the actual field and not on the whole struct.
7130                         //
7131
7132                         Expression original = expr;
7133                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
7134                         if (expr == null)
7135                                 return null;
7136
7137                         if (expr is SimpleName){
7138                                 SimpleName child_expr = (SimpleName) expr;
7139
7140                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7141
7142                                 return new_expr.Resolve (ec, flags);
7143                         }
7144                                         
7145                         //
7146                         // TODO: I mailed Ravi about this, and apparently we can get rid
7147                         // of this and put it in the right place.
7148                         // 
7149                         // Handle enums here when they are in transit.
7150                         // Note that we cannot afford to hit MemberLookup in this case because
7151                         // it will fail to find any members at all
7152                         //
7153
7154                         Type expr_type;
7155                         if (expr is TypeExpr){
7156                                 expr_type = ((TypeExpr) expr).ResolveType (ec);
7157
7158                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7159                                         Error (122, "`" + expr_type + "' " +
7160                                                "is inaccessible because of its protection level");
7161                                         return null;
7162                                 }
7163
7164                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7165                                         Enum en = TypeManager.LookupEnum (expr_type);
7166
7167                                         if (en != null) {
7168                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7169                                                 
7170                                                 if (value != null){
7171                                                         Constant c = Constantify (value, en.UnderlyingType);
7172                                                         return new EnumConstant (c, expr_type);
7173                                                 }
7174                                         }
7175                                 }
7176                         } else
7177                                 expr_type = expr.Type;
7178                         
7179                         if (expr_type.IsPointer){
7180                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7181                                        TypeManager.CSharpName (expr_type) + ")");
7182                                 return null;
7183                         }
7184
7185                         int real_num_type_args = NumTypeArguments +
7186                                 TypeManager.GetNumberOfTypeArguments (expr_type);
7187                         
7188                         Expression member_lookup;
7189                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type,
7190                                                            Identifier, real_num_type_args,
7191                                                            loc);
7192                         if (member_lookup == null)
7193                                 return null;
7194
7195                         if (member_lookup is TypeExpr) {
7196                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7197                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7198                                                member_lookup.Type + "' instead");
7199                                         return null;
7200                                 }
7201
7202                                 return member_lookup;
7203                         }
7204                         
7205                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7206                         if (member_lookup == null)
7207                                 return null;
7208
7209                         // The following DoResolve/DoResolveLValue will do the definite assignment
7210                         // check.
7211
7212                         if (right_side != null)
7213                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7214                         else
7215                                 member_lookup = member_lookup.DoResolve (ec);
7216
7217                         return member_lookup;
7218                 }
7219
7220                 public override Expression DoResolve (EmitContext ec)
7221                 {
7222                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7223                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7224                 }
7225
7226                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7227                 {
7228                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7229                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7230                 }
7231
7232                 public override Expression ResolveAsTypeStep (EmitContext ec)
7233                 {
7234                         string fname = null;
7235                         MemberAccess full_expr = this;
7236                         while (full_expr != null) {
7237                                 if (fname != null)
7238                                         fname = String.Concat (full_expr.Identifier, ".", fname);
7239                                 else
7240                                         fname = full_expr.Identifier;
7241
7242                                 if (full_expr.Expr is SimpleName) {
7243                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7244                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name, 0);
7245                                         if (fully_qualified != null)
7246                                                 return new TypeExpression (fully_qualified, loc);
7247                                 }
7248
7249                                 full_expr = full_expr.Expr as MemberAccess;
7250                         }
7251
7252                         Expression new_expr = expr.ResolveAsTypeStep (ec);
7253
7254                         if (new_expr == null)
7255                                 return null;
7256
7257                         if (new_expr is SimpleName){
7258                                 SimpleName child_expr = (SimpleName) new_expr;
7259                                 
7260                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7261
7262                                 return new_expr.ResolveAsTypeStep (ec);
7263                         }
7264
7265                         Type expr_type = ((TypeExpr) new_expr).ResolveType (ec);
7266
7267                         if (expr_type.IsPointer){
7268                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7269                                        TypeManager.CSharpName (expr_type) + ")");
7270                                 return null;
7271                         }
7272
7273                         int real_num_type_args = NumTypeArguments +
7274                                 TypeManager.GetNumberOfTypeArguments (expr_type);
7275                         
7276                         Expression member_lookup;
7277                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type,
7278                                                            Identifier, real_num_type_args,
7279                                                            loc);
7280                         if (member_lookup == null)
7281                                 return null;
7282
7283                         if (member_lookup is TypeExpr){
7284                                 member_lookup.Resolve (ec, ResolveFlags.Type);
7285                                 return member_lookup;
7286                         } 
7287
7288                         return null;                    
7289                 }
7290
7291                 public override void Emit (EmitContext ec)
7292                 {
7293                         throw new Exception ("Should not happen");
7294                 }
7295
7296                 public override string ToString ()
7297                 {
7298                         return expr + "." + Identifier;
7299                 }
7300         }
7301
7302         /// <summary>
7303         ///   Implements checked expressions
7304         /// </summary>
7305         public class CheckedExpr : Expression {
7306
7307                 public Expression Expr;
7308
7309                 public CheckedExpr (Expression e, Location l)
7310                 {
7311                         Expr = e;
7312                         loc = l;
7313                 }
7314
7315                 public override Expression DoResolve (EmitContext ec)
7316                 {
7317                         bool last_check = ec.CheckState;
7318                         bool last_const_check = ec.ConstantCheckState;
7319
7320                         ec.CheckState = true;
7321                         ec.ConstantCheckState = true;
7322                         Expr = Expr.Resolve (ec);
7323                         ec.CheckState = last_check;
7324                         ec.ConstantCheckState = last_const_check;
7325                         
7326                         if (Expr == null)
7327                                 return null;
7328
7329                         if (Expr is Constant)
7330                                 return Expr;
7331                         
7332                         eclass = Expr.eclass;
7333                         type = Expr.Type;
7334                         return this;
7335                 }
7336
7337                 public override void Emit (EmitContext ec)
7338                 {
7339                         bool last_check = ec.CheckState;
7340                         bool last_const_check = ec.ConstantCheckState;
7341                         
7342                         ec.CheckState = true;
7343                         ec.ConstantCheckState = true;
7344                         Expr.Emit (ec);
7345                         ec.CheckState = last_check;
7346                         ec.ConstantCheckState = last_const_check;
7347                 }
7348                 
7349         }
7350
7351         /// <summary>
7352         ///   Implements the unchecked expression
7353         /// </summary>
7354         public class UnCheckedExpr : Expression {
7355
7356                 public Expression Expr;
7357
7358                 public UnCheckedExpr (Expression e, Location l)
7359                 {
7360                         Expr = e;
7361                         loc = l;
7362                 }
7363
7364                 public override Expression DoResolve (EmitContext ec)
7365                 {
7366                         bool last_check = ec.CheckState;
7367                         bool last_const_check = ec.ConstantCheckState;
7368
7369                         ec.CheckState = false;
7370                         ec.ConstantCheckState = false;
7371                         Expr = Expr.Resolve (ec);
7372                         ec.CheckState = last_check;
7373                         ec.ConstantCheckState = last_const_check;
7374
7375                         if (Expr == null)
7376                                 return null;
7377
7378                         if (Expr is Constant)
7379                                 return Expr;
7380                         
7381                         eclass = Expr.eclass;
7382                         type = Expr.Type;
7383                         return this;
7384                 }
7385
7386                 public override void Emit (EmitContext ec)
7387                 {
7388                         bool last_check = ec.CheckState;
7389                         bool last_const_check = ec.ConstantCheckState;
7390                         
7391                         ec.CheckState = false;
7392                         ec.ConstantCheckState = false;
7393                         Expr.Emit (ec);
7394                         ec.CheckState = last_check;
7395                         ec.ConstantCheckState = last_const_check;
7396                 }
7397                 
7398         }
7399
7400         /// <summary>
7401         ///   An Element Access expression.
7402         ///
7403         ///   During semantic analysis these are transformed into 
7404         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7405         /// </summary>
7406         public class ElementAccess : Expression {
7407                 public ArrayList  Arguments;
7408                 public Expression Expr;
7409                 
7410                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7411                 {
7412                         Expr = e;
7413
7414                         loc  = l;
7415                         
7416                         if (e_list == null)
7417                                 return;
7418                         
7419                         Arguments = new ArrayList ();
7420                         foreach (Expression tmp in e_list)
7421                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7422                         
7423                 }
7424
7425                 bool CommonResolve (EmitContext ec)
7426                 {
7427                         Expr = Expr.Resolve (ec);
7428
7429                         if (Expr == null) 
7430                                 return false;
7431
7432                         if (Arguments == null)
7433                                 return false;
7434
7435                         foreach (Argument a in Arguments){
7436                                 if (!a.Resolve (ec, loc))
7437                                         return false;
7438                         }
7439
7440                         return true;
7441                 }
7442
7443                 Expression MakePointerAccess ()
7444                 {
7445                         Type t = Expr.Type;
7446
7447                         if (t == TypeManager.void_ptr_type){
7448                                 Error (242, "The array index operation is not valid for void pointers");
7449                                 return null;
7450                         }
7451                         if (Arguments.Count != 1){
7452                                 Error (196, "A pointer must be indexed by a single value");
7453                                 return null;
7454                         }
7455                         Expression p;
7456
7457                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
7458                         return new Indirection (p, loc);
7459                 }
7460                 
7461                 public override Expression DoResolve (EmitContext ec)
7462                 {
7463                         if (!CommonResolve (ec))
7464                                 return null;
7465
7466                         //
7467                         // We perform some simple tests, and then to "split" the emit and store
7468                         // code we create an instance of a different class, and return that.
7469                         //
7470                         // I am experimenting with this pattern.
7471                         //
7472                         Type t = Expr.Type;
7473
7474                         if (t == TypeManager.array_type){
7475                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7476                                 return null;
7477                         }
7478                         
7479                         if (t.IsArray)
7480                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7481                         else if (t.IsPointer)
7482                                 return MakePointerAccess ();
7483                         else
7484                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7485                 }
7486
7487                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7488                 {
7489                         if (!CommonResolve (ec))
7490                                 return null;
7491
7492                         Type t = Expr.Type;
7493                         if (t.IsArray)
7494                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7495                         else if (t.IsPointer)
7496                                 return MakePointerAccess ();
7497                         else
7498                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7499                 }
7500                 
7501                 public override void Emit (EmitContext ec)
7502                 {
7503                         throw new Exception ("Should never be reached");
7504                 }
7505         }
7506
7507         /// <summary>
7508         ///   Implements array access 
7509         /// </summary>
7510         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7511                 //
7512                 // Points to our "data" repository
7513                 //
7514                 ElementAccess ea;
7515
7516                 LocalTemporary [] cached_locations;
7517                 
7518                 public ArrayAccess (ElementAccess ea_data, Location l)
7519                 {
7520                         ea = ea_data;
7521                         eclass = ExprClass.Variable;
7522                         loc = l;
7523                 }
7524
7525                 public override Expression DoResolve (EmitContext ec)
7526                 {
7527 #if false
7528                         ExprClass eclass = ea.Expr.eclass;
7529
7530                         // As long as the type is valid
7531                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7532                               eclass == ExprClass.Value)) {
7533                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7534                                 return null;
7535                         }
7536 #endif
7537
7538                         Type t = ea.Expr.Type;
7539                         if (t.GetArrayRank () != ea.Arguments.Count){
7540                                 ea.Error (22,
7541                                           "Incorrect number of indexes for array " +
7542                                           " expected: " + t.GetArrayRank () + " got: " +
7543                                           ea.Arguments.Count);
7544                                 return null;
7545                         }
7546
7547                         type = TypeManager.GetElementType (t);
7548                         if (type.IsPointer && !ec.InUnsafe){
7549                                 UnsafeError (ea.Location);
7550                                 return null;
7551                         }
7552
7553                         foreach (Argument a in ea.Arguments){
7554                                 Type argtype = a.Type;
7555
7556                                 if (argtype == TypeManager.int32_type ||
7557                                     argtype == TypeManager.uint32_type ||
7558                                     argtype == TypeManager.int64_type ||
7559                                     argtype == TypeManager.uint64_type)
7560                                         continue;
7561
7562                                 //
7563                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7564                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7565                                 //
7566                                 // Wonder if I will run into trouble for this.
7567                                 //
7568                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7569                                 if (a.Expr == null)
7570                                         return null;
7571                         }
7572                         
7573                         eclass = ExprClass.Variable;
7574
7575                         return this;
7576                 }
7577
7578                 /// <summary>
7579                 ///    Emits the right opcode to load an object of Type `t'
7580                 ///    from an array of T
7581                 /// </summary>
7582                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7583                 {
7584                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7585                                 ig.Emit (OpCodes.Ldelem_U1);
7586                         else if (type == TypeManager.sbyte_type)
7587                                 ig.Emit (OpCodes.Ldelem_I1);
7588                         else if (type == TypeManager.short_type)
7589                                 ig.Emit (OpCodes.Ldelem_I2);
7590                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7591                                 ig.Emit (OpCodes.Ldelem_U2);
7592                         else if (type == TypeManager.int32_type)
7593                                 ig.Emit (OpCodes.Ldelem_I4);
7594                         else if (type == TypeManager.uint32_type)
7595                                 ig.Emit (OpCodes.Ldelem_U4);
7596                         else if (type == TypeManager.uint64_type)
7597                                 ig.Emit (OpCodes.Ldelem_I8);
7598                         else if (type == TypeManager.int64_type)
7599                                 ig.Emit (OpCodes.Ldelem_I8);
7600                         else if (type == TypeManager.float_type)
7601                                 ig.Emit (OpCodes.Ldelem_R4);
7602                         else if (type == TypeManager.double_type)
7603                                 ig.Emit (OpCodes.Ldelem_R8);
7604                         else if (type == TypeManager.intptr_type)
7605                                 ig.Emit (OpCodes.Ldelem_I);
7606                         else if (type.IsValueType){
7607                                 ig.Emit (OpCodes.Ldelema, type);
7608                                 ig.Emit (OpCodes.Ldobj, type);
7609                         } else if (type.IsGenericParameter)
7610                                 ig.Emit (OpCodes.Ldelem_Any, type);
7611                         else
7612                                 ig.Emit (OpCodes.Ldelem_Ref);
7613                 }
7614
7615                 /// <summary>
7616                 ///    Emits the right opcode to store an object of Type `t'
7617                 ///    from an array of T.  
7618                 /// </summary>
7619                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
7620                 {
7621                         bool is_stobj, has_type_arg;
7622                         OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7623                         if (has_type_arg)
7624                                 ig.Emit (op, t);
7625                         else
7626                                 ig.Emit (op);
7627                 }
7628
7629                 /// <summary>
7630                 ///    Returns the right opcode to store an object of Type `t'
7631                 ///    from an array of T.  
7632                 /// </summary>
7633                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7634                 {
7635                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7636                         has_type_arg = false; is_stobj = false;
7637                         t = TypeManager.TypeToCoreType (t);
7638                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
7639                                 t = TypeManager.EnumToUnderlying (t);
7640                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7641                             t == TypeManager.bool_type)
7642                                 return OpCodes.Stelem_I1;
7643                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7644                                  t == TypeManager.char_type)
7645                                 return OpCodes.Stelem_I2;
7646                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7647                                 return OpCodes.Stelem_I4;
7648                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7649                                 return OpCodes.Stelem_I8;
7650                         else if (t == TypeManager.float_type)
7651                                 return OpCodes.Stelem_R4;
7652                         else if (t == TypeManager.double_type)
7653                                 return OpCodes.Stelem_R8;
7654                         else if (t == TypeManager.intptr_type) {
7655                                 has_type_arg = true;
7656                                 is_stobj = true;
7657                                 return OpCodes.Stobj;
7658                         } else if (t.IsValueType) {
7659                                 has_type_arg = true;
7660                                 is_stobj = true;
7661                                 return OpCodes.Stobj;
7662                         } else if (t.IsGenericParameter) {
7663                                 has_type_arg = true;
7664                                 return OpCodes.Stelem_Any;
7665                         } else
7666                                 return OpCodes.Stelem_Ref;
7667                 }
7668
7669                 MethodInfo FetchGetMethod ()
7670                 {
7671                         ModuleBuilder mb = CodeGen.Module.Builder;
7672                         int arg_count = ea.Arguments.Count;
7673                         Type [] args = new Type [arg_count];
7674                         MethodInfo get;
7675                         
7676                         for (int i = 0; i < arg_count; i++){
7677                                 //args [i++] = a.Type;
7678                                 args [i] = TypeManager.int32_type;
7679                         }
7680                         
7681                         get = mb.GetArrayMethod (
7682                                 ea.Expr.Type, "Get",
7683                                 CallingConventions.HasThis |
7684                                 CallingConventions.Standard,
7685                                 type, args);
7686                         return get;
7687                 }
7688                                 
7689
7690                 MethodInfo FetchAddressMethod ()
7691                 {
7692                         ModuleBuilder mb = CodeGen.Module.Builder;
7693                         int arg_count = ea.Arguments.Count;
7694                         Type [] args = new Type [arg_count];
7695                         MethodInfo address;
7696                         Type ret_type;
7697                         
7698                         ret_type = TypeManager.GetReferenceType (type);
7699                         
7700                         for (int i = 0; i < arg_count; i++){
7701                                 //args [i++] = a.Type;
7702                                 args [i] = TypeManager.int32_type;
7703                         }
7704                         
7705                         address = mb.GetArrayMethod (
7706                                 ea.Expr.Type, "Address",
7707                                 CallingConventions.HasThis |
7708                                 CallingConventions.Standard,
7709                                 ret_type, args);
7710
7711                         return address;
7712                 }
7713
7714                 //
7715                 // Load the array arguments into the stack.
7716                 //
7717                 // If we have been requested to cache the values (cached_locations array
7718                 // initialized), then load the arguments the first time and store them
7719                 // in locals.  otherwise load from local variables.
7720                 //
7721                 void LoadArrayAndArguments (EmitContext ec)
7722                 {
7723                         ILGenerator ig = ec.ig;
7724                         
7725                         if (cached_locations == null){
7726                                 ea.Expr.Emit (ec);
7727                                 foreach (Argument a in ea.Arguments){
7728                                         Type argtype = a.Expr.Type;
7729                                         
7730                                         a.Expr.Emit (ec);
7731                                         
7732                                         if (argtype == TypeManager.int64_type)
7733                                                 ig.Emit (OpCodes.Conv_Ovf_I);
7734                                         else if (argtype == TypeManager.uint64_type)
7735                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7736                                 }
7737                                 return;
7738                         }
7739
7740                         if (cached_locations [0] == null){
7741                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
7742                                 ea.Expr.Emit (ec);
7743                                 ig.Emit (OpCodes.Dup);
7744                                 cached_locations [0].Store (ec);
7745                                 
7746                                 int j = 1;
7747                                 
7748                                 foreach (Argument a in ea.Arguments){
7749                                         Type argtype = a.Expr.Type;
7750                                         
7751                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
7752                                         a.Expr.Emit (ec);
7753                                         if (argtype == TypeManager.int64_type)
7754                                                 ig.Emit (OpCodes.Conv_Ovf_I);
7755                                         else if (argtype == TypeManager.uint64_type)
7756                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7757
7758                                         ig.Emit (OpCodes.Dup);
7759                                         cached_locations [j].Store (ec);
7760                                         j++;
7761                                 }
7762                                 return;
7763                         }
7764
7765                         foreach (LocalTemporary lt in cached_locations)
7766                                 lt.Emit (ec);
7767                 }
7768
7769                 public new void CacheTemporaries (EmitContext ec)
7770                 {
7771                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
7772                 }
7773                 
7774                 public override void Emit (EmitContext ec)
7775                 {
7776                         int rank = ea.Expr.Type.GetArrayRank ();
7777                         ILGenerator ig = ec.ig;
7778
7779                         LoadArrayAndArguments (ec);
7780                         
7781                         if (rank == 1)
7782                                 EmitLoadOpcode (ig, type);
7783                         else {
7784                                 MethodInfo method;
7785                                 
7786                                 method = FetchGetMethod ();
7787                                 ig.Emit (OpCodes.Call, method);
7788                         }
7789                 }
7790
7791                 public void EmitAssign (EmitContext ec, Expression source)
7792                 {
7793                         int rank = ea.Expr.Type.GetArrayRank ();
7794                         ILGenerator ig = ec.ig;
7795                         Type t = source.Type;
7796
7797                         LoadArrayAndArguments (ec);
7798
7799                         //
7800                         // The stobj opcode used by value types will need
7801                         // an address on the stack, not really an array/array
7802                         // pair
7803                         //
7804                         if (rank == 1){
7805                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
7806                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
7807                                         ig.Emit (OpCodes.Ldelema, t);
7808                         }
7809                         
7810                         source.Emit (ec);
7811
7812                         if (rank == 1)
7813                                 EmitStoreOpcode (ig, t);
7814                         else {
7815                                 ModuleBuilder mb = CodeGen.Module.Builder;
7816                                 int arg_count = ea.Arguments.Count;
7817                                 Type [] args = new Type [arg_count + 1];
7818                                 MethodInfo set;
7819                                 
7820                                 for (int i = 0; i < arg_count; i++){
7821                                         //args [i++] = a.Type;
7822                                         args [i] = TypeManager.int32_type;
7823                                 }
7824
7825                                 args [arg_count] = type;
7826                                 
7827                                 set = mb.GetArrayMethod (
7828                                         ea.Expr.Type, "Set",
7829                                         CallingConventions.HasThis |
7830                                         CallingConventions.Standard,
7831                                         TypeManager.void_type, args);
7832                                 
7833                                 ig.Emit (OpCodes.Call, set);
7834                         }
7835                 }
7836
7837                 public void AddressOf (EmitContext ec, AddressOp mode)
7838                 {
7839                         int rank = ea.Expr.Type.GetArrayRank ();
7840                         ILGenerator ig = ec.ig;
7841
7842                         LoadArrayAndArguments (ec);
7843
7844                         if (rank == 1){
7845                                 ig.Emit (OpCodes.Ldelema, type);
7846                         } else {
7847                                 MethodInfo address = FetchAddressMethod ();
7848                                 ig.Emit (OpCodes.Call, address);
7849                         }
7850                 }
7851         }
7852
7853         
7854         class Indexers {
7855                 public ArrayList Properties;
7856                 static Hashtable map;
7857
7858                 public struct Indexer {
7859                         public readonly Type Type;
7860                         public readonly MethodInfo Getter, Setter;
7861
7862                         public Indexer (Type type, MethodInfo get, MethodInfo set)
7863                         {
7864                                 this.Type = type;
7865                                 this.Getter = get;
7866                                 this.Setter = set;
7867                         }
7868                 }
7869
7870                 static Indexers ()
7871                 {
7872                         map = new Hashtable ();
7873                 }
7874
7875                 Indexers ()
7876                 {
7877                         Properties = new ArrayList ();
7878                 }
7879                                 
7880                 void Append (MemberInfo [] mi)
7881                 {
7882                         foreach (PropertyInfo property in mi){
7883                                 MethodInfo get, set;
7884                                 
7885                                 get = property.GetGetMethod (true);
7886                                 set = property.GetSetMethod (true);
7887                                 Properties.Add (new Indexer (property.PropertyType, get, set));
7888                         }
7889                 }
7890
7891                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7892                 {
7893                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7894
7895                         MemberInfo [] mi = TypeManager.MemberLookup (
7896                                 caller_type, caller_type, lookup_type, 0, MemberTypes.Property,
7897                                 BindingFlags.Public | BindingFlags.Instance |
7898                                 BindingFlags.DeclaredOnly, p_name);
7899
7900                         if (mi == null || mi.Length == 0)
7901                                 return null;
7902
7903                         return mi;
7904                 }
7905                 
7906                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
7907                 {
7908                         Indexers ix = (Indexers) map [lookup_type];
7909
7910                         if (ix != null)
7911                                 return ix;
7912
7913                         Type copy = lookup_type;
7914                         while (copy != TypeManager.object_type && copy != null){
7915                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
7916
7917                                 if (mi != null){
7918                                         if (ix == null)
7919                                                 ix = new Indexers ();
7920
7921                                         ix.Append (mi);
7922                                 }
7923                                         
7924                                 copy = copy.BaseType;
7925                         }
7926
7927                         if (!lookup_type.IsInterface)
7928                                 return ix;
7929
7930                         TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
7931                         if (ifaces != null) {
7932                                 foreach (TypeExpr iface in ifaces) {
7933                                         Type itype = iface.Type;
7934                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
7935                                         if (mi != null){
7936                                                 if (ix == null)
7937                                                         ix = new Indexers ();
7938                                         
7939                                                 ix.Append (mi);
7940                                         }
7941                                 }
7942                         }
7943
7944                         return ix;
7945                 }
7946         }
7947
7948         /// <summary>
7949         ///   Expressions that represent an indexer call.
7950         /// </summary>
7951         public class IndexerAccess : Expression, IAssignMethod {
7952                 //
7953                 // Points to our "data" repository
7954                 //
7955                 MethodInfo get, set;
7956                 ArrayList set_arguments;
7957                 bool is_base_indexer;
7958
7959                 protected Type indexer_type;
7960                 protected Type current_type;
7961                 protected Expression instance_expr;
7962                 protected ArrayList arguments;
7963                 
7964                 public IndexerAccess (ElementAccess ea, Location loc)
7965                         : this (ea.Expr, false, loc)
7966                 {
7967                         this.arguments = ea.Arguments;
7968                 }
7969
7970                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7971                                          Location loc)
7972                 {
7973                         this.instance_expr = instance_expr;
7974                         this.is_base_indexer = is_base_indexer;
7975                         this.eclass = ExprClass.Value;
7976                         this.loc = loc;
7977                 }
7978
7979                 protected virtual bool CommonResolve (EmitContext ec)
7980                 {
7981                         indexer_type = instance_expr.Type;
7982                         current_type = ec.ContainerType;
7983
7984                         return true;
7985                 }
7986
7987                 public override Expression DoResolve (EmitContext ec)
7988                 {
7989                         ArrayList AllGetters = new ArrayList();
7990                         if (!CommonResolve (ec))
7991                                 return null;
7992
7993                         //
7994                         // Step 1: Query for all `Item' *properties*.  Notice
7995                         // that the actual methods are pointed from here.
7996                         //
7997                         // This is a group of properties, piles of them.  
7998
7999                         bool found_any = false, found_any_getters = false;
8000                         Type lookup_type = indexer_type;
8001
8002                         Indexers ilist;
8003                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8004                         if (ilist != null) {
8005                                 found_any = true;
8006                                 if (ilist.Properties != null) {
8007                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8008                                                 if (ix.Getter != null)
8009                                                         AllGetters.Add(ix.Getter);
8010                                         }
8011                                 }
8012                         }
8013
8014                         if (AllGetters.Count > 0) {
8015                                 found_any_getters = true;
8016                                 get = (MethodInfo) Invocation.OverloadResolve (
8017                                         ec, new MethodGroupExpr (AllGetters, loc),
8018                                         arguments, false, loc);
8019                         }
8020
8021                         if (!found_any) {
8022                                 Report.Error (21, loc,
8023                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8024                                               "' does not have any indexers defined");
8025                                 return null;
8026                         }
8027
8028                         if (!found_any_getters) {
8029                                 Error (154, "indexer can not be used in this context, because " +
8030                                        "it lacks a `get' accessor");
8031                                 return null;
8032                         }
8033
8034                         if (get == null) {
8035                                 Error (1501, "No Overload for method `this' takes `" +
8036                                        arguments.Count + "' arguments");
8037                                 return null;
8038                         }
8039
8040                         //
8041                         // Only base will allow this invocation to happen.
8042                         //
8043                         if (get.IsAbstract && this is BaseIndexerAccess){
8044                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8045                                 return null;
8046                         }
8047
8048                         type = get.ReturnType;
8049                         if (type.IsPointer && !ec.InUnsafe){
8050                                 UnsafeError (loc);
8051                                 return null;
8052                         }
8053                         
8054                         eclass = ExprClass.IndexerAccess;
8055                         return this;
8056                 }
8057
8058                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8059                 {
8060                         ArrayList AllSetters = new ArrayList();
8061                         if (!CommonResolve (ec))
8062                                 return null;
8063
8064                         bool found_any = false, found_any_setters = false;
8065
8066                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8067                         if (ilist != null) {
8068                                 found_any = true;
8069                                 if (ilist.Properties != null) {
8070                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8071                                                 if (ix.Setter != null)
8072                                                         AllSetters.Add(ix.Setter);
8073                                         }
8074                                 }
8075                         }
8076                         if (AllSetters.Count > 0) {
8077                                 found_any_setters = true;
8078                                 set_arguments = (ArrayList) arguments.Clone ();
8079                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8080                                 set = (MethodInfo) Invocation.OverloadResolve (
8081                                         ec, new MethodGroupExpr (AllSetters, loc),
8082                                         set_arguments, false, loc);
8083                         }
8084
8085                         if (!found_any) {
8086                                 Report.Error (21, loc,
8087                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8088                                               "' does not have any indexers defined");
8089                                 return null;
8090                         }
8091
8092                         if (!found_any_setters) {
8093                                 Error (154, "indexer can not be used in this context, because " +
8094                                        "it lacks a `set' accessor");
8095                                 return null;
8096                         }
8097
8098                         if (set == null) {
8099                                 Error (1501, "No Overload for method `this' takes `" +
8100                                        arguments.Count + "' arguments");
8101                                 return null;
8102                         }
8103
8104                         //
8105                         // Only base will allow this invocation to happen.
8106                         //
8107                         if (set.IsAbstract && this is BaseIndexerAccess){
8108                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8109                                 return null;
8110                         }
8111
8112                         //
8113                         // Now look for the actual match in the list of indexers to set our "return" type
8114                         //
8115                         type = TypeManager.void_type;   // default value
8116                         foreach (Indexers.Indexer ix in ilist.Properties){
8117                                 if (ix.Setter == set){
8118                                         type = ix.Type;
8119                                         break;
8120                                 }
8121                         }
8122                         
8123                         eclass = ExprClass.IndexerAccess;
8124                         return this;
8125                 }
8126                 
8127                 public override void Emit (EmitContext ec)
8128                 {
8129                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
8130                 }
8131
8132                 //
8133                 // source is ignored, because we already have a copy of it from the
8134                 // LValue resolution and we have already constructed a pre-cached
8135                 // version of the arguments (ea.set_arguments);
8136                 //
8137                 public void EmitAssign (EmitContext ec, Expression source)
8138                 {
8139                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
8140                 }
8141         }
8142
8143         /// <summary>
8144         ///   The base operator for method names
8145         /// </summary>
8146         public class BaseAccess : Expression {
8147                 string member;
8148                 
8149                 public BaseAccess (string member, Location l)
8150                 {
8151                         this.member = member;
8152                         loc = l;
8153                 }
8154
8155                 public override Expression DoResolve (EmitContext ec)
8156                 {
8157                         Expression c = CommonResolve (ec);
8158
8159                         if (c == null)
8160                                 return null;
8161
8162                         //
8163                         // MethodGroups use this opportunity to flag an error on lacking ()
8164                         //
8165                         if (!(c is MethodGroupExpr))
8166                                 return c.Resolve (ec);
8167                         return c;
8168                 }
8169
8170                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8171                 {
8172                         Expression c = CommonResolve (ec);
8173
8174                         if (c == null)
8175                                 return null;
8176
8177                         //
8178                         // MethodGroups use this opportunity to flag an error on lacking ()
8179                         //
8180                         if (! (c is MethodGroupExpr))
8181                                 return c.DoResolveLValue (ec, right_side);
8182
8183                         return c;
8184                 }
8185
8186                 Expression CommonResolve (EmitContext ec)
8187                 {
8188                         Expression member_lookup;
8189                         Type current_type = ec.ContainerType;
8190                         Type base_type = current_type.BaseType;
8191                         Expression e;
8192
8193                         if (ec.IsStatic){
8194                                 Error (1511, "Keyword base is not allowed in static method");
8195                                 return null;
8196                         }
8197                         
8198                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
8199                                                       member, 0, AllMemberTypes,
8200                                                       AllBindingFlags, loc);
8201                         if (member_lookup == null) {
8202                                 MemberLookupFailed (ec, base_type, base_type, member,
8203                                                     0, null, loc);
8204                                 return null;
8205                         }
8206
8207                         Expression left;
8208                         
8209                         if (ec.IsStatic)
8210                                 left = new TypeExpression (base_type, loc);
8211                         else
8212                                 left = ec.GetThis (loc);
8213                         
8214                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8215
8216                         if (e is PropertyExpr){
8217                                 PropertyExpr pe = (PropertyExpr) e;
8218
8219                                 pe.IsBase = true;
8220                         }
8221
8222                         return e;
8223                 }
8224
8225                 public override void Emit (EmitContext ec)
8226                 {
8227                         throw new Exception ("Should never be called"); 
8228                 }
8229         }
8230
8231         /// <summary>
8232         ///   The base indexer operator
8233         /// </summary>
8234         public class BaseIndexerAccess : IndexerAccess {
8235                 public BaseIndexerAccess (ArrayList args, Location loc)
8236                         : base (null, true, loc)
8237                 {
8238                         arguments = new ArrayList ();
8239                         foreach (Expression tmp in args)
8240                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8241                 }
8242
8243                 protected override bool CommonResolve (EmitContext ec)
8244                 {
8245                         instance_expr = ec.GetThis (loc);
8246
8247                         current_type = ec.ContainerType.BaseType;
8248                         indexer_type = current_type;
8249
8250                         foreach (Argument a in arguments){
8251                                 if (!a.Resolve (ec, loc))
8252                                         return false;
8253                         }
8254
8255                         return true;
8256                 }
8257         }
8258         
8259         /// <summary>
8260         ///   This class exists solely to pass the Type around and to be a dummy
8261         ///   that can be passed to the conversion functions (this is used by
8262         ///   foreach implementation to typecast the object return value from
8263         ///   get_Current into the proper type.  All code has been generated and
8264         ///   we only care about the side effect conversions to be performed
8265         ///
8266         ///   This is also now used as a placeholder where a no-action expression
8267         ///   is needed (the `New' class).
8268         /// </summary>
8269         public class EmptyExpression : Expression {
8270                 public EmptyExpression ()
8271                 {
8272                         type = TypeManager.object_type;
8273                         eclass = ExprClass.Value;
8274                         loc = Location.Null;
8275                 }
8276
8277                 public EmptyExpression (Type t)
8278                 {
8279                         type = t;
8280                         eclass = ExprClass.Value;
8281                         loc = Location.Null;
8282                 }
8283                 
8284                 public override Expression DoResolve (EmitContext ec)
8285                 {
8286                         return this;
8287                 }
8288
8289                 public override void Emit (EmitContext ec)
8290                 {
8291                         // nothing, as we only exist to not do anything.
8292                 }
8293
8294                 //
8295                 // This is just because we might want to reuse this bad boy
8296                 // instead of creating gazillions of EmptyExpressions.
8297                 // (CanImplicitConversion uses it)
8298                 //
8299                 public void SetType (Type t)
8300                 {
8301                         type = t;
8302                 }
8303         }
8304
8305         public class UserCast : Expression {
8306                 MethodBase method;
8307                 Expression source;
8308                 
8309                 public UserCast (MethodInfo method, Expression source, Location l)
8310                 {
8311                         this.method = method;
8312                         this.source = source;
8313                         type = method.ReturnType;
8314                         eclass = ExprClass.Value;
8315                         loc = l;
8316                 }
8317
8318                 public override Expression DoResolve (EmitContext ec)
8319                 {
8320                         //
8321                         // We are born fully resolved
8322                         //
8323                         return this;
8324                 }
8325
8326                 public override void Emit (EmitContext ec)
8327                 {
8328                         ILGenerator ig = ec.ig;
8329
8330                         source.Emit (ec);
8331                         
8332                         if (method is MethodInfo)
8333                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8334                         else
8335                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8336
8337                 }
8338         }
8339
8340         // <summary>
8341         //   This class is used to "construct" the type during a typecast
8342         //   operation.  Since the Type.GetType class in .NET can parse
8343         //   the type specification, we just use this to construct the type
8344         //   one bit at a time.
8345         // </summary>
8346         public class ComposedCast : TypeExpr {
8347                 Expression left;
8348                 string dim;
8349                 
8350                 public ComposedCast (Expression left, string dim, Location l)
8351                 {
8352                         this.left = left;
8353                         this.dim = dim;
8354                         loc = l;
8355                 }
8356
8357                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8358                 {
8359                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
8360                         if (ltype == null)
8361                                 return null;
8362
8363                         int pos = 0;
8364                         while ((pos < dim.Length) && (dim [pos] == '[')) {
8365                                 pos++;
8366
8367                                 if (dim [pos] == ']') {
8368                                         ltype = ltype.MakeArrayType ();
8369                                         pos++;
8370
8371                                         if (pos < dim.Length)
8372                                                 continue;
8373
8374                                         type = ltype;
8375                                         eclass = ExprClass.Type;
8376                                         return this;
8377                                 }
8378
8379                                 int rank = 0;
8380                                 while (dim [pos] == ',') {
8381                                         pos++; rank++;
8382                                 }
8383
8384                                 if ((dim [pos] != ']') || (pos != dim.Length-1))
8385                                         return null;
8386                                                 
8387                                 type = ltype.MakeArrayType (rank + 1);
8388                                 eclass = ExprClass.Type;
8389                                 return this;
8390                         }
8391
8392                         //
8393                         // ltype.Fullname is already fully qualified, so we can skip
8394                         // a lot of probes, and go directly to TypeManager.LookupType
8395                         //
8396                         string cname = ltype.FullName + dim;
8397                         type = TypeManager.LookupTypeDirect (cname);
8398                         if (type == null){
8399                                 //
8400                                 // For arrays of enumerations we are having a problem
8401                                 // with the direct lookup.  Need to investigate.
8402                                 //
8403                                 // For now, fall back to the full lookup in that case.
8404                                 //
8405                                 type = RootContext.LookupType (
8406                                         ec.DeclSpace, cname, false, loc);
8407
8408                                 if (type == null)
8409                                         return null;
8410                         }
8411
8412                         if (!ec.ResolvingTypeTree){
8413                                 //
8414                                 // If the above flag is set, this is being invoked from the ResolveType function.
8415                                 // Upper layers take care of the type validity in this context.
8416                                 //
8417                         if (!ec.InUnsafe && type.IsPointer){
8418                                 UnsafeError (loc);
8419                                 return null;
8420                         }
8421                         }
8422                         
8423                         eclass = ExprClass.Type;
8424                         return this;
8425                 }
8426
8427                 public override string Name {
8428                         get {
8429                                 return left + dim;
8430                         }
8431                 }
8432         }
8433
8434         //
8435         // This class is used to represent the address of an array, used
8436         // only by the Fixed statement, this is like the C "&a [0]" construct.
8437         //
8438         public class ArrayPtr : Expression {
8439                 Expression array;
8440                 
8441                 public ArrayPtr (Expression array, Location l)
8442                 {
8443                         Type array_type = TypeManager.GetElementType (array.Type);
8444
8445                         this.array = array;
8446
8447                         type = TypeManager.GetPointerType (array_type);
8448                         eclass = ExprClass.Value;
8449                         loc = l;
8450                 }
8451
8452                 public override void Emit (EmitContext ec)
8453                 {
8454                         ILGenerator ig = ec.ig;
8455                         
8456                         array.Emit (ec);
8457                         IntLiteral.EmitInt (ig, 0);
8458                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8459                 }
8460
8461                 public override Expression DoResolve (EmitContext ec)
8462                 {
8463                         //
8464                         // We are born fully resolved
8465                         //
8466                         return this;
8467                 }
8468         }
8469
8470         //
8471         // Used by the fixed statement
8472         //
8473         public class StringPtr : Expression {
8474                 LocalBuilder b;
8475                 
8476                 public StringPtr (LocalBuilder b, Location l)
8477                 {
8478                         this.b = b;
8479                         eclass = ExprClass.Value;
8480                         type = TypeManager.char_ptr_type;
8481                         loc = l;
8482                 }
8483
8484                 public override Expression DoResolve (EmitContext ec)
8485                 {
8486                         // This should never be invoked, we are born in fully
8487                         // initialized state.
8488
8489                         return this;
8490                 }
8491
8492                 public override void Emit (EmitContext ec)
8493                 {
8494                         ILGenerator ig = ec.ig;
8495
8496                         ig.Emit (OpCodes.Ldloc, b);
8497                         ig.Emit (OpCodes.Conv_I);
8498                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8499                         ig.Emit (OpCodes.Add);
8500                 }
8501         }
8502         
8503         //
8504         // Implements the `stackalloc' keyword
8505         //
8506         public class StackAlloc : Expression {
8507                 Type otype;
8508                 Expression t;
8509                 Expression count;
8510                 
8511                 public StackAlloc (Expression type, Expression count, Location l)
8512                 {
8513                         t = type;
8514                         this.count = count;
8515                         loc = l;
8516                 }
8517
8518                 public override Expression DoResolve (EmitContext ec)
8519                 {
8520                         count = count.Resolve (ec);
8521                         if (count == null)
8522                                 return null;
8523                         
8524                         if (count.Type != TypeManager.int32_type){
8525                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8526                                 if (count == null)
8527                                         return null;
8528                         }
8529
8530                         if (ec.CurrentBranching.InCatch () ||
8531                             ec.CurrentBranching.InFinally (true)) {
8532                                 Error (255,
8533                                               "stackalloc can not be used in a catch or finally block");
8534                                 return null;
8535                         }
8536
8537                         otype = ec.DeclSpace.ResolveType (t, false, loc);
8538
8539                         if (otype == null)
8540                                 return null;
8541
8542                         if (!TypeManager.VerifyUnManaged (otype, loc))
8543                                 return null;
8544
8545                         type = TypeManager.GetPointerType (otype);
8546                         eclass = ExprClass.Value;
8547
8548                         return this;
8549                 }
8550
8551                 public override void Emit (EmitContext ec)
8552                 {
8553                         int size = GetTypeSize (otype);
8554                         ILGenerator ig = ec.ig;
8555                                 
8556                         if (size == 0)
8557                                 ig.Emit (OpCodes.Sizeof, otype);
8558                         else
8559                                 IntConstant.EmitInt (ig, size);
8560                         count.Emit (ec);
8561                         ig.Emit (OpCodes.Mul);
8562                         ig.Emit (OpCodes.Localloc);
8563                 }
8564         }
8565 }