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