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