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