**** Merged r40464 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                         type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : 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                         
3453                         // It must be either array or fixed buffer
3454                         Type element = TypeManager.HasElementType (op_type) ?
3455                                 element = TypeManager.GetElementType (op_type) :
3456                                 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3457
3458                         int size = GetTypeSize (element);
3459                         Type rtype = right.Type;
3460                         
3461                         if (rtype.IsPointer){
3462                                 //
3463                                 // handle (pointer - pointer)
3464                                 //
3465                                 left.Emit (ec);
3466                                 right.Emit (ec);
3467                                 ig.Emit (OpCodes.Sub);
3468
3469                                 if (size != 1){
3470                                         if (size == 0)
3471                                                 ig.Emit (OpCodes.Sizeof, element);
3472                                         else 
3473                                                 IntLiteral.EmitInt (ig, size);
3474                                         ig.Emit (OpCodes.Div);
3475                                 }
3476                                 ig.Emit (OpCodes.Conv_I8);
3477                         } else {
3478                                 //
3479                                 // handle + and - on (pointer op int)
3480                                 //
3481                                 left.Emit (ec);
3482                                 ig.Emit (OpCodes.Conv_I);
3483
3484                                 Constant right_const = right as Constant;
3485                                 if (right_const != null && size != 0) {
3486                                         Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size), right_const, loc);
3487                                         if (ex == null)
3488                                                 return;
3489                                         ex.Emit (ec);
3490                                 } else {
3491                                         right.Emit (ec);
3492                                         if (size != 1){
3493                                                 if (size == 0)
3494                                                         ig.Emit (OpCodes.Sizeof, element);
3495                                                 else 
3496                                                         IntLiteral.EmitInt (ig, size);
3497                                                 if (rtype == TypeManager.int64_type)
3498                                                         ig.Emit (OpCodes.Conv_I8);
3499                                                 else if (rtype == TypeManager.uint64_type)
3500                                                         ig.Emit (OpCodes.Conv_U8);
3501                                                 ig.Emit (OpCodes.Mul);
3502                                         }
3503                                 }
3504                                 
3505                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3506                                         ig.Emit (OpCodes.Conv_I);
3507                                 
3508                                 if (is_add)
3509                                         ig.Emit (OpCodes.Add);
3510                                 else
3511                                         ig.Emit (OpCodes.Sub);
3512                         }
3513                 }
3514         }
3515         
3516         /// <summary>
3517         ///   Implements the ternary conditional operator (?:)
3518         /// </summary>
3519         public class Conditional : Expression {
3520                 Expression expr, trueExpr, falseExpr;
3521                 
3522                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3523                 {
3524                         this.expr = expr;
3525                         this.trueExpr = trueExpr;
3526                         this.falseExpr = falseExpr;
3527                         this.loc = l;
3528                 }
3529
3530                 public Expression Expr {
3531                         get {
3532                                 return expr;
3533                         }
3534                 }
3535
3536                 public Expression TrueExpr {
3537                         get {
3538                                 return trueExpr;
3539                         }
3540                 }
3541
3542                 public Expression FalseExpr {
3543                         get {
3544                                 return falseExpr;
3545                         }
3546                 }
3547
3548                 public override Expression DoResolve (EmitContext ec)
3549                 {
3550                         expr = expr.Resolve (ec);
3551
3552                         if (expr == null)
3553                                 return null;
3554
3555                         if (TypeManager.IsNullableType (expr.Type))
3556                                 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3557                         
3558                         if (expr.Type != TypeManager.bool_type){
3559                                 expr = Expression.ResolveBoolean (
3560                                         ec, expr, loc);
3561                                 
3562                                 if (expr == null)
3563                                         return null;
3564                         }
3565                         
3566                         trueExpr = trueExpr.Resolve (ec);
3567                         falseExpr = falseExpr.Resolve (ec);
3568
3569                         if (trueExpr == null || falseExpr == null)
3570                                 return null;
3571
3572                         eclass = ExprClass.Value;
3573                         if (trueExpr.Type == falseExpr.Type)
3574                                 type = trueExpr.Type;
3575                         else {
3576                                 Expression conv;
3577                                 Type true_type = trueExpr.Type;
3578                                 Type false_type = falseExpr.Type;
3579
3580                                 //
3581                                 // First, if an implicit conversion exists from trueExpr
3582                                 // to falseExpr, then the result type is of type falseExpr.Type
3583                                 //
3584                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3585                                 if (conv != null){
3586                                         //
3587                                         // Check if both can convert implicitl to each other's type
3588                                         //
3589                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3590                                                 Error (172,
3591                                                        "Can not compute type of conditional expression " +
3592                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3593                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3594                                                        "' convert implicitly to each other");
3595                                                 return null;
3596                                         }
3597                                         type = false_type;
3598                                         trueExpr = conv;
3599                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3600                                         type = true_type;
3601                                         falseExpr = conv;
3602                                 } else {
3603                                         Error (173, "The type of the conditional expression can " +
3604                                                "not be computed because there is no implicit conversion" +
3605                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3606                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3607                                         return null;
3608                                 }
3609                         }
3610
3611                         // Dead code optimalization
3612                         if (expr is BoolConstant){
3613                                 BoolConstant bc = (BoolConstant) expr;
3614
3615                                 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3616                                 return bc.Value ? trueExpr : falseExpr;
3617                         }
3618
3619                         return this;
3620                 }
3621
3622                 public override void Emit (EmitContext ec)
3623                 {
3624                         ILGenerator ig = ec.ig;
3625                         Label false_target = ig.DefineLabel ();
3626                         Label end_target = ig.DefineLabel ();
3627
3628                         expr.EmitBranchable (ec, false_target, false);
3629                         trueExpr.Emit (ec);
3630                         ig.Emit (OpCodes.Br, end_target);
3631                         ig.MarkLabel (false_target);
3632                         falseExpr.Emit (ec);
3633                         ig.MarkLabel (end_target);
3634                 }
3635
3636         }
3637
3638         /// <summary>
3639         ///   Local variables
3640         /// </summary>
3641         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3642                 public readonly string Name;
3643                 public readonly Block Block;
3644                 public LocalInfo local_info;
3645                 bool is_readonly;
3646                 bool prepared;
3647                 LocalTemporary temp;
3648                 
3649                 public LocalVariableReference (Block block, string name, Location l)
3650                 {
3651                         Block = block;
3652                         Name = name;
3653                         loc = l;
3654                         eclass = ExprClass.Variable;
3655                 }
3656
3657                 //
3658                 // Setting `is_readonly' to false will allow you to create a writable
3659                 // reference to a read-only variable.  This is used by foreach and using.
3660                 //
3661                 public LocalVariableReference (Block block, string name, Location l,
3662                                                LocalInfo local_info, bool is_readonly)
3663                         : this (block, name, l)
3664                 {
3665                         this.local_info = local_info;
3666                         this.is_readonly = is_readonly;
3667                 }
3668
3669                 public VariableInfo VariableInfo {
3670                         get {
3671                                 return local_info.VariableInfo;
3672                         }
3673                 }
3674
3675                 public bool IsReadOnly {
3676                         get {
3677                                 return is_readonly;
3678                         }
3679                 }
3680
3681                 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3682                 {
3683                         if (local_info == null) {
3684                                 local_info = Block.GetLocalInfo (Name);
3685
3686                                 // is out param
3687                                 if (lvalue_right_side == EmptyExpression.Null)
3688                                         local_info.Used = true;
3689
3690                                 is_readonly = local_info.ReadOnly;
3691                         }
3692
3693                         type = local_info.VariableType;
3694
3695                         VariableInfo variable_info = local_info.VariableInfo;
3696                         if (lvalue_right_side != null){
3697                                 if (is_readonly){
3698                                         Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3699                                         return null;
3700                                 }
3701                                 
3702                                 if (variable_info != null)
3703                                         variable_info.SetAssigned (ec);
3704                 }
3705                 
3706                         Expression e = Block.GetConstantExpression (Name);
3707                         if (e != null) {
3708                                 local_info.Used = true;
3709                                 eclass = ExprClass.Value;
3710                                 return e.Resolve (ec);
3711                         }
3712
3713                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3714                                 return null;
3715
3716                         if (lvalue_right_side == null)
3717                                 local_info.Used = true;
3718
3719                         if (ec.CurrentAnonymousMethod != null){
3720                                 //
3721                                 // If we are referencing a variable from the external block
3722                                 // flag it for capturing
3723                                 //
3724                                 if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){
3725                                         if (local_info.AddressTaken){
3726                                                 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3727                                                 return null;
3728                                         }
3729                                         ec.CaptureVariable (local_info);
3730                                 }
3731                         }
3732                         
3733                         return this;
3734                 }
3735
3736                 public override Expression DoResolve (EmitContext ec)
3737                 {
3738                         return DoResolveBase (ec, null);
3739                 }
3740
3741                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3742                 {
3743                         Expression ret = DoResolveBase (ec, right_side);
3744                         if (ret != null)
3745                                 CheckObsoleteAttribute (ret.Type);
3746
3747                         return ret;
3748                 }
3749
3750                 public bool VerifyFixed (bool is_expression)
3751                 {
3752                         return !is_expression || local_info.IsFixed;
3753                 }
3754
3755                 public override void Emit (EmitContext ec)
3756                 {
3757                         ILGenerator ig = ec.ig;
3758
3759                         if (local_info.FieldBuilder == null){
3760                                 //
3761                                 // A local variable on the local CLR stack
3762                                 //
3763                         ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3764                         } else {
3765                                 //
3766                                 // A local variable captured by anonymous methods.
3767                                 //
3768                                 if (!prepared)
3769                                         ec.EmitCapturedVariableInstance (local_info);
3770                                 
3771                                 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3772                         }
3773                 }
3774                 
3775                 public void Emit (EmitContext ec, bool leave_copy)
3776                 {
3777                         Emit (ec);
3778                         if (leave_copy){
3779                                 ec.ig.Emit (OpCodes.Dup);
3780                                 if (local_info.FieldBuilder != null){
3781                                         temp = new LocalTemporary (ec, Type);
3782                                         temp.Store (ec);
3783                                 }
3784                         }
3785                 }
3786                 
3787                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3788                 {
3789                         ILGenerator ig = ec.ig;
3790                         prepared = prepare_for_load;
3791
3792                         if (local_info.FieldBuilder == null){
3793                                 //
3794                                 // A local variable on the local CLR stack
3795                                 //
3796                                 if (local_info.LocalBuilder == null)
3797                                         throw new Exception ("This should not happen: both Field and Local are null");
3798                                 
3799                         source.Emit (ec);
3800                         if (leave_copy)
3801                                 ec.ig.Emit (OpCodes.Dup);
3802                                 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3803                         } else {
3804                                 //
3805                                 // A local variable captured by anonymous methods or itereators.
3806                                 //
3807                                 ec.EmitCapturedVariableInstance (local_info);
3808
3809                                 if (prepare_for_load)
3810                                         ig.Emit (OpCodes.Dup);
3811                                 source.Emit (ec);
3812                                 if (leave_copy){
3813                                         ig.Emit (OpCodes.Dup);
3814                                         temp = new LocalTemporary (ec, Type);
3815                                         temp.Store (ec);
3816                                 }
3817                                 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3818                                 if (temp != null)
3819                                         temp.Emit (ec);
3820                         }
3821                 }
3822                 
3823                 public void AddressOf (EmitContext ec, AddressOp mode)
3824                 {
3825                         ILGenerator ig = ec.ig;
3826                         
3827                         if (local_info.FieldBuilder == null){
3828                                 //
3829                                 // A local variable on the local CLR stack
3830                                 //
3831                         ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3832                         } else {
3833                                 //
3834                                 // A local variable captured by anonymous methods or iterators
3835                                 //
3836                                 ec.EmitCapturedVariableInstance (local_info);
3837                                 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3838                         }
3839                 }
3840
3841                 public override string ToString ()
3842                 {
3843                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3844                 }
3845         }
3846
3847         /// <summary>
3848         ///   This represents a reference to a parameter in the intermediate
3849         ///   representation.
3850         /// </summary>
3851         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3852                 Parameters pars;
3853                 String name;
3854                 int idx;
3855                 Block block;
3856                 VariableInfo vi;
3857                 public Parameter.Modifier mod;
3858                 public bool is_ref, is_out, prepared;
3859
3860                 public bool IsOut {
3861                         get {
3862                                 return is_out;
3863                         }
3864                 }
3865
3866                 public bool IsRef {
3867                         get {
3868                                 return is_ref;
3869                         }
3870                 }
3871
3872                 LocalTemporary temp;
3873                 
3874                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3875                 {
3876                         this.pars = pars;
3877                         this.block = block;
3878                         this.idx  = idx;
3879                         this.name = name;
3880                         this.loc = loc;
3881                         eclass = ExprClass.Variable;
3882                 }
3883
3884                 public VariableInfo VariableInfo {
3885                         get { return vi; }
3886                 }
3887
3888                 public bool VerifyFixed (bool is_expression)
3889                 {
3890                         return !is_expression || TypeManager.IsValueType (type);
3891                 }
3892
3893                 public bool IsAssigned (EmitContext ec, Location loc)
3894                 {
3895                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3896                                 return true;
3897
3898                         Report.Error (165, loc,
3899                                       "Use of unassigned parameter `" + name + "'");
3900                         return false;
3901                 }
3902
3903                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3904                 {
3905                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3906                                 return true;
3907
3908                         Report.Error (170, loc,
3909                                       "Use of possibly unassigned field `" + field_name + "'");
3910                         return false;
3911                 }
3912
3913                 public void SetAssigned (EmitContext ec)
3914                 {
3915                         if (is_out && ec.DoFlowAnalysis)
3916                                 ec.CurrentBranching.SetAssigned (vi);
3917                 }
3918
3919                 public void SetFieldAssigned (EmitContext ec, string field_name)
3920                 {
3921                         if (is_out && ec.DoFlowAnalysis)
3922                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3923                 }
3924
3925                 protected void DoResolveBase (EmitContext ec)
3926                 {
3927                         type = pars.GetParameterInfo (ec, idx, out mod);
3928                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3929                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3930                         eclass = ExprClass.Variable;
3931
3932                         if (is_out)
3933                                 vi = block.ParameterMap [idx];
3934
3935                         if (ec.CurrentAnonymousMethod != null){
3936                                 if (is_ref){
3937                                         Report.Error (1628, Location,
3938                                                       "Can not reference a ref or out parameter in an anonymous method");
3939                                         return;
3940                                 }
3941                                 
3942                                 //
3943                                 // If we are referencing the parameter from the external block
3944                                 // flag it for capturing
3945                                 //
3946                                 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3947                                 if (!block.IsLocalParameter (name)){
3948                                         ec.CaptureParameter (name, type, idx);
3949                                 }
3950                         }
3951                 }
3952
3953                 //
3954                 // Notice that for ref/out parameters, the type exposed is not the
3955                 // same type exposed externally.
3956                 //
3957                 // for "ref int a":
3958                 //   externally we expose "int&"
3959                 //   here we expose       "int".
3960                 //
3961                 // We record this in "is_ref".  This means that the type system can treat
3962                 // the type as it is expected, but when we generate the code, we generate
3963                 // the alternate kind of code.
3964                 //
3965                 public override Expression DoResolve (EmitContext ec)
3966                 {
3967                         DoResolveBase (ec);
3968
3969                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3970                                 return null;
3971
3972                         if (ec.RemapToProxy)
3973                                 return ec.RemapParameter (idx);
3974                         
3975                         return this;
3976                 }
3977
3978                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3979                 {
3980                         DoResolveBase (ec);
3981
3982                         SetAssigned (ec);
3983
3984                         if (ec.RemapToProxy)
3985                                 return ec.RemapParameterLValue (idx, right_side);
3986                         
3987                         return this;
3988                 }
3989
3990                 static public void EmitLdArg (ILGenerator ig, int x)
3991                 {
3992                         if (x <= 255){
3993                                 switch (x){
3994                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3995                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3996                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3997                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3998                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3999                                 }
4000                         } else
4001                                 ig.Emit (OpCodes.Ldarg, x);
4002                 }
4003                 
4004                 //
4005                 // This method is used by parameters that are references, that are
4006                 // being passed as references:  we only want to pass the pointer (that
4007                 // is already stored in the parameter, not the address of the pointer,
4008                 // and not the value of the variable).
4009                 //
4010                 public void EmitLoad (EmitContext ec)
4011                 {
4012                         ILGenerator ig = ec.ig;
4013                         int arg_idx = idx;
4014
4015                         if (!ec.IsStatic)
4016                                 arg_idx++;
4017
4018                         EmitLdArg (ig, arg_idx);
4019
4020                         //
4021                         // FIXME: Review for anonymous methods
4022                         //
4023                 }
4024                 
4025                 public override void Emit (EmitContext ec)
4026                 {
4027                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4028                                 ec.EmitParameter (name);
4029                                 return;
4030                         }
4031                         
4032                         Emit (ec, false);
4033                 }
4034                 
4035                 public void Emit (EmitContext ec, bool leave_copy)
4036                 {
4037                         ILGenerator ig = ec.ig;
4038                         int arg_idx = idx;
4039
4040                         if (!ec.IsStatic)
4041                                 arg_idx++;
4042
4043                         EmitLdArg (ig, arg_idx);
4044
4045                         if (is_ref) {
4046                                 if (prepared)
4047                                         ec.ig.Emit (OpCodes.Dup);
4048         
4049                                 //
4050                                 // If we are a reference, we loaded on the stack a pointer
4051                                 // Now lets load the real value
4052                                 //
4053                                 LoadFromPtr (ig, type);
4054                         }
4055                         
4056                         if (leave_copy) {
4057                                 ec.ig.Emit (OpCodes.Dup);
4058                                 
4059                                 if (is_ref) {
4060                                         temp = new LocalTemporary (ec, type);
4061                                         temp.Store (ec);
4062                                 }
4063                         }
4064                 }
4065                 
4066                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4067                 {
4068                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4069                                 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
4070                                 return;
4071                         }
4072
4073                         ILGenerator ig = ec.ig;
4074                         int arg_idx = idx;
4075                         
4076                         prepared = prepare_for_load;
4077                         
4078                         if (!ec.IsStatic)
4079                                 arg_idx++;
4080
4081                         if (is_ref && !prepared)
4082                                 EmitLdArg (ig, arg_idx);
4083                         
4084                         source.Emit (ec);
4085
4086                         if (leave_copy)
4087                                 ec.ig.Emit (OpCodes.Dup);
4088                         
4089                         if (is_ref) {
4090                                 if (leave_copy) {
4091                                         temp = new LocalTemporary (ec, type);
4092                                         temp.Store (ec);
4093                                 }
4094                                 
4095                                 StoreFromPtr (ig, type);
4096                                 
4097                                 if (temp != null)
4098                                         temp.Emit (ec);
4099                         } else {
4100                                 if (arg_idx <= 255)
4101                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
4102                                 else
4103                                         ig.Emit (OpCodes.Starg, arg_idx);
4104                         }
4105                 }
4106
4107                 public void AddressOf (EmitContext ec, AddressOp mode)
4108                 {
4109                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4110                                 ec.EmitAddressOfParameter (name);
4111                                 return;
4112                         }
4113                         
4114                         int arg_idx = idx;
4115
4116                         if (!ec.IsStatic)
4117                                 arg_idx++;
4118
4119                         if (is_ref){
4120                                 if (arg_idx <= 255)
4121                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4122                                 else
4123                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4124                         } else {
4125                                 if (arg_idx <= 255)
4126                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4127                                 else
4128                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4129                         }
4130                 }
4131
4132         }
4133         
4134         /// <summary>
4135         ///   Used for arguments to New(), Invocation()
4136         /// </summary>
4137         public class Argument {
4138                 public enum AType : byte {
4139                         Expression,
4140                         Ref,
4141                         Out,
4142                         ArgList
4143                 };
4144
4145                 public readonly AType ArgType;
4146                 public Expression Expr;
4147                 
4148                 public Argument (Expression expr, AType type)
4149                 {
4150                         this.Expr = expr;
4151                         this.ArgType = type;
4152                 }
4153
4154                 public Argument (Expression expr)
4155                 {
4156                         this.Expr = expr;
4157                         this.ArgType = AType.Expression;
4158                 }
4159
4160                 public Type Type {
4161                         get {
4162                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4163                                         return TypeManager.GetReferenceType (Expr.Type);
4164                                 else
4165                                         return Expr.Type;
4166                         }
4167                 }
4168
4169                 public Parameter.Modifier GetParameterModifier ()
4170                 {
4171                         switch (ArgType) {
4172                         case AType.Out:
4173                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4174
4175                         case AType.Ref:
4176                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4177
4178                         default:
4179                                 return Parameter.Modifier.NONE;
4180                         }
4181                 }
4182
4183                 public static string FullDesc (Argument a)
4184                 {
4185                         if (a.ArgType == AType.ArgList)
4186                                 return "__arglist";
4187
4188                         return (a.ArgType == AType.Ref ? "ref " :
4189                                 (a.ArgType == AType.Out ? "out " : "")) +
4190                                 TypeManager.CSharpName (a.Expr.Type);
4191                 }
4192
4193                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4194                 {
4195                         ConstructedType ctype = Expr as ConstructedType;
4196                         if (ctype != null)
4197                                 Expr = ctype.GetSimpleName (ec);
4198
4199                         // FIXME: csc doesn't report any error if you try to use `ref' or
4200                         //        `out' in a delegate creation expression.
4201                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4202                         if (Expr == null)
4203                                 return false;
4204
4205                         return true;
4206                 }
4207                 
4208                 public bool Resolve (EmitContext ec, Location loc)
4209                 {
4210                         if (ArgType == AType.Ref) {
4211                                 Expr = Expr.Resolve (ec);
4212                                 if (Expr == null)
4213                                         return false;
4214
4215                                 if (!ec.IsConstructor) {
4216                                         FieldExpr fe = Expr as FieldExpr;
4217                                         if (fe != null && fe.FieldInfo.IsInitOnly) {
4218                                                 if (fe.FieldInfo.IsStatic)
4219                                                         Report.Error (199, loc, "A static readonly field cannot be passed ref or out (except in a static constructor)");
4220                                                 else
4221                                                         Report.Error (192, loc, "A readonly field cannot be passed ref or out (except in a constructor)");
4222                                                 return false;
4223                                         }
4224                                 }
4225                                 Expr = Expr.ResolveLValue (ec, Expr);
4226                         } else if (ArgType == AType.Out)
4227                                 Expr = Expr.ResolveLValue (ec, EmptyExpression.Null);
4228                         else
4229                                 Expr = Expr.Resolve (ec);
4230
4231                         if (Expr == null)
4232                                 return false;
4233
4234                         if (ArgType == AType.Expression)
4235                                 return true;
4236                         else {
4237                                 //
4238                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4239                                 // This is only allowed for `this'
4240                                 //
4241                                 FieldExpr fe = Expr as FieldExpr;
4242                                 if (fe != null && !fe.IsStatic){
4243                                         Expression instance = fe.InstanceExpression;
4244
4245                                         if (instance.GetType () != typeof (This)){
4246                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4247                                                         Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type);
4248                                                         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",
4249                                                                 fe.Name);
4250                                                         return false;
4251                                                 }
4252                                         }
4253                                 }
4254                         }
4255
4256                         if (Expr.eclass != ExprClass.Variable){
4257                                 //
4258                                 // We just probe to match the CSC output
4259                                 //
4260                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4261                                     Expr.eclass == ExprClass.IndexerAccess){
4262                                         Report.Error (
4263                                                 206, loc,
4264                                                 "A property or indexer can not be passed as an out or ref " +
4265                                                 "parameter");
4266                                 } else {
4267                                         Report.Error (
4268                                                 1510, loc,
4269                                                 "An lvalue is required as an argument to out or ref");
4270                                 }
4271                                 return false;
4272                         }
4273                                 
4274                         return true;
4275                 }
4276
4277                 public void Emit (EmitContext ec)
4278                 {
4279                         //
4280                         // Ref and Out parameters need to have their addresses taken.
4281                         //
4282                         // ParameterReferences might already be references, so we want
4283                         // to pass just the value
4284                         //
4285                         if (ArgType == AType.Ref || ArgType == AType.Out){
4286                                 AddressOp mode = AddressOp.Store;
4287
4288                                 if (ArgType == AType.Ref)
4289                                         mode |= AddressOp.Load;
4290                                 
4291                                 if (Expr is ParameterReference){
4292                                         ParameterReference pr = (ParameterReference) Expr;
4293
4294                                         if (pr.IsRef)
4295                                                 pr.EmitLoad (ec);
4296                                         else {
4297                                                 
4298                                                 pr.AddressOf (ec, mode);
4299                                         }
4300                                 } else {
4301                                         if (Expr is IMemoryLocation)
4302                                                ((IMemoryLocation) Expr).AddressOf (ec, mode);
4303                                         else {
4304                                                 Report.Error (
4305                                                         1510, Expr.Location,
4306                                                         "An lvalue is required as an argument to out or ref");
4307                                                 return;
4308                                         }
4309                                 }
4310                         } else
4311                                 Expr.Emit (ec);
4312                 }
4313         }
4314
4315         /// <summary>
4316         ///   Invocation of methods or delegates.
4317         /// </summary>
4318         public class Invocation : ExpressionStatement {
4319                 public readonly ArrayList Arguments;
4320
4321                 Expression expr;
4322                 MethodBase method = null;
4323                 
4324                 //
4325                 // arguments is an ArrayList, but we do not want to typecast,
4326                 // as it might be null.
4327                 //
4328                 // FIXME: only allow expr to be a method invocation or a
4329                 // delegate invocation (7.5.5)
4330                 //
4331                 public Invocation (Expression expr, ArrayList arguments, Location l)
4332                 {
4333                         this.expr = expr;
4334                         Arguments = arguments;
4335                         loc = l;
4336                 }
4337
4338                 public Expression Expr {
4339                         get {
4340                                 return expr;
4341                         }
4342                 }
4343
4344                 /// <summary>
4345                 ///   Determines "better conversion" as specified in 7.4.2.3
4346                 ///
4347                 ///    Returns : p    if a->p is better,
4348                 ///              q    if a->q is better,
4349                 ///              null if neither is better
4350                 /// </summary>
4351                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4352                 {
4353                         Type argument_type = TypeManager.TypeToCoreType (a.Type);
4354                         Expression argument_expr = a.Expr;
4355
4356                         // p = TypeManager.TypeToCoreType (p);
4357                         // q = TypeManager.TypeToCoreType (q);
4358
4359                         if (argument_type == null)
4360                                 throw new Exception ("Expression of type " + a.Expr +
4361                                                      " does not resolve its type");
4362
4363                         if (p == null || q == null)
4364                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
4365
4366                         if (p == q)
4367                                 return null;
4368
4369                         if (argument_expr is NullLiteral) {
4370                         //
4371                                 // If the argument is null and one of the types to compare is 'object' and
4372                                 // the other is a reference type, we prefer the other.
4373                         //
4374                                 // This follows from the usual rules:
4375                                 //   * There is an implicit conversion from 'null' to type 'object'
4376                                 //   * There is an implicit conversion from 'null' to any reference type
4377                                 //   * There is an implicit conversion from any reference type to type 'object'
4378                                 //   * There is no implicit conversion from type 'object' to other reference types
4379                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
4380                                 //
4381                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
4382                                 //         null type. I think it used to be 'object' and thus needed a special 
4383                                 //         case to avoid the immediately following two checks.
4384                                 //
4385                                 if (!p.IsValueType && q == TypeManager.object_type)
4386                                         return p;
4387                                 if (!q.IsValueType && p == TypeManager.object_type)
4388                                         return q;
4389                         }
4390                         
4391                         if (argument_type == p)
4392                                 return p;
4393
4394                         if (argument_type == q)
4395                                 return q;
4396
4397                         Expression p_tmp = new EmptyExpression (p);
4398                         Expression q_tmp = new EmptyExpression (q);
4399                         
4400                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4401                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4402
4403                         if (p_to_q && !q_to_p)
4404                                 return p;
4405
4406                         if (q_to_p && !p_to_q)
4407                                 return q;
4408
4409                         if (p == TypeManager.sbyte_type)
4410                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4411                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4412                                         return p;
4413                         if (q == TypeManager.sbyte_type)
4414                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4415                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4416                                         return q;
4417
4418                         if (p == TypeManager.short_type)
4419                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4420                                     q == TypeManager.uint64_type)
4421                                         return p;
4422
4423                         if (q == TypeManager.short_type)
4424                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4425                                     p == TypeManager.uint64_type)
4426                                         return q;
4427
4428                         if (p == TypeManager.int32_type)
4429                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4430                                         return p;
4431
4432                         if (q == TypeManager.int32_type)
4433                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4434                                         return q;
4435
4436                         if (p == TypeManager.int64_type)
4437                                 if (q == TypeManager.uint64_type)
4438                                         return p;
4439                         if (q == TypeManager.int64_type)
4440                                 if (p == TypeManager.uint64_type)
4441                                         return q;
4442
4443                         return null;
4444                 }
4445                 
4446                 /// <summary>
4447                 ///   Determines "Better function" between candidate
4448                 ///   and the current best match
4449                 /// </summary>
4450                 /// <remarks>
4451                 ///    Returns a boolean indicating :
4452                 ///     false if candidate ain't better
4453                 ///     true  if candidate is better than the current best match
4454                 /// </remarks>
4455                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4456                                            MethodBase candidate, bool candidate_params,
4457                                            MethodBase best, bool best_params, Location loc)
4458                 {
4459                         ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4460                         ParameterData best_pd = TypeManager.GetParameterData (best);
4461                 
4462                         bool better_at_least_one = false;
4463                         bool same = true;
4464                         for (int j = 0; j < argument_count; ++j) {
4465                                 Argument a = (Argument) args [j];
4466
4467                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4468                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4469
4470                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4471                                         if (candidate_params)
4472                                                 ct = TypeManager.GetElementType (ct);
4473
4474                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4475                                         if (best_params)
4476                                                 bt = TypeManager.GetElementType (bt);
4477
4478                                 if (ct.Equals (bt))
4479                                         continue;
4480
4481                                 same = false;
4482                                 Type better = BetterConversion (ec, a, ct, bt, loc);
4483                                 // for each argument, the conversion to 'ct' should be no worse than 
4484                                 // the conversion to 'bt'.
4485                                 if (better == bt)
4486                                         return false;
4487                                 
4488                                 // for at least one argument, the conversion to 'ct' should be better than 
4489                                 // the conversion to 'bt'.
4490                                 if (better == ct)
4491                                         better_at_least_one = true;
4492                         }
4493
4494                         if (better_at_least_one)
4495                                 return true;
4496
4497                         if (!same)
4498                                 return false;
4499
4500                         //
4501                         // If two methods have equal parameter types, but
4502                         // only one of them is generic, the non-generic one wins.
4503                         //
4504                         if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
4505                                 return true;
4506                         else if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
4507                                 return false;
4508
4509                         //
4510                         // Note that this is not just an optimization.  This handles the case
4511                         //
4512                         //   Add (float f1, float f2, float f3);
4513                         //   Add (params decimal [] foo);
4514                         //
4515                         // The call Add (3, 4, 5) should be ambiguous.  Without this check, the
4516                         // first candidate would've chosen as better.
4517                         //
4518                         if (candidate_params == best_params) {
4519                                 //
4520                                 // We need to handle the case of a virtual function and its override.
4521                                 // The override is ignored during 'applicable_type' calculation.  However,
4522                                 // it should be chosen over the base virtual function, especially when handling
4523                                 // value types.
4524                                 //
4525                                 return IsAncestralType (best.DeclaringType, candidate.DeclaringType);
4526                         }
4527
4528                         //
4529                         // This handles the following cases:
4530                         //
4531                         //   Trim () is better than Trim (params char[] chars)
4532                         //   Concat (string s1, string s2, string s3) is better than
4533                         //     Concat (string s1, params string [] srest)
4534                         //
4535                         return !candidate_params && best_params;
4536                 }
4537
4538                 public static string FullMethodDesc (MethodBase mb)
4539                 {
4540                         string ret_type = "";
4541
4542                         if (mb == null)
4543                                 return "";
4544
4545                         if (mb is MethodInfo)
4546                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4547                         
4548                         StringBuilder sb = new StringBuilder (ret_type);
4549                         sb.Append (" ");
4550                         sb.Append (mb.ReflectedType.ToString ());
4551                         sb.Append (".");
4552                         sb.Append (mb.Name);
4553                         
4554                         ParameterData pd = TypeManager.GetParameterData (mb);
4555
4556                         int count = pd.Count;
4557                         sb.Append (" (");
4558                         
4559                         for (int i = count; i > 0; ) {
4560                                 i--;
4561
4562                                 sb.Append (pd.ParameterDesc (count - i - 1));
4563                                 if (i != 0)
4564                                         sb.Append (", ");
4565                         }
4566                         
4567                         sb.Append (")");
4568                         return sb.ToString ();
4569                 }
4570
4571                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4572                 {
4573                         MemberInfo [] miset;
4574                         MethodGroupExpr union;
4575
4576                         if (mg1 == null) {
4577                                 if (mg2 == null)
4578                                         return null;
4579                                 return (MethodGroupExpr) mg2;
4580                         } else {
4581                                 if (mg2 == null)
4582                                         return (MethodGroupExpr) mg1;
4583                         }
4584                         
4585                         MethodGroupExpr left_set = null, right_set = null;
4586                         int length1 = 0, length2 = 0;
4587                         
4588                         left_set = (MethodGroupExpr) mg1;
4589                         length1 = left_set.Methods.Length;
4590                         
4591                         right_set = (MethodGroupExpr) mg2;
4592                         length2 = right_set.Methods.Length;
4593                         
4594                         ArrayList common = new ArrayList ();
4595
4596                         foreach (MethodBase r in right_set.Methods){
4597                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4598                                         common.Add (r);
4599                         }
4600
4601                         miset = new MemberInfo [length1 + length2 - common.Count];
4602                         left_set.Methods.CopyTo (miset, 0);
4603                         
4604                         int k = length1;
4605
4606                         foreach (MethodBase r in right_set.Methods) {
4607                                 if (!common.Contains (r))
4608                                         miset [k++] = r;
4609                         }
4610
4611                         union = new MethodGroupExpr (miset, loc);
4612                         
4613                         return union;
4614                 }
4615
4616                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4617                                                       ArrayList arguments, int arg_count,
4618                                                       ref MethodBase candidate)
4619                 {
4620                         return IsParamsMethodApplicable (
4621                                 ec, me, arguments, arg_count, false, ref candidate) ||
4622                                 IsParamsMethodApplicable (
4623                                         ec, me, arguments, arg_count, true, ref candidate);
4624
4625
4626                 }
4627
4628                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4629                                                       ArrayList arguments, int arg_count,
4630                                                       bool do_varargs, ref MethodBase candidate)
4631                 {
4632                         if (!me.HasTypeArguments &&
4633                             !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4634                                 return false;
4635
4636                         return IsParamsMethodApplicable (
4637                                 ec, arguments, arg_count, candidate, do_varargs);
4638                 }
4639
4640                 /// <summary>
4641                 ///   Determines if the candidate method, if a params method, is applicable
4642                 ///   in its expanded form to the given set of arguments
4643                 /// </summary>
4644                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4645                                                       int arg_count, MethodBase candidate,
4646                                                       bool do_varargs)
4647                 {
4648                         ParameterData pd = TypeManager.GetParameterData (candidate);
4649                         
4650                         int pd_count = pd.Count;
4651
4652                         if (pd_count == 0)
4653                                 return false;
4654                         
4655                         int count = pd_count - 1;
4656                         if (do_varargs) {
4657                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4658                                         return false;
4659                                 if (pd_count != arg_count)
4660                                         return false;
4661                         } else {
4662                                 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4663                                 return false;
4664                         }
4665                         
4666                         if (count > arg_count)
4667                                 return false;
4668                         
4669                         if (pd_count == 1 && arg_count == 0)
4670                                 return true;
4671
4672                         //
4673                         // If we have come this far, the case which
4674                         // remains is when the number of parameters is
4675                         // less than or equal to the argument count.
4676                         //
4677                         for (int i = 0; i < count; ++i) {
4678
4679                                 Argument a = (Argument) arguments [i];
4680
4681                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4682                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4683                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4684                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4685
4686                                 if (a_mod == p_mod) {
4687
4688                                         if (a_mod == Parameter.Modifier.NONE)
4689                                                 if (!Convert.ImplicitConversionExists (ec,
4690                                                                                        a.Expr,
4691                                                                                        pd.ParameterType (i)))
4692                                                         return false;
4693                                                                                 
4694                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4695                                                 Type pt = pd.ParameterType (i);
4696
4697                                                 if (!pt.IsByRef)
4698                                                         pt = TypeManager.GetReferenceType (pt);
4699                                                 
4700                                                 if (pt != a.Type)
4701                                                         return false;
4702                                         }
4703                                 } else
4704                                         return false;
4705                                 
4706                         }
4707
4708                         if (do_varargs) {
4709                                 Argument a = (Argument) arguments [count];
4710                                 if (!(a.Expr is Arglist))
4711                                         return false;
4712
4713                                 return true;
4714                         }
4715
4716                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4717
4718                         for (int i = pd_count - 1; i < arg_count; i++) {
4719                                 Argument a = (Argument) arguments [i];
4720                                 
4721                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4722                                         return false;
4723                         }
4724                         
4725                         return true;
4726                 }
4727
4728                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4729                                           ArrayList arguments, int arg_count,
4730                                           ref MethodBase candidate)
4731                 {
4732                         if (!me.HasTypeArguments &&
4733                             !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4734                                 return false;
4735
4736                         return IsApplicable (ec, arguments, arg_count, candidate);
4737                 }
4738
4739                 /// <summary>
4740                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4741                 ///   to the given set of arguments
4742                 /// </summary>
4743                 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4744                                           MethodBase candidate)
4745                 {
4746                         ParameterData pd = TypeManager.GetParameterData (candidate);
4747
4748                         if (arg_count != pd.Count)
4749                                 return false;
4750
4751                         for (int i = arg_count; i > 0; ) {
4752                                 i--;
4753
4754                                 Argument a = (Argument) arguments [i];
4755
4756                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4757                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4758                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4759                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4760
4761
4762                                 if (a_mod == p_mod ||
4763                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4764                                         if (a_mod == Parameter.Modifier.NONE) {
4765                                                 if (!Convert.ImplicitConversionExists (ec,
4766                                                                                        a.Expr,
4767                                                                                        pd.ParameterType (i)))
4768                                                         return false;
4769                                         }
4770                                         
4771                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4772                                                 Type pt = pd.ParameterType (i);
4773
4774                                                 if (!pt.IsByRef)
4775                                                         pt = TypeManager.GetReferenceType (pt);
4776                                                 
4777                                                 if (pt != a.Type)
4778                                                         return false;
4779                                         }
4780                                 } else
4781                                         return false;
4782                         }
4783
4784                         return true;
4785                 }
4786                 
4787                 static private bool IsAncestralType (Type first_type, Type second_type)
4788                 {
4789                         return first_type != second_type &&
4790                                 (second_type.IsSubclassOf (first_type) ||
4791                                  TypeManager.ImplementsInterface (second_type, first_type));
4792                 }
4793                 
4794                 /// <summary>
4795                 ///   Find the Applicable Function Members (7.4.2.1)
4796                 ///
4797                 ///   me: Method Group expression with the members to select.
4798                 ///       it might contain constructors or methods (or anything
4799                 ///       that maps to a method).
4800                 ///
4801                 ///   Arguments: ArrayList containing resolved Argument objects.
4802                 ///
4803                 ///   loc: The location if we want an error to be reported, or a Null
4804                 ///        location for "probing" purposes.
4805                 ///
4806                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4807                 ///            that is the best match of me on Arguments.
4808                 ///
4809                 /// </summary>
4810                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4811                                                           ArrayList Arguments, bool may_fail,
4812                                                           Location loc)
4813                 {
4814                         MethodBase method = null;
4815                         bool method_params = false;
4816                         Type applicable_type = null;
4817                         int arg_count = 0;
4818                         ArrayList candidates = new ArrayList ();
4819
4820                         //
4821                         // Used to keep a map between the candidate
4822                         // and whether it is being considered in its
4823                         // normal or expanded form
4824                         //
4825                         // false is normal form, true is expanded form
4826                         //
4827                         Hashtable candidate_to_form = null;
4828
4829                         if (Arguments != null)
4830                                 arg_count = Arguments.Count;
4831   
4832                         if ((me.Name == "Invoke") &&
4833                             TypeManager.IsDelegateType (me.DeclaringType)) {
4834                                 Error_InvokeOnDelegate (loc);
4835                                 return null;
4836                         }
4837
4838                         MethodBase[] methods = me.Methods;
4839
4840                         //
4841                         // First we construct the set of applicable methods
4842                         //
4843                         bool is_sorted = true;
4844                         for (int i = 0; i < methods.Length; i++){
4845                                 Type decl_type = methods [i].DeclaringType;
4846
4847                                 //
4848                                 // If we have already found an applicable method
4849                                 // we eliminate all base types (Section 14.5.5.1)
4850                                 //
4851                                 if ((applicable_type != null) &&
4852                                     IsAncestralType (decl_type, applicable_type))
4853                                         continue;
4854
4855                                 //
4856                                 // Check if candidate is applicable (section 14.4.2.1)
4857                                 //   Is candidate applicable in normal form?
4858                                 //
4859                                 bool is_applicable = IsApplicable (
4860                                         ec, me, Arguments, arg_count, ref methods [i]);
4861
4862                                 if (!is_applicable &&
4863                                     (IsParamsMethodApplicable (
4864                                             ec, me, Arguments, arg_count, ref methods [i]))) {
4865                                         MethodBase candidate = methods [i];
4866                                         if (candidate_to_form == null)
4867                                                 candidate_to_form = new PtrHashtable ();
4868                                         candidate_to_form [candidate] = candidate;
4869                                         // Candidate is applicable in expanded form
4870                                         is_applicable = true;
4871                                 }
4872
4873                                 if (!is_applicable)
4874                                         continue;
4875
4876                                 candidates.Add (methods [i]);
4877
4878                                 //
4879                                 // Methods marked 'override' don't take part in 'applicable_type'
4880                                 // computation.
4881                                 //
4882                                 if (!me.IsBase &&
4883                                     methods [i].IsVirtual &&
4884                                     (methods [i].Attributes & MethodAttributes.NewSlot) == 0)
4885                                         continue;
4886
4887                                 if (applicable_type == null)
4888                                         applicable_type = decl_type;
4889                                 else if (applicable_type != decl_type) {
4890                                         is_sorted = false;
4891                                         if (IsAncestralType (applicable_type, decl_type))
4892                                                 applicable_type = decl_type;
4893                                 }
4894                         }
4895
4896                         int candidate_top = candidates.Count;
4897
4898                         if (applicable_type == null) {
4899                                 //
4900                                 // Okay so we have failed to find anything so we
4901                                 // return by providing info about the closest match
4902                                 //
4903                                 for (int i = 0; i < methods.Length; ++i) {
4904                                         MethodBase c = (MethodBase) methods [i];
4905                                         ParameterData pd = TypeManager.GetParameterData (c);
4906
4907                                         if (pd.Count != arg_count)
4908                                                 continue;
4909
4910                                         if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
4911                                                 continue;
4912
4913                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4914                                                                c, false, null, may_fail, loc);
4915                                         break;
4916                                 }
4917
4918                                 if (!may_fail) {
4919                                         string report_name = me.Name;
4920                                         if (report_name == ".ctor")
4921                                                 report_name = me.DeclaringType.ToString ();
4922                                         
4923                                         for (int i = 0; i < methods.Length; ++i) {
4924                                                 MethodBase c = methods [i];
4925                                                 ParameterData pd = TypeManager.GetParameterData (c);
4926
4927                                                 if (pd.Count != arg_count)
4928                                                         continue;
4929
4930                                                 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
4931                                                         continue;
4932
4933                                                 Report.Error (
4934                                                         411, loc, "The type arguments for " +
4935                                                         "method `{0}' cannot be infered from " +
4936                                                         "the usage. Try specifying the type " +
4937                                                         "arguments explicitly.", report_name);
4938                                                 return null;
4939                                         }
4940
4941                                         Error_WrongNumArguments (
4942                                                 loc, report_name, arg_count);
4943                                         return null;
4944                                 }
4945
4946                                 return null;
4947                         }
4948
4949                         if (!is_sorted) {
4950                                 //
4951                                 // At this point, applicable_type is _one_ of the most derived types
4952                                 // in the set of types containing the methods in this MethodGroup.
4953                                 // Filter the candidates so that they only contain methods from the
4954                                 // most derived types.
4955                                 //
4956
4957                                 int finalized = 0; // Number of finalized candidates
4958
4959                                 do {
4960                                         // Invariant: applicable_type is a most derived type
4961                                         
4962                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4963                                         // eliminating all it's base types.  At the same time, we'll also move
4964                                         // every unrelated type to the end of the array, and pick the next
4965                                         // 'applicable_type'.
4966
4967                                         Type next_applicable_type = null;
4968                                         int j = finalized; // where to put the next finalized candidate
4969                                         int k = finalized; // where to put the next undiscarded candidate
4970                                         for (int i = finalized; i < candidate_top; ++i) {
4971                                                 MethodBase candidate = (MethodBase) candidates [i];
4972                                                 Type decl_type = candidate.DeclaringType;
4973
4974                                                 if (decl_type == applicable_type) {
4975                                                         candidates [k++] = candidates [j];
4976                                                         candidates [j++] = candidates [i];
4977                                                         continue;
4978                                                 }
4979
4980                                                 if (IsAncestralType (decl_type, applicable_type))
4981                                                         continue;
4982
4983                                                 if (next_applicable_type != null &&
4984                                                     IsAncestralType (decl_type, next_applicable_type))
4985                                                         continue;
4986
4987                                                 candidates [k++] = candidates [i];
4988
4989 #if false
4990                                                 //
4991                                                 // Methods marked 'override' don't take part in 'applicable_type'
4992                                                 // computation.
4993                                                 //
4994                                                 if (!me.IsBase &&
4995                                                     candidate.IsVirtual &&
4996                                                     (candidate.Attributes & MethodAttributes.NewSlot) == 0)
4997                                                         continue;
4998 #endif
4999
5000                                                 if (next_applicable_type == null ||
5001                                                     IsAncestralType (next_applicable_type, decl_type))
5002                                                         next_applicable_type = decl_type;
5003                                         }
5004
5005                                         applicable_type = next_applicable_type;
5006                                         finalized = j;
5007                                         candidate_top = k;
5008                                 } while (applicable_type != null);
5009                         }
5010
5011                         //
5012                         // Now we actually find the best method
5013                         //
5014
5015                         method = (MethodBase) candidates [0];
5016                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
5017                         for (int ix = 1; ix < candidate_top; ix++){
5018                                 MethodBase candidate = (MethodBase) candidates [ix];
5019
5020                                 if (candidate == method)
5021                                         continue;
5022
5023                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5024
5025                                 if (BetterFunction (ec, Arguments, arg_count, 
5026                                                     candidate, cand_params,
5027                                                     method, method_params, loc)) {
5028                                         method = candidate;
5029                                         method_params = cand_params;
5030                                 }
5031                         }
5032
5033                         //
5034                         // Now check that there are no ambiguities i.e the selected method
5035                         // should be better than all the others
5036                         //
5037                         bool ambiguous = false;
5038                         for (int ix = 0; ix < candidate_top; ix++){
5039                                 MethodBase candidate = (MethodBase) candidates [ix];
5040
5041                                 if (candidate == method)
5042                                         continue;
5043
5044                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5045                                 if (!BetterFunction (ec, Arguments, arg_count,
5046                                                     method, method_params,
5047                                                     candidate, cand_params,
5048                                                      loc)) {
5049                                         Report.SymbolRelatedToPreviousError (candidate);
5050                                         ambiguous = true;
5051                                 }
5052                         }
5053
5054                         if (ambiguous) {
5055                                 Report.SymbolRelatedToPreviousError (method);
5056                                 Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts");                                        
5057                                 return null;
5058                         }
5059
5060                         //
5061                         // And now check if the arguments are all
5062                         // compatible, perform conversions if
5063                         // necessary etc. and return if everything is
5064                         // all right
5065                         //
5066                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
5067                                                     method_params, null, may_fail, loc))
5068                                 return null;
5069
5070                         return method;
5071                 }
5072
5073                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
5074                 {
5075                         Report.Error (1501, loc,
5076                                       "No overload for method `" + name + "' takes `" +
5077                                       arg_count + "' arguments");
5078                 }
5079
5080                 static void Error_InvokeOnDelegate (Location loc)
5081                 {
5082                         Report.Error (1533, loc,
5083                                       "Invoke cannot be called directly on a delegate");
5084                 }
5085                         
5086                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
5087                                                     Type delegate_type, string arg_sig, string par_desc)
5088                 {
5089                         if (delegate_type == null) 
5090                                 Report.Error (1502, loc,
5091                                               "The best overloaded match for method '" +
5092                                               FullMethodDesc (method) +
5093                                               "' has some invalid arguments");
5094                         else
5095                                 Report.Error (1594, loc,
5096                                               "Delegate '" + delegate_type.ToString () +
5097                                               "' has some invalid arguments.");
5098                         Report.Error (1503, loc,
5099                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
5100                                                      idx, arg_sig, par_desc));
5101                 }
5102                 
5103                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
5104                                                           int arg_count, MethodBase method, 
5105                                                           bool chose_params_expanded,
5106                                                           Type delegate_type, bool may_fail,
5107                                                           Location loc)
5108                 {
5109                         ParameterData pd = TypeManager.GetParameterData (method);
5110                         int pd_count = pd.Count;
5111                         
5112                         for (int j = 0; j < arg_count; j++) {
5113                                 Argument a = (Argument) Arguments [j];
5114                                 Expression a_expr = a.Expr;
5115                                 Type parameter_type = pd.ParameterType (j);
5116                                 Parameter.Modifier pm = pd.ParameterModifier (j);
5117                                 
5118                                 if (pm == Parameter.Modifier.PARAMS){
5119                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
5120                                                 if (!may_fail)
5121                                                         Error_InvalidArguments (
5122                                                                 loc, j, method, delegate_type,
5123                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5124                                                 return false;
5125                                         }
5126
5127                                         if (chose_params_expanded)
5128                                                 parameter_type = TypeManager.GetElementType (parameter_type);
5129                                 } else if (pm == Parameter.Modifier.ARGLIST){
5130                                         continue;
5131                                 } else {
5132                                         //
5133                                         // Check modifiers
5134                                         //
5135                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
5136                                                 if (!may_fail)
5137                                                         Error_InvalidArguments (
5138                                                                 loc, j, method, delegate_type,
5139                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5140                                                 return false;
5141                                         }
5142                                 }
5143
5144                                 //
5145                                 // Check Type
5146                                 //
5147                                 if (!TypeManager.IsEqual (a.Type, parameter_type)){
5148                                         Expression conv;
5149
5150                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5151
5152                                         if (conv == null) {
5153                                                 if (!may_fail)
5154                                                         Error_InvalidArguments (
5155                                                                 loc, j, method, delegate_type,
5156                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5157                                                 return false;
5158                                         }
5159                                         
5160                                         //
5161                                         // Update the argument with the implicit conversion
5162                                         //
5163                                         if (a_expr != conv)
5164                                                 a.Expr = conv;
5165                                 }
5166
5167                                 if (parameter_type.IsPointer){
5168                                         if (!ec.InUnsafe){
5169                                                 UnsafeError (loc);
5170                                                 return false;
5171                                         }
5172                                 }
5173                                 
5174                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
5175                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5176                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5177                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5178                                 
5179                                 if (a_mod != p_mod &&
5180                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5181                                         if (!may_fail) {
5182                                                 Report.Error (1502, loc,
5183                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
5184                                                        "' has some invalid arguments");
5185                                                 Report.Error (1503, loc,
5186                                                        "Argument " + (j+1) +
5187                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
5188                                                        + "' to '" + pd.ParameterDesc (j) + "'");
5189                                         }
5190                                         
5191                                         return false;
5192                                 }
5193                         }
5194
5195                         return true;
5196                 }
5197
5198                 public override Expression DoResolve (EmitContext ec)
5199                 {
5200                         //
5201                         // First, resolve the expression that is used to
5202                         // trigger the invocation
5203                         //
5204                         if (expr is ConstructedType)
5205                                 expr = ((ConstructedType) expr).GetSimpleName (ec);
5206
5207                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5208                         if (expr == null)
5209                                 return null;
5210
5211                         if (!(expr is MethodGroupExpr)) {
5212                                 Type expr_type = expr.Type;
5213
5214                                 if (expr_type != null){
5215                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5216                                         if (IsDelegate)
5217                                                 return (new DelegateInvocation (
5218                                                         this.expr, Arguments, loc)).Resolve (ec);
5219                                 }
5220                         }
5221
5222                         if (!(expr is MethodGroupExpr)){
5223                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5224                                 return null;
5225                         }
5226
5227                         //
5228                         // Next, evaluate all the expressions in the argument list
5229                         //
5230                         if (Arguments != null){
5231                                 foreach (Argument a in Arguments){
5232                                         if (!a.Resolve (ec, loc))
5233                                                 return null;
5234                                 }
5235                         }
5236
5237                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5238                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5239
5240                         if (method == null)
5241                                 return null;
5242
5243                         MethodInfo mi = method as MethodInfo;
5244                         if (mi != null) {
5245                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5246                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5247                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5248                                         return null;
5249                                 }
5250
5251                                 Expression iexpr = mg.InstanceExpression;
5252                                 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5253                                         if (mg.IdenticalTypeName)
5254                                                 mg.InstanceExpression = null;
5255                                         else {
5256                                                 MemberAccess.error176 (loc, mi.Name);
5257                                                 return null;
5258                                         }
5259                                 }
5260                         }
5261
5262                         if (type.IsPointer){
5263                                 if (!ec.InUnsafe){
5264                                         UnsafeError (loc);
5265                                         return null;
5266                                 }
5267                         }
5268                         
5269                         //
5270                         // Only base will allow this invocation to happen.
5271                         //
5272                         if (mg.IsBase && method.IsAbstract){
5273                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5274                                               FullMethodDesc (method));
5275                                 return null;
5276                         }
5277
5278                         if (method.Name == "Finalize" && Arguments == null) {
5279                                 if (mg.IsBase)
5280                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5281                                 else
5282                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5283                                 return null;
5284                         }
5285
5286                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
5287                                 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5288                                         Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor");
5289                                         return null;
5290                                 }
5291                         }
5292                         
5293                         if (mg.InstanceExpression != null)
5294                                 mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
5295
5296                         eclass = ExprClass.Value;
5297                         return this;
5298                 }
5299
5300                 // <summary>
5301                 //   Emits the list of arguments as an array
5302                 // </summary>
5303                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5304                 {
5305                         ILGenerator ig = ec.ig;
5306                         int count = arguments.Count - idx;
5307                         Argument a = (Argument) arguments [idx];
5308                         Type t = a.Expr.Type;
5309
5310                         IntConstant.EmitInt (ig, count);
5311                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5312
5313                         int top = arguments.Count;
5314                         for (int j = idx; j < top; j++){
5315                                 a = (Argument) arguments [j];
5316                                 
5317                                 ig.Emit (OpCodes.Dup);
5318                                 IntConstant.EmitInt (ig, j - idx);
5319
5320                                 bool is_stobj, has_type_arg;
5321                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5322                                 if (is_stobj)
5323                                         ig.Emit (OpCodes.Ldelema, t);
5324
5325                                 a.Emit (ec);
5326
5327                                 if (has_type_arg)
5328                                         ig.Emit (op, t);
5329                                 else
5330                                         ig.Emit (op);
5331                         }
5332                 }
5333                 
5334                 /// <summary>
5335                 ///   Emits a list of resolved Arguments that are in the arguments
5336                 ///   ArrayList.
5337                 /// 
5338                 ///   The MethodBase argument might be null if the
5339                 ///   emission of the arguments is known not to contain
5340                 ///   a `params' field (for example in constructors or other routines
5341                 ///   that keep their arguments in this structure)
5342                 ///   
5343                 ///   if `dup_args' is true, a copy of the arguments will be left
5344                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5345                 ///   which will be duplicated before any other args. Only EmitCall
5346                 ///   should be using this interface.
5347                 /// </summary>
5348                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5349                 {
5350                         ParameterData pd;
5351                         if (mb != null)
5352                                 pd = TypeManager.GetParameterData (mb);
5353                         else
5354                                 pd = null;
5355                         
5356                         LocalTemporary [] temps = null;
5357                         
5358                         if (dup_args)
5359                                 temps = new LocalTemporary [arguments.Count];
5360
5361                         //
5362                         // If we are calling a params method with no arguments, special case it
5363                         //
5364                         if (arguments == null){
5365                                 if (pd != null && pd.Count > 0 &&
5366                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5367                                         ILGenerator ig = ec.ig;
5368
5369                                         IntConstant.EmitInt (ig, 0);
5370                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5371                                 }
5372
5373                                 return;
5374                         }
5375
5376                         int top = arguments.Count;
5377
5378                         for (int i = 0; i < top; i++){
5379                                 Argument a = (Argument) arguments [i];
5380
5381                                 if (pd != null){
5382                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5383                                                 //
5384                                                 // Special case if we are passing the same data as the
5385                                                 // params argument, do not put it in an array.
5386                                                 //
5387                                                 if (pd.ParameterType (i) == a.Type)
5388                                                         a.Emit (ec);
5389                                                 else
5390                                                         EmitParams (ec, i, arguments);
5391                                                 return;
5392                                         }
5393                                 }
5394                                             
5395                                 a.Emit (ec);
5396                                 if (dup_args) {
5397                                         ec.ig.Emit (OpCodes.Dup);
5398                                         (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5399                                 }
5400                         }
5401                         
5402                         if (dup_args) {
5403                                 if (this_arg != null)
5404                                         this_arg.Emit (ec);
5405                                 
5406                                 for (int i = 0; i < top; i ++)
5407                                         temps [i].Emit (ec);
5408                         }
5409
5410                         if (pd != null && pd.Count > top &&
5411                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5412                                 ILGenerator ig = ec.ig;
5413
5414                                 IntConstant.EmitInt (ig, 0);
5415                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5416                         }
5417                 }
5418
5419                 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5420                                                ArrayList arguments)
5421                 {
5422                         ParameterData pd = TypeManager.GetParameterData (mb);
5423
5424                         if (arguments == null)
5425                                 return new Type [0];
5426
5427                         Argument a = (Argument) arguments [pd.Count - 1];
5428                         Arglist list = (Arglist) a.Expr;
5429
5430                         return list.ArgumentTypes;
5431                 }
5432
5433                 /// <summary>
5434                 /// This checks the ConditionalAttribute on the method 
5435                 /// </summary>
5436                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5437                 {
5438                         if (method.IsConstructor)
5439                                 return false;
5440
5441                         IMethodData md = TypeManager.GetMethod (method);
5442                         if (md != null)
5443                                 return md.IsExcluded (ec);
5444
5445                         // For some methods (generated by delegate class) GetMethod returns null
5446                         // because they are not included in builder_to_method table
5447                         if (method.DeclaringType is TypeBuilder)
5448                                 return false;
5449
5450                         return AttributeTester.IsConditionalMethodExcluded (method);
5451                 }
5452
5453                 /// <remarks>
5454                 ///   is_base tells whether we want to force the use of the `call'
5455                 ///   opcode instead of using callvirt.  Call is required to call
5456                 ///   a specific method, while callvirt will always use the most
5457                 ///   recent method in the vtable.
5458                 ///
5459                 ///   is_static tells whether this is an invocation on a static method
5460                 ///
5461                 ///   instance_expr is an expression that represents the instance
5462                 ///   it must be non-null if is_static is false.
5463                 ///
5464                 ///   method is the method to invoke.
5465                 ///
5466                 ///   Arguments is the list of arguments to pass to the method or constructor.
5467                 /// </remarks>
5468                 public static void EmitCall (EmitContext ec, bool is_base,
5469                                              bool is_static, Expression instance_expr,
5470                                              MethodBase method, ArrayList Arguments, Location loc)
5471                 {
5472                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5473                 }
5474                 
5475                 // `dup_args' leaves an extra copy of the arguments on the stack
5476                 // `omit_args' does not leave any arguments at all.
5477                 // So, basically, you could make one call with `dup_args' set to true,
5478                 // and then another with `omit_args' set to true, and the two calls
5479                 // would have the same set of arguments. However, each argument would
5480                 // only have been evaluated once.
5481                 public static void EmitCall (EmitContext ec, bool is_base,
5482                                              bool is_static, Expression instance_expr,
5483                                              MethodBase method, ArrayList Arguments, Location loc,
5484                                              bool dup_args, bool omit_args)
5485                 {
5486                         ILGenerator ig = ec.ig;
5487                         bool struct_call = false;
5488                         bool this_call = false;
5489                         LocalTemporary this_arg = null;
5490
5491                         Type decl_type = method.DeclaringType;
5492
5493                         if (!RootContext.StdLib) {
5494                                 // Replace any calls to the system's System.Array type with calls to
5495                                 // the newly created one.
5496                                 if (method == TypeManager.system_int_array_get_length)
5497                                         method = TypeManager.int_array_get_length;
5498                                 else if (method == TypeManager.system_int_array_get_rank)
5499                                         method = TypeManager.int_array_get_rank;
5500                                 else if (method == TypeManager.system_object_array_clone)
5501                                         method = TypeManager.object_array_clone;
5502                                 else if (method == TypeManager.system_int_array_get_length_int)
5503                                         method = TypeManager.int_array_get_length_int;
5504                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5505                                         method = TypeManager.int_array_get_lower_bound_int;
5506                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5507                                         method = TypeManager.int_array_get_upper_bound_int;
5508                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5509                                         method = TypeManager.void_array_copyto_array_int;
5510                         }
5511
5512                         if (ec.TestObsoleteMethodUsage) {
5513                                 //
5514                                 // This checks ObsoleteAttribute on the method and on the declaring type
5515                                 //
5516                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5517                                 if (oa != null)
5518                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5519
5520                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5521                                 if (oa != null) {
5522                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5523                                 }
5524                         }
5525
5526                         if (IsMethodExcluded (method, ec))
5527                                 return;
5528                         
5529                         if (!is_static){
5530                                 this_call = instance_expr == null;
5531                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5532                                         struct_call = true;
5533
5534                                 //
5535                                 // If this is ourselves, push "this"
5536                                 //
5537                                 if (!omit_args) {
5538                                         Type t = null;
5539                                         if (this_call) {
5540                                                 ig.Emit (OpCodes.Ldarg_0);
5541                                                 t = decl_type;
5542                                         } else {
5543                                                 Type iexpr_type = instance_expr.Type;
5544
5545                                                 //
5546                                                 // Push the instance expression
5547                                                 //
5548                                                 if (TypeManager.IsValueType (iexpr_type)) {
5549                                                         //
5550                                                         // Special case: calls to a function declared in a 
5551                                                         // reference-type with a value-type argument need
5552                                                         // to have their value boxed.
5553                                                         if (decl_type.IsValueType ||
5554                                                             iexpr_type.IsGenericParameter) {
5555                                                                 //
5556                                                                 // If the expression implements IMemoryLocation, then
5557                                                                 // we can optimize and use AddressOf on the
5558                                                                 // return.
5559                                                                 //
5560                                                                 // If not we have to use some temporary storage for
5561                                                                 // it.
5562                                                                 if (instance_expr is IMemoryLocation) {
5563                                                                         ((IMemoryLocation)instance_expr).
5564                                                                                 AddressOf (ec, AddressOp.LoadStore);
5565                                                                 } else {
5566                                                                         LocalTemporary temp = new LocalTemporary (ec, iexpr_type);
5567                                                                         instance_expr.Emit (ec);
5568                                                                         temp.Store (ec);
5569                                                                         temp.AddressOf (ec, AddressOp.Load);
5570                                                                 }
5571
5572                                                                 // avoid the overhead of doing this all the time.
5573                                                                 if (dup_args)
5574                                                                         t = TypeManager.GetReferenceType (iexpr_type);
5575                                                         } else {
5576                                                                 instance_expr.Emit (ec);
5577                                                                 ig.Emit (OpCodes.Box, instance_expr.Type);
5578                                                                 t = TypeManager.object_type;
5579                                                         }
5580                                                 } else {
5581                                                         instance_expr.Emit (ec);
5582                                                         t = instance_expr.Type;
5583                                                 }
5584                                         }
5585
5586                                         if (dup_args) {
5587                                                 this_arg = new LocalTemporary (ec, t);
5588                                                 ig.Emit (OpCodes.Dup);
5589                                                 this_arg.Store (ec);
5590                                         }
5591                                 }
5592                         }
5593
5594                         if (!omit_args)
5595                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5596
5597                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5598                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5599
5600                         OpCode call_op;
5601                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5602                                 call_op = OpCodes.Call;
5603                         else
5604                                 call_op = OpCodes.Callvirt;
5605
5606                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5607                                 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5608                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5609                                 return;
5610                         }
5611
5612                         //
5613                         // If you have:
5614                         // this.DoFoo ();
5615                         // and DoFoo is not virtual, you can omit the callvirt,
5616                         // because you don't need the null checking behavior.
5617                         //
5618                         if (method is MethodInfo)
5619                                 ig.Emit (call_op, (MethodInfo) method);
5620                         else
5621                                 ig.Emit (call_op, (ConstructorInfo) method);
5622                 }
5623                 
5624                 public override void Emit (EmitContext ec)
5625                 {
5626                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5627
5628                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5629                 }
5630                 
5631                 public override void EmitStatement (EmitContext ec)
5632                 {
5633                         Emit (ec);
5634
5635                         // 
5636                         // Pop the return value if there is one
5637                         //
5638                         if (method is MethodInfo){
5639                                 Type ret = ((MethodInfo)method).ReturnType;
5640                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5641                                         ec.ig.Emit (OpCodes.Pop);
5642                         }
5643                 }
5644         }
5645
5646         public class InvocationOrCast : ExpressionStatement
5647         {
5648                 Expression expr;
5649                 Expression argument;
5650
5651                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5652                 {
5653                         this.expr = expr;
5654                         this.argument = argument;
5655                         this.loc = loc;
5656                 }
5657
5658                 public override Expression DoResolve (EmitContext ec)
5659                 {
5660                         //
5661                         // First try to resolve it as a cast.
5662                         //
5663                         TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr;
5664                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5665                                 Cast cast = new Cast (te, argument, loc);
5666                                 return cast.Resolve (ec);
5667                         }
5668
5669                         //
5670                         // This can either be a type or a delegate invocation.
5671                         // Let's just resolve it and see what we'll get.
5672                         //
5673                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5674                         if (expr == null)
5675                                 return null;
5676
5677                         //
5678                         // Ok, so it's a Cast.
5679                         //
5680                         if (expr.eclass == ExprClass.Type) {
5681                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5682                                 return cast.Resolve (ec);
5683                         }
5684
5685                         //
5686                         // It's a delegate invocation.
5687                         //
5688                         if (!TypeManager.IsDelegateType (expr.Type)) {
5689                                 Error (149, "Method name expected");
5690                                 return null;
5691                         }
5692
5693                         ArrayList args = new ArrayList ();
5694                         args.Add (new Argument (argument, Argument.AType.Expression));
5695                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5696                         return invocation.Resolve (ec);
5697                 }
5698
5699                 void error201 ()
5700                 {
5701                         Error (201, "Only assignment, call, increment, decrement and new object " +
5702                                "expressions can be used as a statement");
5703                 }
5704
5705                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5706                 {
5707                         //
5708                         // First try to resolve it as a cast.
5709                         //
5710                         TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr;
5711                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5712                                 error201 ();
5713                                 return null;
5714                         }
5715
5716                         //
5717                         // This can either be a type or a delegate invocation.
5718                         // Let's just resolve it and see what we'll get.
5719                         //
5720                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5721                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5722                                 error201 ();
5723                                 return null;
5724                         }
5725
5726                         //
5727                         // It's a delegate invocation.
5728                         //
5729                         if (!TypeManager.IsDelegateType (expr.Type)) {
5730                                 Error (149, "Method name expected");
5731                                 return null;
5732                         }
5733
5734                         ArrayList args = new ArrayList ();
5735                         args.Add (new Argument (argument, Argument.AType.Expression));
5736                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5737                         return invocation.ResolveStatement (ec);
5738                 }
5739
5740                 public override void Emit (EmitContext ec)
5741                 {
5742                         throw new Exception ("Cannot happen");
5743                 }
5744
5745                 public override void EmitStatement (EmitContext ec)
5746                 {
5747                         throw new Exception ("Cannot happen");
5748                 }
5749         }
5750
5751         //
5752         // This class is used to "disable" the code generation for the
5753         // temporary variable when initializing value types.
5754         //
5755         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5756                 public void AddressOf (EmitContext ec, AddressOp Mode)
5757                 {
5758                         // nothing
5759                 }
5760         }
5761         
5762         /// <summary>
5763         ///    Implements the new expression 
5764         /// </summary>
5765         public class New : ExpressionStatement, IMemoryLocation {
5766                 public readonly ArrayList Arguments;
5767
5768                 //
5769                 // During bootstrap, it contains the RequestedType,
5770                 // but if `type' is not null, it *might* contain a NewDelegate
5771                 // (because of field multi-initialization)
5772                 //
5773                 public Expression RequestedType;
5774
5775                 MethodBase method = null;
5776
5777                 //
5778                 // If set, the new expression is for a value_target, and
5779                 // we will not leave anything on the stack.
5780                 //
5781                 Expression value_target;
5782                 bool value_target_set = false;
5783                 bool is_type_parameter = false;
5784                 
5785                 public New (Expression requested_type, ArrayList arguments, Location l)
5786                 {
5787                         RequestedType = requested_type;
5788                         Arguments = arguments;
5789                         loc = l;
5790                 }
5791
5792                 public bool SetValueTypeVariable (Expression value)
5793                 {
5794                         value_target = value;
5795                         value_target_set = true;
5796                         if (!(value_target is IMemoryLocation)){
5797                                 Error_UnexpectedKind ("variable", loc);
5798                                 return false;
5799                         }
5800                         return true;
5801                 }
5802
5803                 //
5804                 // This function is used to disable the following code sequence for
5805                 // value type initialization:
5806                 //
5807                 // AddressOf (temporary)
5808                 // Construct/Init
5809                 // LoadTemporary
5810                 //
5811                 // Instead the provide will have provided us with the address on the
5812                 // stack to store the results.
5813                 //
5814                 static Expression MyEmptyExpression;
5815                 
5816                 public void DisableTemporaryValueType ()
5817                 {
5818                         if (MyEmptyExpression == null)
5819                                 MyEmptyExpression = new EmptyAddressOf ();
5820
5821                         //
5822                         // To enable this, look into:
5823                         // test-34 and test-89 and self bootstrapping.
5824                         //
5825                         // For instance, we can avoid a copy by using `newobj'
5826                         // instead of Call + Push-temp on value types.
5827 //                      value_target = MyEmptyExpression;
5828                 }
5829
5830                 public override Expression DoResolve (EmitContext ec)
5831                 {
5832                         //
5833                         // The New DoResolve might be called twice when initializing field
5834                         // expressions (see EmitFieldInitializers, the call to
5835                         // GetInitializerExpression will perform a resolve on the expression,
5836                         // and later the assign will trigger another resolution
5837                         //
5838                         // This leads to bugs (#37014)
5839                         //
5840                         if (type != null){
5841                                 if (RequestedType is NewDelegate)
5842                                         return RequestedType;
5843                                 return this;
5844                         }
5845                         
5846                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec);
5847                         if (texpr == null)
5848                                 return null;
5849                         
5850                         type = texpr.Type;
5851                         if (type == null)
5852                                 return null;
5853                         
5854                         CheckObsoleteAttribute (type);
5855
5856                         bool IsDelegate = TypeManager.IsDelegateType (type);
5857                         
5858                         if (IsDelegate){
5859                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5860                                 if (RequestedType != null)
5861                                         if (!(RequestedType is DelegateCreation))
5862                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5863                                 return RequestedType;
5864                         }
5865
5866                         if (type.IsGenericParameter) {
5867                                 if (!TypeManager.HasConstructorConstraint (type)) {
5868                                         Error (304, String.Format (
5869                                                        "Cannot create an instance of the " +
5870                                                        "variable type '{0}' because it " +
5871                                                        "doesn't have the new() constraint",
5872                                                        type));
5873                                         return null;
5874                                 }
5875
5876                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5877                                         Error (417, String.Format (
5878                                                        "`{0}': cannot provide arguments " +
5879                                                        "when creating an instance of a " +
5880                                                        "variable type.", type));
5881                                         return null;
5882                                 }
5883
5884                                 is_type_parameter = true;
5885                                 eclass = ExprClass.Value;
5886                                 return this;
5887                         }
5888
5889                         if (type.IsInterface || type.IsAbstract){
5890                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5891                                 return null;
5892                         }
5893
5894                         if (type.IsAbstract && type.IsSealed) {
5895                                 Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type));
5896                                 return null;
5897                         }
5898
5899                         bool is_struct = type.IsValueType;
5900                         eclass = ExprClass.Value;
5901
5902                         //
5903                         // SRE returns a match for .ctor () on structs (the object constructor), 
5904                         // so we have to manually ignore it.
5905                         //
5906                         if (is_struct && Arguments == null)
5907                                 return this;
5908
5909                         Expression ml;
5910                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5911                                                 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5912                                                 MemberTypes.Constructor,
5913                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5914
5915                         if (ml == null)
5916                                 return null;
5917                         
5918                         if (! (ml is MethodGroupExpr)){
5919                                 if (!is_struct){
5920                                         ml.Error_UnexpectedKind ("method group", loc);
5921                                         return null;
5922                                 }
5923                         }
5924
5925                         if (ml != null) {
5926                                 if (Arguments != null){
5927                                         foreach (Argument a in Arguments){
5928                                                 if (!a.Resolve (ec, loc))
5929                                                         return null;
5930                                         }
5931                                 }
5932
5933                                 method = Invocation.OverloadResolve (
5934                                         ec, (MethodGroupExpr) ml, Arguments, true, loc);
5935                                 
5936                         }
5937
5938                         if (method == null) {
5939                                 if (almostMatchedMembers.Count != 0) {
5940                                         MemberLookupFailed (ec, type, type, ".ctor", null, loc);
5941                                         return null;
5942                                 }
5943
5944                                 if (!is_struct || Arguments.Count > 0) {
5945                                         Error (1501, String.Format (
5946                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5947                                             TypeManager.CSharpName (type)));
5948                                         return null;
5949                                 }
5950                         }
5951
5952                         return this;
5953                 }
5954
5955                 bool DoEmitTypeParameter (EmitContext ec)
5956                 {
5957                         ILGenerator ig = ec.ig;
5958
5959                         ig.Emit (OpCodes.Ldtoken, type);
5960                         ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5961                         ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5962                         ig.Emit (OpCodes.Unbox_Any, type);
5963
5964                         return true;
5965                 }
5966
5967                 //
5968                 // This DoEmit can be invoked in two contexts:
5969                 //    * As a mechanism that will leave a value on the stack (new object)
5970                 //    * As one that wont (init struct)
5971                 //
5972                 // You can control whether a value is required on the stack by passing
5973                 // need_value_on_stack.  The code *might* leave a value on the stack
5974                 // so it must be popped manually
5975                 //
5976                 // If we are dealing with a ValueType, we have a few
5977                 // situations to deal with:
5978                 //
5979                 //    * The target is a ValueType, and we have been provided
5980                 //      the instance (this is easy, we are being assigned).
5981                 //
5982                 //    * The target of New is being passed as an argument,
5983                 //      to a boxing operation or a function that takes a
5984                 //      ValueType.
5985                 //
5986                 //      In this case, we need to create a temporary variable
5987                 //      that is the argument of New.
5988                 //
5989                 // Returns whether a value is left on the stack
5990                 //
5991                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5992                 {
5993                         bool is_value_type = TypeManager.IsValueType (type);
5994                         ILGenerator ig = ec.ig;
5995
5996                         if (is_value_type){
5997                                 IMemoryLocation ml;
5998
5999                                 // Allow DoEmit() to be called multiple times.
6000                                 // We need to create a new LocalTemporary each time since
6001                                 // you can't share LocalBuilders among ILGeneators.
6002                                 if (!value_target_set)
6003                                         value_target = new LocalTemporary (ec, type);
6004
6005                                 ml = (IMemoryLocation) value_target;
6006                                 ml.AddressOf (ec, AddressOp.Store);
6007                         }
6008
6009                         if (method != null)
6010                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
6011
6012                         if (is_value_type){
6013                                 if (method == null)
6014                                         ig.Emit (OpCodes.Initobj, type);
6015                                 else 
6016                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6017                                 if (need_value_on_stack){
6018                                         value_target.Emit (ec);
6019                                         return true;
6020                                 }
6021                                 return false;
6022                         } else {
6023                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6024                                 return true;
6025                         }
6026                 }
6027
6028                 public override void Emit (EmitContext ec)
6029                 {
6030                         if (is_type_parameter)
6031                                 DoEmitTypeParameter (ec);
6032                         else
6033                                 DoEmit (ec, true);
6034                 }
6035                 
6036                 public override void EmitStatement (EmitContext ec)
6037                 {
6038                         if (is_type_parameter)
6039                                 throw new InvalidOperationException ();
6040
6041                         if (DoEmit (ec, false))
6042                                 ec.ig.Emit (OpCodes.Pop);
6043                 }
6044
6045                 public void AddressOf (EmitContext ec, AddressOp Mode)
6046                 {
6047                         if (is_type_parameter)
6048                                 throw new InvalidOperationException ();
6049
6050                         if (!type.IsValueType){
6051                                 //
6052                                 // We throw an exception.  So far, I believe we only need to support
6053                                 // value types:
6054                                 // foreach (int j in new StructType ())
6055                                 // see bug 42390
6056                                 //
6057                                 throw new Exception ("AddressOf should not be used for classes");
6058                         }
6059
6060                         if (!value_target_set)
6061                                 value_target = new LocalTemporary (ec, type);
6062                                         
6063                         IMemoryLocation ml = (IMemoryLocation) value_target;
6064                         ml.AddressOf (ec, AddressOp.Store);
6065                         if (method != null)
6066                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
6067
6068                         if (method == null)
6069                                 ec.ig.Emit (OpCodes.Initobj, type);
6070                         else 
6071                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6072                         
6073                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6074                 }
6075         }
6076
6077         /// <summary>
6078         ///   14.5.10.2: Represents an array creation expression.
6079         /// </summary>
6080         ///
6081         /// <remarks>
6082         ///   There are two possible scenarios here: one is an array creation
6083         ///   expression that specifies the dimensions and optionally the
6084         ///   initialization data and the other which does not need dimensions
6085         ///   specified but where initialization data is mandatory.
6086         /// </remarks>
6087         public class ArrayCreation : Expression {
6088                 Expression requested_base_type;
6089                 ArrayList initializers;
6090
6091                 //
6092                 // The list of Argument types.
6093                 // This is used to construct the `newarray' or constructor signature
6094                 //
6095                 ArrayList arguments;
6096
6097                 //
6098                 // Method used to create the array object.
6099                 //
6100                 MethodBase new_method = null;
6101                 
6102                 Type array_element_type;
6103                 Type underlying_type;
6104                 bool is_one_dimensional = false;
6105                 bool is_builtin_type = false;
6106                 bool expect_initializers = false;
6107                 int num_arguments = 0;
6108                 int dimensions = 0;
6109                 string rank;
6110
6111                 ArrayList array_data;
6112
6113                 Hashtable bounds;
6114
6115                 //
6116                 // The number of array initializers that we can handle
6117                 // via the InitializeArray method - through EmitStaticInitializers
6118                 //
6119                 int num_automatic_initializers;
6120
6121                 const int max_automatic_initializers = 6;
6122                 
6123                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6124                 {
6125                         this.requested_base_type = requested_base_type;
6126                         this.initializers = initializers;
6127                         this.rank = rank;
6128                         loc = l;
6129
6130                         arguments = new ArrayList ();
6131
6132                         foreach (Expression e in exprs) {
6133                                 arguments.Add (new Argument (e, Argument.AType.Expression));
6134                                 num_arguments++;
6135                         }
6136                 }
6137
6138                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6139                 {
6140                         this.requested_base_type = requested_base_type;
6141                         this.initializers = initializers;
6142                         this.rank = rank;
6143                         loc = l;
6144
6145                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6146                         //
6147                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
6148                         //
6149                         //dimensions = tmp.Length - 1;
6150                         expect_initializers = true;
6151                 }
6152
6153                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6154                 {
6155                         StringBuilder sb = new StringBuilder (rank);
6156                         
6157                         sb.Append ("[");
6158                         for (int i = 1; i < idx_count; i++)
6159                                 sb.Append (",");
6160                         
6161                         sb.Append ("]");
6162
6163                         return new ComposedCast (base_type, sb.ToString (), loc);
6164                 }
6165
6166                 void Error_IncorrectArrayInitializer ()
6167                 {
6168                         Error (178, "Incorrectly structured array initializer");
6169                 }
6170                 
6171                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6172                 {
6173                         if (specified_dims) { 
6174                                 Argument a = (Argument) arguments [idx];
6175                                 
6176                                 if (!a.Resolve (ec, loc))
6177                                         return false;
6178                                 
6179                                 if (!(a.Expr is Constant)) {
6180                                         Error (150, "A constant value is expected");
6181                                         return false;
6182                                 }
6183                                 
6184                                 int value = (int) ((Constant) a.Expr).GetValue ();
6185                                 
6186                                 if (value != probe.Count) {
6187                                         Error_IncorrectArrayInitializer ();
6188                                         return false;
6189                                 }
6190                                 
6191                                 bounds [idx] = value;
6192                         }
6193
6194                         int child_bounds = -1;
6195                         foreach (object o in probe) {
6196                                 if (o is ArrayList) {
6197                                         int current_bounds = ((ArrayList) o).Count;
6198                                         
6199                                         if (child_bounds == -1) 
6200                                                 child_bounds = current_bounds;
6201
6202                                         else if (child_bounds != current_bounds){
6203                                                 Error_IncorrectArrayInitializer ();
6204                                                 return false;
6205                                         }
6206                                         if (specified_dims && (idx + 1 >= arguments.Count)){
6207                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6208                                                 return false;
6209                                         }
6210                                         
6211                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
6212                                         if (!ret)
6213                                                 return false;
6214                                 } else {
6215                                         if (child_bounds != -1){
6216                                                 Error_IncorrectArrayInitializer ();
6217                                                 return false;
6218                                         }
6219                                         
6220                                         Expression tmp = (Expression) o;
6221                                         tmp = tmp.Resolve (ec);
6222                                         if (tmp == null)
6223                                                 return false;
6224
6225                                         // Console.WriteLine ("I got: " + tmp);
6226                                         // Handle initialization from vars, fields etc.
6227
6228                                         Expression conv = Convert.ImplicitConversionRequired (
6229                                                 ec, tmp, underlying_type, loc);
6230                                         
6231                                         if (conv == null) 
6232                                                 return false;
6233
6234                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6235                                                 // These are subclasses of Constant that can appear as elements of an
6236                                                 // array that cannot be statically initialized (with num_automatic_initializers
6237                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6238                                                 array_data.Add (conv);
6239                                         } else if (conv is Constant) {
6240                                                 // These are the types of Constant that can appear in arrays that can be
6241                                                 // statically allocated.
6242                                                 array_data.Add (conv);
6243                                                 num_automatic_initializers++;
6244                                         } else
6245                                                 array_data.Add (conv);
6246                                 }
6247                         }
6248
6249                         return true;
6250                 }
6251                 
6252                 public void UpdateIndices (EmitContext ec)
6253                 {
6254                         int i = 0;
6255                         for (ArrayList probe = initializers; probe != null;) {
6256                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6257                                         Expression e = new IntConstant (probe.Count);
6258                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6259
6260                                         bounds [i++] =  probe.Count;
6261                                         
6262                                         probe = (ArrayList) probe [0];
6263                                         
6264                                 } else {
6265                                         Expression e = new IntConstant (probe.Count);
6266                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6267
6268                                         bounds [i++] = probe.Count;
6269                                         probe = null;
6270                                 }
6271                         }
6272
6273                 }
6274                 
6275                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6276                 {
6277                         if (initializers == null) {
6278                                 if (expect_initializers)
6279                                         return false;
6280                                 else
6281                                         return true;
6282                         }
6283                         
6284                         if (underlying_type == null)
6285                                 return false;
6286                         
6287                         //
6288                         // We use this to store all the date values in the order in which we
6289                         // will need to store them in the byte blob later
6290                         //
6291                         array_data = new ArrayList ();
6292                         bounds = new Hashtable ();
6293                         
6294                         bool ret;
6295
6296                         if (arguments != null) {
6297                                 ret = CheckIndices (ec, initializers, 0, true);
6298                                 return ret;
6299                         } else {
6300                                 arguments = new ArrayList ();
6301
6302                                 ret = CheckIndices (ec, initializers, 0, false);
6303                                 
6304                                 if (!ret)
6305                                         return false;
6306                                 
6307                                 UpdateIndices (ec);
6308                                 
6309                                 if (arguments.Count != dimensions) {
6310                                         Error_IncorrectArrayInitializer ();
6311                                         return false;
6312                                 }
6313
6314                                 return ret;
6315                         }
6316                 }
6317
6318                 //
6319                 // Converts `source' to an int, uint, long or ulong.
6320                 //
6321                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6322                 {
6323                         Expression target;
6324                         
6325                         bool old_checked = ec.CheckState;
6326                         ec.CheckState = true;
6327                         
6328                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6329                         if (target == null){
6330                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6331                                 if (target == null){
6332                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6333                                         if (target == null){
6334                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6335                                                 if (target == null)
6336                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6337                                         }
6338                                 }
6339                         } 
6340                         ec.CheckState = old_checked;
6341
6342                         //
6343                         // Only positive constants are allowed at compile time
6344                         //
6345                         if (target is Constant){
6346                                 if (target is IntConstant){
6347                                         if (((IntConstant) target).Value < 0){
6348                                                 Expression.Error_NegativeArrayIndex (loc);
6349                                                 return null;
6350                                         }
6351                                 }
6352
6353                                 if (target is LongConstant){
6354                                         if (((LongConstant) target).Value < 0){
6355                                                 Expression.Error_NegativeArrayIndex (loc);
6356                                                 return null;
6357                                         }
6358                                 }
6359                                 
6360                         }
6361
6362                         return target;
6363                 }
6364
6365                 //
6366                 // Creates the type of the array
6367                 //
6368                 bool LookupType (EmitContext ec)
6369                 {
6370                         StringBuilder array_qualifier = new StringBuilder (rank);
6371
6372                         //
6373                         // `In the first form allocates an array instace of the type that results
6374                         // from deleting each of the individual expression from the expression list'
6375                         //
6376                         if (num_arguments > 0) {
6377                                 array_qualifier.Append ("[");
6378                                 for (int i = num_arguments-1; i > 0; i--)
6379                                         array_qualifier.Append (",");
6380                                 array_qualifier.Append ("]");                           
6381                         }
6382
6383                         //
6384                         // Lookup the type
6385                         //
6386                         TypeExpr array_type_expr;
6387                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6388                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec);
6389                         if (array_type_expr == null)
6390                                 return false;
6391
6392                         type = array_type_expr.Type;
6393
6394                         if (!type.IsArray) {
6395                                 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6396                                 return false;
6397                         }
6398                         underlying_type = TypeManager.GetElementType (type);
6399                         dimensions = type.GetArrayRank ();
6400
6401                         return true;
6402                 }
6403                 
6404                 public override Expression DoResolve (EmitContext ec)
6405                 {
6406                         int arg_count;
6407
6408                         if (!LookupType (ec))
6409                                 return null;
6410                         
6411                         //
6412                         // First step is to validate the initializers and fill
6413                         // in any missing bits
6414                         //
6415                         if (!ValidateInitializers (ec, type))
6416                                 return null;
6417
6418                         if (arguments == null)
6419                                 arg_count = 0;
6420                         else {
6421                                 arg_count = arguments.Count;
6422                                 foreach (Argument a in arguments){
6423                                         if (!a.Resolve (ec, loc))
6424                                                 return null;
6425
6426                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6427                                         if (real_arg == null)
6428                                                 return null;
6429
6430                                         a.Expr = real_arg;
6431                                 }
6432                         }
6433                         
6434                         array_element_type = TypeManager.GetElementType (type);
6435
6436                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6437                                 Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6438                                 return null;
6439                         }
6440
6441                         if (arg_count == 1) {
6442                                 is_one_dimensional = true;
6443                                 eclass = ExprClass.Value;
6444                                 return this;
6445                         }
6446
6447                         is_builtin_type = TypeManager.IsBuiltinType (type);
6448
6449                         if (is_builtin_type) {
6450                                 Expression ml;
6451                                 
6452                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6453                                                    AllBindingFlags, loc);
6454                                 
6455                                 if (!(ml is MethodGroupExpr)) {
6456                                         ml.Error_UnexpectedKind ("method group", loc);
6457                                         return null;
6458                                 }
6459                                 
6460                                 if (ml == null) {
6461                                         Error (-6, "New invocation: Can not find a constructor for " +
6462                                                       "this argument list");
6463                                         return null;
6464                                 }
6465                                 
6466                                 new_method = Invocation.OverloadResolve (
6467                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6468
6469                                 if (new_method == null) {
6470                                         Error (-6, "New invocation: Can not find a constructor for " +
6471                                                       "this argument list");
6472                                         return null;
6473                                 }
6474                                 
6475                                 eclass = ExprClass.Value;
6476                                 return this;
6477                         } else {
6478                                 ModuleBuilder mb = CodeGen.Module.Builder;
6479                                 ArrayList args = new ArrayList ();
6480                                 
6481                                 if (arguments != null) {
6482                                         for (int i = 0; i < arg_count; i++)
6483                                                 args.Add (TypeManager.int32_type);
6484                                 }
6485                                 
6486                                 Type [] arg_types = null;
6487
6488                                 if (args.Count > 0)
6489                                         arg_types = new Type [args.Count];
6490                                 
6491                                 args.CopyTo (arg_types, 0);
6492                                 
6493                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6494                                                             arg_types);
6495
6496                                 if (new_method == null) {
6497                                         Error (-6, "New invocation: Can not find a constructor for " +
6498                                                       "this argument list");
6499                                         return null;
6500                                 }
6501                                 
6502                                 eclass = ExprClass.Value;
6503                                 return this;
6504                         }
6505                 }
6506
6507                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6508                 {
6509                         int factor;
6510                         byte [] data;
6511                         byte [] element;
6512                         int count = array_data.Count;
6513
6514                         if (underlying_type.IsEnum)
6515                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6516                         
6517                         factor = GetTypeSize (underlying_type);
6518                         if (factor == 0)
6519                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6520
6521                         data = new byte [(count * factor + 4) & ~3];
6522                         int idx = 0;
6523                         
6524                         for (int i = 0; i < count; ++i) {
6525                                 object v = array_data [i];
6526
6527                                 if (v is EnumConstant)
6528                                         v = ((EnumConstant) v).Child;
6529                                 
6530                                 if (v is Constant && !(v is StringConstant))
6531                                         v = ((Constant) v).GetValue ();
6532                                 else {
6533                                         idx += factor;
6534                                         continue;
6535                                 }
6536                                 
6537                                 if (underlying_type == TypeManager.int64_type){
6538                                         if (!(v is Expression)){
6539                                                 long val = (long) v;
6540                                                 
6541                                                 for (int j = 0; j < factor; ++j) {
6542                                                         data [idx + j] = (byte) (val & 0xFF);
6543                                                         val = (val >> 8);
6544                                                 }
6545                                         }
6546                                 } else if (underlying_type == TypeManager.uint64_type){
6547                                         if (!(v is Expression)){
6548                                                 ulong val = (ulong) v;
6549
6550                                                 for (int j = 0; j < factor; ++j) {
6551                                                         data [idx + j] = (byte) (val & 0xFF);
6552                                                         val = (val >> 8);
6553                                                 }
6554                                         }
6555                                 } else if (underlying_type == TypeManager.float_type) {
6556                                         if (!(v is Expression)){
6557                                                 element = BitConverter.GetBytes ((float) v);
6558                                                         
6559                                                 for (int j = 0; j < factor; ++j)
6560                                                         data [idx + j] = element [j];
6561                                         }
6562                                 } else if (underlying_type == TypeManager.double_type) {
6563                                         if (!(v is Expression)){
6564                                                 element = BitConverter.GetBytes ((double) v);
6565
6566                                                 for (int j = 0; j < factor; ++j)
6567                                                         data [idx + j] = element [j];
6568                                         }
6569                                 } else if (underlying_type == TypeManager.char_type){
6570                                         if (!(v is Expression)){
6571                                                 int val = (int) ((char) v);
6572                                                 
6573                                                 data [idx] = (byte) (val & 0xff);
6574                                                 data [idx+1] = (byte) (val >> 8);
6575                                         }
6576                                 } else if (underlying_type == TypeManager.short_type){
6577                                         if (!(v is Expression)){
6578                                                 int val = (int) ((short) v);
6579                                         
6580                                                 data [idx] = (byte) (val & 0xff);
6581                                                 data [idx+1] = (byte) (val >> 8);
6582                                         }
6583                                 } else if (underlying_type == TypeManager.ushort_type){
6584                                         if (!(v is Expression)){
6585                                                 int val = (int) ((ushort) v);
6586                                         
6587                                                 data [idx] = (byte) (val & 0xff);
6588                                                 data [idx+1] = (byte) (val >> 8);
6589                                         }
6590                                 } else if (underlying_type == TypeManager.int32_type) {
6591                                         if (!(v is Expression)){
6592                                                 int val = (int) v;
6593                                         
6594                                                 data [idx]   = (byte) (val & 0xff);
6595                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6596                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6597                                                 data [idx+3] = (byte) (val >> 24);
6598                                         }
6599                                 } else if (underlying_type == TypeManager.uint32_type) {
6600                                         if (!(v is Expression)){
6601                                                 uint val = (uint) v;
6602                                         
6603                                                 data [idx]   = (byte) (val & 0xff);
6604                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6605                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6606                                                 data [idx+3] = (byte) (val >> 24);
6607                                         }
6608                                 } else if (underlying_type == TypeManager.sbyte_type) {
6609                                         if (!(v is Expression)){
6610                                                 sbyte val = (sbyte) v;
6611                                                 data [idx] = (byte) val;
6612                                         }
6613                                 } else if (underlying_type == TypeManager.byte_type) {
6614                                         if (!(v is Expression)){
6615                                                 byte val = (byte) v;
6616                                                 data [idx] = (byte) val;
6617                                         }
6618                                 } else if (underlying_type == TypeManager.bool_type) {
6619                                         if (!(v is Expression)){
6620                                                 bool val = (bool) v;
6621                                                 data [idx] = (byte) (val ? 1 : 0);
6622                                         }
6623                                 } else if (underlying_type == TypeManager.decimal_type){
6624                                         if (!(v is Expression)){
6625                                                 int [] bits = Decimal.GetBits ((decimal) v);
6626                                                 int p = idx;
6627
6628                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6629                                                 int [] nbits = new int [4];
6630                                                 nbits [0] = bits [3];
6631                                                 nbits [1] = bits [2];
6632                                                 nbits [2] = bits [0];
6633                                                 nbits [3] = bits [1];
6634                                                 
6635                                                 for (int j = 0; j < 4; j++){
6636                                                         data [p++] = (byte) (nbits [j] & 0xff);
6637                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6638                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6639                                                         data [p++] = (byte) (nbits [j] >> 24);
6640                                                 }
6641                                         }
6642                                 } else
6643                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6644
6645                                 idx += factor;
6646                         }
6647
6648                         return data;
6649                 }
6650
6651                 //
6652                 // Emits the initializers for the array
6653                 //
6654                 void EmitStaticInitializers (EmitContext ec)
6655                 {
6656                         //
6657                         // First, the static data
6658                         //
6659                         FieldBuilder fb;
6660                         ILGenerator ig = ec.ig;
6661                         
6662                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6663
6664                         fb = RootContext.MakeStaticData (data);
6665
6666                         ig.Emit (OpCodes.Dup);
6667                         ig.Emit (OpCodes.Ldtoken, fb);
6668                         ig.Emit (OpCodes.Call,
6669                                  TypeManager.void_initializearray_array_fieldhandle);
6670                 }
6671
6672                 //
6673                 // Emits pieces of the array that can not be computed at compile
6674                 // time (variables and string locations).
6675                 //
6676                 // This always expect the top value on the stack to be the array
6677                 //
6678                 void EmitDynamicInitializers (EmitContext ec)
6679                 {
6680                         ILGenerator ig = ec.ig;
6681                         int dims = bounds.Count;
6682                         int [] current_pos = new int [dims];
6683                         int top = array_data.Count;
6684
6685                         MethodInfo set = null;
6686
6687                         if (dims != 1){
6688                                 Type [] args;
6689                                 ModuleBuilder mb = null;
6690                                 mb = CodeGen.Module.Builder;
6691                                 args = new Type [dims + 1];
6692
6693                                 int j;
6694                                 for (j = 0; j < dims; j++)
6695                                         args [j] = TypeManager.int32_type;
6696
6697                                 args [j] = array_element_type;
6698                                 
6699                                 set = mb.GetArrayMethod (
6700                                         type, "Set",
6701                                         CallingConventions.HasThis | CallingConventions.Standard,
6702                                         TypeManager.void_type, args);
6703                         }
6704                         
6705                         for (int i = 0; i < top; i++){
6706
6707                                 Expression e = null;
6708
6709                                 if (array_data [i] is Expression)
6710                                         e = (Expression) array_data [i];
6711
6712                                 if (e != null) {
6713                                         //
6714                                         // Basically we do this for string literals and
6715                                         // other non-literal expressions
6716                                         //
6717                                         if (e is EnumConstant){
6718                                                 e = ((EnumConstant) e).Child;
6719                                         }
6720                                         
6721                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6722                                             num_automatic_initializers <= max_automatic_initializers) {
6723                                                 Type etype = e.Type;
6724                                                 
6725                                                 ig.Emit (OpCodes.Dup);
6726
6727                                                 for (int idx = 0; idx < dims; idx++) 
6728                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6729
6730                                                 //
6731                                                 // If we are dealing with a struct, get the
6732                                                 // address of it, so we can store it.
6733                                                 //
6734                                                 if ((dims == 1) && etype.IsValueType &&
6735                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6736                                                      etype == TypeManager.decimal_type)) {
6737                                                         if (e is New){
6738                                                                 New n = (New) e;
6739
6740                                                                 //
6741                                                                 // Let new know that we are providing
6742                                                                 // the address where to store the results
6743                                                                 //
6744                                                                 n.DisableTemporaryValueType ();
6745                                                         }
6746
6747                                                         ig.Emit (OpCodes.Ldelema, etype);
6748                                                 }
6749
6750                                                 e.Emit (ec);
6751
6752                                                 if (dims == 1) {
6753                                                         bool is_stobj, has_type_arg;
6754                                                         OpCode op = ArrayAccess.GetStoreOpcode (
6755                                                                 etype, out is_stobj,
6756                                                                 out has_type_arg);
6757                                                         if (is_stobj)
6758                                                                 ig.Emit (OpCodes.Stobj, etype);
6759                                                         else if (has_type_arg)
6760                                                                 ig.Emit (op, etype);
6761                                                         else
6762                                                                 ig.Emit (op);
6763                                                 } else 
6764                                                         ig.Emit (OpCodes.Call, set);
6765                                         }
6766                                 }
6767                                 
6768                                 //
6769                                 // Advance counter
6770                                 //
6771                                 for (int j = dims - 1; j >= 0; j--){
6772                                         current_pos [j]++;
6773                                         if (current_pos [j] < (int) bounds [j])
6774                                                 break;
6775                                         current_pos [j] = 0;
6776                                 }
6777                         }
6778                 }
6779
6780                 void EmitArrayArguments (EmitContext ec)
6781                 {
6782                         ILGenerator ig = ec.ig;
6783                         
6784                         foreach (Argument a in arguments) {
6785                                 Type atype = a.Type;
6786                                 a.Emit (ec);
6787
6788                                 if (atype == TypeManager.uint64_type)
6789                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6790                                 else if (atype == TypeManager.int64_type)
6791                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6792                         }
6793                 }
6794                 
6795                 public override void Emit (EmitContext ec)
6796                 {
6797                         ILGenerator ig = ec.ig;
6798                         
6799                         EmitArrayArguments (ec);
6800                         if (is_one_dimensional)
6801                                 ig.Emit (OpCodes.Newarr, array_element_type);
6802                         else {
6803                                 if (is_builtin_type) 
6804                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6805                                 else 
6806                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6807                         }
6808                         
6809                         if (initializers != null){
6810                                 //
6811                                 // FIXME: Set this variable correctly.
6812                                 // 
6813                                 bool dynamic_initializers = true;
6814
6815                                 // This will never be true for array types that cannot be statically
6816                                 // initialized. num_automatic_initializers will always be zero.  See
6817                                 // CheckIndices.
6818                                         if (num_automatic_initializers > max_automatic_initializers)
6819                                                 EmitStaticInitializers (ec);
6820                                 
6821                                 if (dynamic_initializers)
6822                                         EmitDynamicInitializers (ec);
6823                         }
6824                 }
6825                 
6826                 public object EncodeAsAttribute ()
6827                 {
6828                         if (!is_one_dimensional){
6829                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6830                                 return null;
6831                         }
6832
6833                         if (array_data == null){
6834                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6835                                 return null;
6836                         }
6837                         
6838                         object [] ret = new object [array_data.Count];
6839                         int i = 0;
6840                         foreach (Expression e in array_data){
6841                                 object v;
6842                                 
6843                                 if (e is NullLiteral)
6844                                         v = null;
6845                                 else {
6846                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6847                                                 return null;
6848                                 }
6849                                 ret [i++] = v;
6850                         }
6851                         return ret;
6852                 }
6853         }
6854         
6855         /// <summary>
6856         ///   Represents the `this' construct
6857         /// </summary>
6858         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6859
6860                 Block block;
6861                 VariableInfo variable_info;
6862                 
6863                 public This (Block block, Location loc)
6864                 {
6865                         this.loc = loc;
6866                         this.block = block;
6867                 }
6868
6869                 public This (Location loc)
6870                 {
6871                         this.loc = loc;
6872                 }
6873
6874                 public VariableInfo VariableInfo {
6875                         get { return variable_info; }
6876                 }
6877
6878                 public bool VerifyFixed (bool is_expression)
6879                 {
6880                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6881                                 return false;
6882                         else
6883                                 return variable_info.LocalInfo.IsFixed;
6884                 }
6885
6886                 public bool ResolveBase (EmitContext ec)
6887                 {
6888                         eclass = ExprClass.Variable;
6889
6890                         if (ec.TypeContainer.CurrentType != null)
6891                                 type = ec.TypeContainer.CurrentType;
6892                         else
6893                                 type = ec.ContainerType;
6894
6895                         if (ec.IsStatic) {
6896                                 Error (26, "Keyword this not valid in static code");
6897                                 return false;
6898                         }
6899
6900                         if ((block != null) && (block.ThisVariable != null))
6901                                 variable_info = block.ThisVariable.VariableInfo;
6902
6903                         if (ec.CurrentAnonymousMethod != null)
6904                                 ec.CaptureThis ();
6905                         
6906                         return true;
6907                 }
6908
6909                 public override Expression DoResolve (EmitContext ec)
6910                 {
6911                         if (!ResolveBase (ec))
6912                                 return null;
6913
6914                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6915                                 Error (188, "The this object cannot be used before all " +
6916                                        "of its fields are assigned to");
6917                                 variable_info.SetAssigned (ec);
6918                                 return this;
6919                         }
6920
6921                         if (ec.IsFieldInitializer) {
6922                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6923                                        "a method or a property.");
6924                                 return null;
6925                         }
6926
6927                         return this;
6928                 }
6929
6930                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6931                 {
6932                         if (!ResolveBase (ec))
6933                                 return null;
6934
6935                         if (variable_info != null)
6936                                 variable_info.SetAssigned (ec);
6937                         
6938                         if (ec.TypeContainer is Class){
6939                                 Error (1604, "Cannot assign to `this'");
6940                                 return null;
6941                         }
6942
6943                         return this;
6944                 }
6945
6946                 public void Emit (EmitContext ec, bool leave_copy)
6947                 {
6948                         Emit (ec);
6949                         if (leave_copy)
6950                                 ec.ig.Emit (OpCodes.Dup);
6951                 }
6952                 
6953                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6954                 {
6955                         ILGenerator ig = ec.ig;
6956                         
6957                         if (ec.TypeContainer is Struct){
6958                                 ec.EmitThis ();
6959                                 source.Emit (ec);
6960                                 if (leave_copy)
6961                                         ec.ig.Emit (OpCodes.Dup);
6962                                 ig.Emit (OpCodes.Stobj, type);
6963                         } else {
6964                                 throw new Exception ("how did you get here");
6965                         }
6966                 }
6967                 
6968                 public override void Emit (EmitContext ec)
6969                 {
6970                         ILGenerator ig = ec.ig;
6971
6972                         ec.EmitThis ();
6973                         if (ec.TypeContainer is Struct)
6974                                 ig.Emit (OpCodes.Ldobj, type);
6975                 }
6976
6977                 public void AddressOf (EmitContext ec, AddressOp mode)
6978                 {
6979                         ec.EmitThis ();
6980
6981                         // FIMXE
6982                         // FIGURE OUT WHY LDARG_S does not work
6983                         //
6984                         // consider: struct X { int val; int P { set { val = value; }}}
6985                         //
6986                         // Yes, this looks very bad. Look at `NOTAS' for
6987                         // an explanation.
6988                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6989                 }
6990         }
6991
6992         /// <summary>
6993         ///   Represents the `__arglist' construct
6994         /// </summary>
6995         public class ArglistAccess : Expression
6996         {
6997                 public ArglistAccess (Location loc)
6998                 {
6999                         this.loc = loc;
7000                 }
7001
7002                 public bool ResolveBase (EmitContext ec)
7003                 {
7004                         eclass = ExprClass.Variable;
7005                         type = TypeManager.runtime_argument_handle_type;
7006                         return true;
7007                 }
7008
7009                 public override Expression DoResolve (EmitContext ec)
7010                 {
7011                         if (!ResolveBase (ec))
7012                                 return null;
7013
7014                         if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
7015                                 Error (190, "The __arglist construct is valid only within " +
7016                                        "a variable argument method.");
7017                                 return null;
7018                         }
7019
7020                         return this;
7021                 }
7022
7023                 public override void Emit (EmitContext ec)
7024                 {
7025                         ec.ig.Emit (OpCodes.Arglist);
7026                 }
7027         }
7028
7029         /// <summary>
7030         ///   Represents the `__arglist (....)' construct
7031         /// </summary>
7032         public class Arglist : Expression
7033         {
7034                 public readonly Argument[] Arguments;
7035
7036                 public Arglist (Argument[] args, Location l)
7037                 {
7038                         Arguments = args;
7039                         loc = l;
7040                 }
7041
7042                 public Type[] ArgumentTypes {
7043                         get {
7044                                 Type[] retval = new Type [Arguments.Length];
7045                                 for (int i = 0; i < Arguments.Length; i++)
7046                                         retval [i] = Arguments [i].Type;
7047                                 return retval;
7048                         }
7049                 }
7050
7051                 public override Expression DoResolve (EmitContext ec)
7052                 {
7053                         eclass = ExprClass.Variable;
7054                         type = TypeManager.runtime_argument_handle_type;
7055
7056                         foreach (Argument arg in Arguments) {
7057                                 if (!arg.Resolve (ec, loc))
7058                                         return null;
7059                         }
7060
7061                         return this;
7062                 }
7063
7064                 public override void Emit (EmitContext ec)
7065                 {
7066                         foreach (Argument arg in Arguments)
7067                                 arg.Emit (ec);
7068                 }
7069         }
7070
7071         //
7072         // This produces the value that renders an instance, used by the iterators code
7073         //
7074         public class ProxyInstance : Expression, IMemoryLocation  {
7075                 public override Expression DoResolve (EmitContext ec)
7076                 {
7077                         eclass = ExprClass.Variable;
7078                         type = ec.ContainerType;
7079                         return this;
7080                 }
7081                 
7082                 public override void Emit (EmitContext ec)
7083                 {
7084                         ec.ig.Emit (OpCodes.Ldarg_0);
7085
7086                 }
7087                 
7088                 public void AddressOf (EmitContext ec, AddressOp mode)
7089                 {
7090                         ec.ig.Emit (OpCodes.Ldarg_0);
7091                 }
7092         }
7093
7094         /// <summary>
7095         ///   Implements the typeof operator
7096         /// </summary>
7097         public class TypeOf : Expression {
7098                 public Expression QueriedType;
7099                 protected Type typearg;
7100                 
7101                 public TypeOf (Expression queried_type, Location l)
7102                 {
7103                         QueriedType = queried_type;
7104                         loc = l;
7105                 }
7106
7107                 public override Expression DoResolve (EmitContext ec)
7108                 {
7109                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec);
7110                         if (texpr == null)
7111                                 return null;
7112
7113                         typearg = texpr.Type;
7114
7115                         if (typearg == TypeManager.void_type) {
7116                                 Error (673, "System.Void cannot be used from C# - " +
7117                                        "use typeof (void) to get the void type object");
7118                                 return null;
7119                         }
7120
7121                         if (typearg.IsPointer && !ec.InUnsafe){
7122                                 UnsafeError (loc);
7123                                 return null;
7124                         }
7125                         CheckObsoleteAttribute (typearg);
7126
7127                         type = TypeManager.type_type;
7128                         eclass = ExprClass.Type;
7129                         return this;
7130                 }
7131
7132                 public override void Emit (EmitContext ec)
7133                 {
7134                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
7135                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7136                 }
7137
7138                 public Type TypeArg { 
7139                         get { return typearg; }
7140                 }
7141         }
7142
7143         /// <summary>
7144         ///   Implements the `typeof (void)' operator
7145         /// </summary>
7146         public class TypeOfVoid : TypeOf {
7147                 public TypeOfVoid (Location l) : base (null, l)
7148                 {
7149                         loc = l;
7150                 }
7151
7152                 public override Expression DoResolve (EmitContext ec)
7153                 {
7154                         type = TypeManager.type_type;
7155                         typearg = TypeManager.void_type;
7156                         eclass = ExprClass.Type;
7157                         return this;
7158                 }
7159         }
7160
7161         /// <summary>
7162         ///   Implements the sizeof expression
7163         /// </summary>
7164         public class SizeOf : Expression {
7165                 public Expression QueriedType;
7166                 Type type_queried;
7167                 
7168                 public SizeOf (Expression queried_type, Location l)
7169                 {
7170                         this.QueriedType = queried_type;
7171                         loc = l;
7172                 }
7173
7174                 public override Expression DoResolve (EmitContext ec)
7175                 {
7176                         if (!ec.InUnsafe) {
7177                                 Report.Error (
7178                                         233, loc, "Sizeof may only be used in an unsafe context " +
7179                                         "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
7180                                 return null;
7181                         }
7182                                 
7183                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec);
7184                         if (texpr == null)
7185                                 return null;
7186
7187                         if (texpr is TypeParameterExpr){
7188                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
7189                                 return null;
7190                         }
7191
7192                         type_queried = texpr.Type;
7193
7194                         CheckObsoleteAttribute (type_queried);
7195
7196                         if (!TypeManager.IsUnmanagedType (type_queried)){
7197                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
7198                                 return null;
7199                         }
7200                         
7201                         type = TypeManager.int32_type;
7202                         eclass = ExprClass.Value;
7203                         return this;
7204                 }
7205
7206                 public override void Emit (EmitContext ec)
7207                 {
7208                         int size = GetTypeSize (type_queried);
7209
7210                         if (size == 0)
7211                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7212                         else
7213                                 IntConstant.EmitInt (ec.ig, size);
7214                 }
7215         }
7216
7217         /// <summary>
7218         ///   Implements the member access expression
7219         /// </summary>
7220         public class MemberAccess : Expression {
7221                 public string Identifier;
7222                 protected Expression expr;
7223                 protected TypeArguments args;
7224                 
7225                 public MemberAccess (Expression expr, string id, Location l)
7226                 {
7227                         this.expr = expr;
7228                         Identifier = id;
7229                         loc = l;
7230                 }
7231
7232                 public MemberAccess (Expression expr, string id, TypeArguments args,
7233                                      Location l)
7234                         : this (expr, id, l)
7235                 {
7236                         this.args = args;
7237                 }
7238
7239                 public Expression Expr {
7240                         get {
7241                                 return expr;
7242                         }
7243                 }
7244
7245                 public static void error176 (Location loc, string name)
7246                 {
7247                         Report.Error (176, loc, "Static member `" +
7248                                       name + "' cannot be accessed " +
7249                                       "with an instance reference, qualify with a " +
7250                                       "type name instead");
7251                 }
7252
7253                 public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
7254                 {
7255                         SimpleName sn = left_original as SimpleName;
7256                         if (sn == null || left == null || left.Type.Name != sn.Name)
7257                                 return false;
7258
7259                         return ec.DeclSpace.LookupType (sn.Name, true, loc) != null;
7260                 }
7261                 
7262                 // TODO: possible optimalization
7263                 // Cache resolved constant result in FieldBuilder <-> expresion map
7264                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7265                                                               Expression left, Location loc,
7266                                                               Expression left_original)
7267                 {
7268                         bool left_is_type, left_is_explicit;
7269
7270                         // If `left' is null, then we're called from SimpleNameResolve and this is
7271                         // a member in the currently defining class.
7272                         if (left == null) {
7273                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7274                                 left_is_explicit = false;
7275
7276                                 // Implicitly default to `this' unless we're static.
7277                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7278                                         left = ec.GetThis (loc);
7279                         } else {
7280                                 left_is_type = left is TypeExpr;
7281                                 left_is_explicit = true;
7282                         }
7283
7284                         if (member_lookup is FieldExpr){
7285                                 FieldExpr fe = (FieldExpr) member_lookup;
7286                                 FieldInfo fi = fe.FieldInfo.Mono_GetGenericFieldDefinition ();
7287                                 Type decl_type = fi.DeclaringType;
7288
7289                                 bool is_emitted = fi is FieldBuilder;
7290                                 Type t = fi.FieldType;
7291
7292                                 if (is_emitted) {
7293                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7294                                         
7295                                         if (c != null) {
7296                                                 object o;
7297                                                 if (!c.LookupConstantValue (out o))
7298                                                         return null;
7299
7300                                                 object real_value = ((Constant) c.Expr).GetValue ();
7301
7302                                                 Expression exp = Constantify (real_value, t);
7303
7304                                                 if (left_is_explicit && !left_is_type && !IdenticalNameAndTypeName (ec, left_original, left, loc)) {
7305                                                         Report.SymbolRelatedToPreviousError (c);
7306                                                         error176 (loc, c.GetSignatureForError ());
7307                                                         return null;
7308                                                 }
7309                                         
7310                                                 return exp;
7311                                         }
7312                                 }
7313
7314                                 // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
7315                                 if (fi.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
7316                                         object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
7317                                         if (attrs.Length == 1)
7318                                                 return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
7319                                 }
7320
7321                                 if (fi.IsLiteral) {
7322                                         object o;
7323
7324                                         if (is_emitted)
7325                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
7326                                         else
7327                                                 o = fi.GetValue (fi);
7328                                         
7329                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7330                                                 if (left_is_explicit && !left_is_type &&
7331                                                     !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) {
7332                                                         error176 (loc, fe.FieldInfo.Name);
7333                                                         return null;
7334                                                 }                                       
7335                                                 
7336                                                 Expression enum_member = MemberLookup (
7337                                                         ec, decl_type, "value__", MemberTypes.Field,
7338                                                         AllBindingFlags, loc); 
7339
7340                                                 Enum en = TypeManager.LookupEnum (decl_type);
7341
7342                                                 Constant c;
7343                                                 if (en != null)
7344                                                         c = Constantify (o, en.UnderlyingType);
7345                                                 else 
7346                                                         c = Constantify (o, enum_member.Type);
7347                                                 
7348                                                 return new EnumConstant (c, decl_type);
7349                                         }
7350                                         
7351                                         Expression exp = Constantify (o, t);
7352
7353                                         if (left_is_explicit && !left_is_type) {
7354                                                 error176 (loc, fe.FieldInfo.Name);
7355                                                 return null;
7356                                         }
7357                                         
7358                                         return exp;
7359                                 }
7360
7361                                 if (t.IsPointer && !ec.InUnsafe){
7362                                         UnsafeError (loc);
7363                                         return null;
7364                                 }
7365                         }
7366
7367                         if (member_lookup is EventExpr) {
7368                                 EventExpr ee = (EventExpr) member_lookup;
7369                                 
7370                                 //
7371                                 // If the event is local to this class, we transform ourselves into
7372                                 // a FieldExpr
7373                                 //
7374
7375                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7376                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7377                                         MemberInfo mi = GetFieldFromEvent (ee);
7378
7379                                         if (mi == null) {
7380                                                 //
7381                                                 // If this happens, then we have an event with its own
7382                                                 // accessors and private field etc so there's no need
7383                                                 // to transform ourselves.
7384                                                 //
7385                                                 ee.InstanceExpression = left;
7386                                                 return ee;
7387                                         }
7388
7389                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7390                                         
7391                                         if (ml == null) {
7392                                                 Report.Error (-200, loc, "Internal error!!");
7393                                                 return null;
7394                                         }
7395
7396                                         if (!left_is_explicit)
7397                                                 left = null;
7398                                         
7399                                         ee.InstanceExpression = left;
7400
7401                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7402                                 }
7403                         }
7404
7405                         if (member_lookup is IMemberExpr) {
7406                                 IMemberExpr me = (IMemberExpr) member_lookup;
7407                                 MethodGroupExpr mg = me as MethodGroupExpr;
7408
7409                                 if (left_is_type){
7410                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7411                                                 mg.IsExplicitImpl = left_is_explicit;
7412
7413                                         if (!me.IsStatic){
7414                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7415                                                     IdenticalNameAndTypeName (ec, left_original, member_lookup, loc))
7416                                                         return member_lookup;
7417
7418                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7419                                                 return null;
7420                                         }
7421
7422                                 } else {
7423                                         if (!me.IsInstance){
7424                                                 if (IdenticalNameAndTypeName (ec, left_original, left, loc))
7425                                                         return member_lookup;
7426
7427                                                 if (left_is_explicit) {
7428                                                         error176 (loc, me.Name);
7429                                                         return null;
7430                                                 }
7431                                         }
7432
7433                                         //
7434                                         // Since we can not check for instance objects in SimpleName,
7435                                         // becaue of the rule that allows types and variables to share
7436                                         // the name (as long as they can be de-ambiguated later, see 
7437                                         // IdenticalNameAndTypeName), we have to check whether left 
7438                                         // is an instance variable in a static context
7439                                         //
7440                                         // However, if the left-hand value is explicitly given, then
7441                                         // it is already our instance expression, so we aren't in
7442                                         // static context.
7443                                         //
7444
7445                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7446                                                 IMemberExpr mexp = (IMemberExpr) left;
7447
7448                                                 if (!mexp.IsStatic){
7449                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7450                                                         return null;
7451                                                 }
7452                                         }
7453
7454                                         if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc))
7455                                                 mg.IdenticalTypeName = true;
7456
7457                                         me.InstanceExpression = left;
7458                                 }
7459
7460                                 return member_lookup;
7461                         }
7462
7463                         Console.WriteLine ("Left is: " + left);
7464                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7465                         Environment.Exit (1);
7466                         return null;
7467                 }
7468                 
7469                 public virtual Expression DoResolve (EmitContext ec, Expression right_side,
7470                                                      ResolveFlags flags)
7471                 {
7472                         if (type != null)
7473                                 throw new Exception ();
7474
7475                         //
7476                         // Resolve the expression with flow analysis turned off, we'll do the definite
7477                         // assignment checks later.  This is because we don't know yet what the expression
7478                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7479                         // definite assignment check on the actual field and not on the whole struct.
7480                         //
7481
7482                         Expression original = expr;
7483                         expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7484                         if (expr == null)
7485                                 return null;
7486
7487                         if (expr is Namespace) {
7488                                 Namespace ns = (Namespace) expr;
7489                                 string lookup_id = MemberName.MakeName (Identifier, args);
7490                                 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc);
7491                                 if ((retval != null) && (args != null))
7492                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec);
7493                                 if (retval == null)
7494                                         Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName);
7495                                 return retval;
7496                         }
7497                                         
7498                         //
7499                         // TODO: I mailed Ravi about this, and apparently we can get rid
7500                         // of this and put it in the right place.
7501                         // 
7502                         // Handle enums here when they are in transit.
7503                         // Note that we cannot afford to hit MemberLookup in this case because
7504                         // it will fail to find any members at all
7505                         //
7506
7507                         Type expr_type;
7508                         if (expr is TypeExpr){
7509                                 expr_type = expr.Type;
7510
7511                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7512                                         Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type);
7513                                         return null;
7514                                 }
7515
7516                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7517                                         Enum en = TypeManager.LookupEnum (expr_type);
7518
7519                                         if (en != null) {
7520                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7521                                                 
7522                                                 if (value != null){
7523                                                         MemberCore mc = en.GetDefinition (Identifier);
7524                                                         ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7525                                                         if (oa != null) {
7526                                                                 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7527                                                         }
7528                                                         oa = en.GetObsoleteAttribute (en);
7529                                                         if (oa != null) {
7530                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7531                                                         }
7532
7533                                                         Constant c = Constantify (value, en.UnderlyingType);
7534                                                         return new EnumConstant (c, expr_type);
7535                                                 }
7536                                         } else {
7537                                                 CheckObsoleteAttribute (expr_type);
7538
7539                                                 FieldInfo fi = expr_type.GetField (Identifier);
7540                                                 if (fi != null) {
7541                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7542                                                         if (oa != null)
7543                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7544                                                 }
7545                                         }
7546                                 }
7547                         } else
7548                                 expr_type = expr.Type;
7549                         
7550                         if (expr_type.IsPointer){
7551                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7552                                        TypeManager.CSharpName (expr_type) + ")");
7553                                 return null;
7554                         }
7555
7556                         Expression member_lookup;
7557                         member_lookup = MemberLookup (
7558                                 ec, expr_type, expr_type, Identifier, loc);
7559                         if ((member_lookup == null) && (args != null)) {
7560                                 string lookup_id = MemberName.MakeName (Identifier, args);
7561                                 member_lookup = MemberLookup (
7562                                         ec, expr_type, expr_type, lookup_id, loc);
7563                         }
7564                         if (member_lookup == null) {
7565                                 MemberLookupFailed (
7566                                         ec, expr_type, expr_type, Identifier, null, loc);
7567                                 return null;
7568                         }
7569
7570                         if (member_lookup is TypeExpr) {
7571                                 if (!(expr is TypeExpr) && 
7572                                     !IdenticalNameAndTypeName (ec, original, expr, loc)) {
7573                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7574                                                member_lookup.Type + "' instead");
7575                                         return null;
7576                                 }
7577
7578                                 return member_lookup;
7579                         }
7580
7581                         if (args != null) {
7582                                 string full_name = expr_type + "." + Identifier;
7583
7584                                 if (member_lookup is FieldExpr) {
7585                                         Report.Error (307, loc, "The field `{0}' cannot " +
7586                                                       "be used with type arguments", full_name);
7587                                         return null;
7588                                 } else if (member_lookup is EventExpr) {
7589                                         Report.Error (307, loc, "The event `{0}' cannot " +
7590                                                       "be used with type arguments", full_name);
7591                                         return null;
7592                                 } else if (member_lookup is PropertyExpr) {
7593                                         Report.Error (307, loc, "The property `{0}' cannot " +
7594                                                       "be used with type arguments", full_name);
7595                                         return null;
7596                                 }
7597                         }
7598                         
7599                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7600                         if (member_lookup == null)
7601                                 return null;
7602
7603                         if (args != null) {
7604                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7605                                 if (mg == null)
7606                                         throw new InternalErrorException ();
7607
7608                                 return mg.ResolveGeneric (ec, args);
7609                         }
7610
7611                         // The following DoResolve/DoResolveLValue will do the definite assignment
7612                         // check.
7613
7614                         if (right_side != null)
7615                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7616                         else
7617                                 member_lookup = member_lookup.DoResolve (ec);
7618
7619                         return member_lookup;
7620                 }
7621
7622                 public override Expression DoResolve (EmitContext ec)
7623                 {
7624                         return DoResolve (ec, null, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7625                 }
7626
7627                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7628                 {
7629                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue | ResolveFlags.Type);
7630                 }
7631
7632                 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
7633                 {
7634                         return ResolveNamespaceOrType (ec, false);
7635                 }
7636
7637                 public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent)
7638                 {
7639                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec);
7640
7641                         if (new_expr == null)
7642                                 return null;
7643
7644                         string lookup_id = MemberName.MakeName (Identifier, args);
7645
7646                         if (new_expr is Namespace) {
7647                                 Namespace ns = (Namespace) new_expr;
7648                                 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc);
7649                                 if ((retval != null) && (args != null))
7650                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec);
7651                                 if (!silent && retval == null)
7652                                         Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName);
7653                                 return retval;
7654                         }
7655
7656                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (ec);
7657                         if (tnew_expr == null)
7658                                 return null;
7659
7660                         Type expr_type = tnew_expr.Type;
7661
7662                         if (expr_type.IsPointer){
7663                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7664                                        TypeManager.CSharpName (expr_type) + ")");
7665                                 return null;
7666                         }
7667
7668                         Expression member_lookup;
7669                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, lookup_id, loc);
7670                         if (!silent && member_lookup == null) {
7671                                 Report.Error (234, loc, "The type name `{0}' could not be found in type `{1}'", 
7672                                               Identifier, new_expr.FullName);
7673                                 return null;
7674                         }
7675
7676                         if (!(member_lookup is TypeExpr)) {
7677                                 Report.Error (118, loc, "'{0}.{1}' denotes a '{2}', where a type was expected",
7678                                               new_expr.FullName, Identifier, member_lookup.ExprClassName ());
7679                                 return null;
7680                         }
7681
7682                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (ec);
7683                         if (texpr == null)
7684                                 return null;
7685
7686                         TypeArguments the_args = args;
7687                         if (TypeManager.HasGenericArguments (expr_type)) {
7688                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7689
7690                                 TypeArguments new_args = new TypeArguments (loc);
7691                                 foreach (Type decl in decl_args)
7692                                         new_args.Add (new TypeExpression (decl, loc));
7693
7694                                 if (args != null)
7695                                         new_args.Add (args);
7696
7697                                 the_args = new_args;
7698                         }
7699
7700                         if (the_args != null) {
7701                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7702                                 return ctype.ResolveAsTypeStep (ec);
7703                         }
7704
7705                         return texpr;
7706                 }
7707
7708                 public override void Emit (EmitContext ec)
7709                 {
7710                         throw new Exception ("Should not happen");
7711                 }
7712
7713                 public override string ToString ()
7714                 {
7715                         return expr + "." + MemberName.MakeName (Identifier, args);
7716                 }
7717         }
7718
7719         /// <summary>
7720         ///   Implements checked expressions
7721         /// </summary>
7722         public class CheckedExpr : Expression {
7723
7724                 public Expression Expr;
7725
7726                 public CheckedExpr (Expression e, Location l)
7727                 {
7728                         Expr = e;
7729                         loc = l;
7730                 }
7731
7732                 public override Expression DoResolve (EmitContext ec)
7733                 {
7734                         bool last_check = ec.CheckState;
7735                         bool last_const_check = ec.ConstantCheckState;
7736
7737                         ec.CheckState = true;
7738                         ec.ConstantCheckState = true;
7739                         Expr = Expr.Resolve (ec);
7740                         ec.CheckState = last_check;
7741                         ec.ConstantCheckState = last_const_check;
7742                         
7743                         if (Expr == null)
7744                                 return null;
7745
7746                         if (Expr is Constant)
7747                                 return Expr;
7748                         
7749                         eclass = Expr.eclass;
7750                         type = Expr.Type;
7751                         return this;
7752                 }
7753
7754                 public override void Emit (EmitContext ec)
7755                 {
7756                         bool last_check = ec.CheckState;
7757                         bool last_const_check = ec.ConstantCheckState;
7758                         
7759                         ec.CheckState = true;
7760                         ec.ConstantCheckState = true;
7761                         Expr.Emit (ec);
7762                         ec.CheckState = last_check;
7763                         ec.ConstantCheckState = last_const_check;
7764                 }
7765                 
7766         }
7767
7768         /// <summary>
7769         ///   Implements the unchecked expression
7770         /// </summary>
7771         public class UnCheckedExpr : Expression {
7772
7773                 public Expression Expr;
7774
7775                 public UnCheckedExpr (Expression e, Location l)
7776                 {
7777                         Expr = e;
7778                         loc = l;
7779                 }
7780
7781                 public override Expression DoResolve (EmitContext ec)
7782                 {
7783                         bool last_check = ec.CheckState;
7784                         bool last_const_check = ec.ConstantCheckState;
7785
7786                         ec.CheckState = false;
7787                         ec.ConstantCheckState = false;
7788                         Expr = Expr.Resolve (ec);
7789                         ec.CheckState = last_check;
7790                         ec.ConstantCheckState = last_const_check;
7791
7792                         if (Expr == null)
7793                                 return null;
7794
7795                         if (Expr is Constant)
7796                                 return Expr;
7797                         
7798                         eclass = Expr.eclass;
7799                         type = Expr.Type;
7800                         return this;
7801                 }
7802
7803                 public override void Emit (EmitContext ec)
7804                 {
7805                         bool last_check = ec.CheckState;
7806                         bool last_const_check = ec.ConstantCheckState;
7807                         
7808                         ec.CheckState = false;
7809                         ec.ConstantCheckState = false;
7810                         Expr.Emit (ec);
7811                         ec.CheckState = last_check;
7812                         ec.ConstantCheckState = last_const_check;
7813                 }
7814                 
7815         }
7816
7817         /// <summary>
7818         ///   An Element Access expression.
7819         ///
7820         ///   During semantic analysis these are transformed into 
7821         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7822         /// </summary>
7823         public class ElementAccess : Expression {
7824                 public ArrayList  Arguments;
7825                 public Expression Expr;
7826                 
7827                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7828                 {
7829                         Expr = e;
7830
7831                         loc  = l;
7832                         
7833                         if (e_list == null)
7834                                 return;
7835                         
7836                         Arguments = new ArrayList ();
7837                         foreach (Expression tmp in e_list)
7838                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7839                         
7840                 }
7841
7842                 bool CommonResolve (EmitContext ec)
7843                 {
7844                         Expr = Expr.Resolve (ec);
7845
7846                         if (Expr == null) 
7847                                 return false;
7848
7849                         if (Arguments == null)
7850                                 return false;
7851
7852                         foreach (Argument a in Arguments){
7853                                 if (!a.Resolve (ec, loc))
7854                                         return false;
7855                         }
7856
7857                         return true;
7858                 }
7859
7860                 Expression MakePointerAccess (EmitContext ec, Type t)
7861                 {
7862                         if (t == TypeManager.void_ptr_type){
7863                                 Error (242, "The array index operation is not valid for void pointers");
7864                                 return null;
7865                         }
7866                         if (Arguments.Count != 1){
7867                                 Error (196, "A pointer must be indexed by a single value");
7868                                 return null;
7869                         }
7870                         Expression p;
7871
7872                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7873                         if (p == null)
7874                                 return null;
7875                         return new Indirection (p, loc).Resolve (ec);
7876                 }
7877                 
7878                 public override Expression DoResolve (EmitContext ec)
7879                 {
7880                         if (!CommonResolve (ec))
7881                                 return null;
7882
7883                         //
7884                         // We perform some simple tests, and then to "split" the emit and store
7885                         // code we create an instance of a different class, and return that.
7886                         //
7887                         // I am experimenting with this pattern.
7888                         //
7889                         Type t = Expr.Type;
7890
7891                         if (t == TypeManager.array_type){
7892                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7893                                 return null;
7894                         }
7895                         
7896                         if (t.IsArray)
7897                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7898                         if (t.IsPointer)
7899                                 return MakePointerAccess (ec, Expr.Type);
7900
7901                         FieldExpr fe = Expr as FieldExpr;
7902                         if (fe != null) {
7903                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7904                                 if (ff != null) {
7905                                         return MakePointerAccess (ec, ff.ElementType);
7906                                 }
7907                         }
7908                         return (new IndexerAccess (this, loc)).Resolve (ec);
7909                 }
7910
7911                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7912                 {
7913                         if (!CommonResolve (ec))
7914                                 return null;
7915
7916                         Type t = Expr.Type;
7917                         if (t.IsArray)
7918                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7919
7920                         if (t.IsPointer)
7921                                 return MakePointerAccess (ec, Expr.Type);
7922
7923                         FieldExpr fe = Expr as FieldExpr;
7924                         if (fe != null) {
7925                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7926                                 if (ff != null) {
7927 // TODO: not sure whether it is correct
7928 //                                      if (!ec.InFixedInitializer) {
7929 //                                      if (!ec.InFixedInitializer) {
7930 //                                              Error (1666, "You cannot use fixed sized buffers contained in unfixed expressions. Try using the fixed statement.");
7931 //                                              return null;
7932 //                                      }
7933                                         return MakePointerAccess (ec, ff.ElementType);
7934                                 }
7935                         }
7936                         return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7937                 }
7938                 
7939                 public override void Emit (EmitContext ec)
7940                 {
7941                         throw new Exception ("Should never be reached");
7942                 }
7943         }
7944
7945         /// <summary>
7946         ///   Implements array access 
7947         /// </summary>
7948         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7949                 //
7950                 // Points to our "data" repository
7951                 //
7952                 ElementAccess ea;
7953
7954                 LocalTemporary temp;
7955                 bool prepared;
7956                 
7957                 public ArrayAccess (ElementAccess ea_data, Location l)
7958                 {
7959                         ea = ea_data;
7960                         eclass = ExprClass.Variable;
7961                         loc = l;
7962                 }
7963
7964                 public override Expression DoResolve (EmitContext ec)
7965                 {
7966 #if false
7967                         ExprClass eclass = ea.Expr.eclass;
7968
7969                         // As long as the type is valid
7970                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7971                               eclass == ExprClass.Value)) {
7972                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7973                                 return null;
7974                         }
7975 #endif
7976
7977                         Type t = ea.Expr.Type;
7978                         if (t.GetArrayRank () != ea.Arguments.Count){
7979                                 ea.Error (22,
7980                                           "Incorrect number of indexes for array " +
7981                                           " expected: " + t.GetArrayRank () + " got: " +
7982                                           ea.Arguments.Count);
7983                                 return null;
7984                         }
7985
7986                         type = TypeManager.GetElementType (t);
7987                         if (type.IsPointer && !ec.InUnsafe){
7988                                 UnsafeError (ea.Location);
7989                                 return null;
7990                         }
7991
7992                         foreach (Argument a in ea.Arguments){
7993                                 Type argtype = a.Type;
7994
7995                                 if (argtype == TypeManager.int32_type ||
7996                                     argtype == TypeManager.uint32_type ||
7997                                     argtype == TypeManager.int64_type ||
7998                                     argtype == TypeManager.uint64_type) {
7999                                         Constant c = a.Expr as Constant;
8000                                         if (c != null && c.IsNegative) {
8001                                                 Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)");
8002                                         }
8003                                         continue;
8004                                 }
8005
8006                                 //
8007                                 // Mhm.  This is strage, because the Argument.Type is not the same as
8008                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
8009                                 //
8010                                 // Wonder if I will run into trouble for this.
8011                                 //
8012                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
8013                                 if (a.Expr == null)
8014                                         return null;
8015                         }
8016                         
8017                         eclass = ExprClass.Variable;
8018
8019                         return this;
8020                 }
8021
8022                 /// <summary>
8023                 ///    Emits the right opcode to load an object of Type `t'
8024                 ///    from an array of T
8025                 /// </summary>
8026                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
8027                 {
8028                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8029                                 ig.Emit (OpCodes.Ldelem_U1);
8030                         else if (type == TypeManager.sbyte_type)
8031                                 ig.Emit (OpCodes.Ldelem_I1);
8032                         else if (type == TypeManager.short_type)
8033                                 ig.Emit (OpCodes.Ldelem_I2);
8034                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8035                                 ig.Emit (OpCodes.Ldelem_U2);
8036                         else if (type == TypeManager.int32_type)
8037                                 ig.Emit (OpCodes.Ldelem_I4);
8038                         else if (type == TypeManager.uint32_type)
8039                                 ig.Emit (OpCodes.Ldelem_U4);
8040                         else if (type == TypeManager.uint64_type)
8041                                 ig.Emit (OpCodes.Ldelem_I8);
8042                         else if (type == TypeManager.int64_type)
8043                                 ig.Emit (OpCodes.Ldelem_I8);
8044                         else if (type == TypeManager.float_type)
8045                                 ig.Emit (OpCodes.Ldelem_R4);
8046                         else if (type == TypeManager.double_type)
8047                                 ig.Emit (OpCodes.Ldelem_R8);
8048                         else if (type == TypeManager.intptr_type)
8049                                 ig.Emit (OpCodes.Ldelem_I);
8050                         else if (TypeManager.IsEnumType (type)){
8051                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
8052                         } else if (type.IsValueType){
8053                                 ig.Emit (OpCodes.Ldelema, type);
8054                                 ig.Emit (OpCodes.Ldobj, type);
8055                         } else if (type.IsGenericParameter)
8056                                 ig.Emit (OpCodes.Ldelem_Any, type);
8057                         else
8058                                 ig.Emit (OpCodes.Ldelem_Ref);
8059                 }
8060
8061                 /// <summary>
8062                 ///    Returns the right opcode to store an object of Type `t'
8063                 ///    from an array of T.  
8064                 /// </summary>
8065                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8066                 {
8067                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
8068                         has_type_arg = false; is_stobj = false;
8069                         t = TypeManager.TypeToCoreType (t);
8070                         if (TypeManager.IsEnumType (t))
8071                                 t = TypeManager.EnumToUnderlying (t);
8072                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8073                             t == TypeManager.bool_type)
8074                                 return OpCodes.Stelem_I1;
8075                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8076                                  t == TypeManager.char_type)
8077                                 return OpCodes.Stelem_I2;
8078                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8079                                 return OpCodes.Stelem_I4;
8080                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8081                                 return OpCodes.Stelem_I8;
8082                         else if (t == TypeManager.float_type)
8083                                 return OpCodes.Stelem_R4;
8084                         else if (t == TypeManager.double_type)
8085                                 return OpCodes.Stelem_R8;
8086                         else if (t == TypeManager.intptr_type) {
8087                                 has_type_arg = true;
8088                                 is_stobj = true;
8089                                 return OpCodes.Stobj;
8090                         } else if (t.IsValueType) {
8091                                 has_type_arg = true;
8092                                 is_stobj = true;
8093                                 return OpCodes.Stobj;
8094                         } else if (t.IsGenericParameter) {
8095                                 has_type_arg = true;
8096                                 return OpCodes.Stelem_Any;
8097                         } else
8098                                 return OpCodes.Stelem_Ref;
8099                 }
8100
8101                 MethodInfo FetchGetMethod ()
8102                 {
8103                         ModuleBuilder mb = CodeGen.Module.Builder;
8104                         int arg_count = ea.Arguments.Count;
8105                         Type [] args = new Type [arg_count];
8106                         MethodInfo get;
8107                         
8108                         for (int i = 0; i < arg_count; i++){
8109                                 //args [i++] = a.Type;
8110                                 args [i] = TypeManager.int32_type;
8111                         }
8112                         
8113                         get = mb.GetArrayMethod (
8114                                 ea.Expr.Type, "Get",
8115                                 CallingConventions.HasThis |
8116                                 CallingConventions.Standard,
8117                                 type, args);
8118                         return get;
8119                 }
8120                                 
8121
8122                 MethodInfo FetchAddressMethod ()
8123                 {
8124                         ModuleBuilder mb = CodeGen.Module.Builder;
8125                         int arg_count = ea.Arguments.Count;
8126                         Type [] args = new Type [arg_count];
8127                         MethodInfo address;
8128                         Type ret_type;
8129                         
8130                         ret_type = TypeManager.GetReferenceType (type);
8131                         
8132                         for (int i = 0; i < arg_count; i++){
8133                                 //args [i++] = a.Type;
8134                                 args [i] = TypeManager.int32_type;
8135                         }
8136                         
8137                         address = mb.GetArrayMethod (
8138                                 ea.Expr.Type, "Address",
8139                                 CallingConventions.HasThis |
8140                                 CallingConventions.Standard,
8141                                 ret_type, args);
8142
8143                         return address;
8144                 }
8145
8146                 //
8147                 // Load the array arguments into the stack.
8148                 //
8149                 // If we have been requested to cache the values (cached_locations array
8150                 // initialized), then load the arguments the first time and store them
8151                 // in locals.  otherwise load from local variables.
8152                 //
8153                 void LoadArrayAndArguments (EmitContext ec)
8154                 {
8155                         ILGenerator ig = ec.ig;
8156                         
8157                         ea.Expr.Emit (ec);
8158                         foreach (Argument a in ea.Arguments){
8159                                 Type argtype = a.Expr.Type;
8160                                 
8161                                 a.Expr.Emit (ec);
8162                                 
8163                                 if (argtype == TypeManager.int64_type)
8164                                         ig.Emit (OpCodes.Conv_Ovf_I);
8165                                 else if (argtype == TypeManager.uint64_type)
8166                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
8167                         }
8168                 }
8169
8170                 public void Emit (EmitContext ec, bool leave_copy)
8171                 {
8172                         int rank = ea.Expr.Type.GetArrayRank ();
8173                         ILGenerator ig = ec.ig;
8174
8175                         if (!prepared) {
8176                                 LoadArrayAndArguments (ec);
8177                                 
8178                                 if (rank == 1)
8179                                         EmitLoadOpcode (ig, type);
8180                                 else {
8181                                         MethodInfo method;
8182                                         
8183                                         method = FetchGetMethod ();
8184                                         ig.Emit (OpCodes.Call, method);
8185                                 }
8186                         } else
8187                                 LoadFromPtr (ec.ig, this.type);
8188                         
8189                         if (leave_copy) {
8190                                 ec.ig.Emit (OpCodes.Dup);
8191                                 temp = new LocalTemporary (ec, this.type);
8192                                 temp.Store (ec);
8193                         }
8194                 }
8195                 
8196                 public override void Emit (EmitContext ec)
8197                 {
8198                         Emit (ec, false);
8199                 }
8200
8201                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8202                 {
8203                         int rank = ea.Expr.Type.GetArrayRank ();
8204                         ILGenerator ig = ec.ig;
8205                         Type t = source.Type;
8206                         prepared = prepare_for_load;
8207
8208                         if (prepare_for_load) {
8209                                 AddressOf (ec, AddressOp.LoadStore);
8210                                 ec.ig.Emit (OpCodes.Dup);
8211                                 source.Emit (ec);
8212                                 if (leave_copy) {
8213                                         ec.ig.Emit (OpCodes.Dup);
8214                                         temp = new LocalTemporary (ec, this.type);
8215                                         temp.Store (ec);
8216                                 }
8217                                 StoreFromPtr (ec.ig, t);
8218                                 
8219                                 if (temp != null)
8220                                         temp.Emit (ec);
8221                                 
8222                                 return;
8223                         }
8224                         
8225                         LoadArrayAndArguments (ec);
8226
8227                         if (rank == 1) {
8228                                 bool is_stobj, has_type_arg;
8229                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8230
8231                                 //
8232                                 // The stobj opcode used by value types will need
8233                                 // an address on the stack, not really an array/array
8234                                 // pair
8235                                 //
8236                                 if (is_stobj)
8237                                         ig.Emit (OpCodes.Ldelema, t);
8238                                 
8239                                 source.Emit (ec);
8240                                 if (leave_copy) {
8241                                         ec.ig.Emit (OpCodes.Dup);
8242                                         temp = new LocalTemporary (ec, this.type);
8243                                         temp.Store (ec);
8244                                 }
8245                                 
8246                                 if (is_stobj)
8247                                         ig.Emit (OpCodes.Stobj, t);
8248                                 else if (has_type_arg)
8249                                         ig.Emit (op, t);
8250                                 else
8251                                         ig.Emit (op);
8252                         } else {
8253                                 ModuleBuilder mb = CodeGen.Module.Builder;
8254                                 int arg_count = ea.Arguments.Count;
8255                                 Type [] args = new Type [arg_count + 1];
8256                                 MethodInfo set;
8257                                 
8258                                 source.Emit (ec);
8259                                 if (leave_copy) {
8260                                         ec.ig.Emit (OpCodes.Dup);
8261                                         temp = new LocalTemporary (ec, this.type);
8262                                         temp.Store (ec);
8263                                 }
8264                                 
8265                                 for (int i = 0; i < arg_count; i++){
8266                                         //args [i++] = a.Type;
8267                                         args [i] = TypeManager.int32_type;
8268                                 }
8269
8270                                 args [arg_count] = type;
8271                                 
8272                                 set = mb.GetArrayMethod (
8273                                         ea.Expr.Type, "Set",
8274                                         CallingConventions.HasThis |
8275                                         CallingConventions.Standard,
8276                                         TypeManager.void_type, args);
8277                                 
8278                                 ig.Emit (OpCodes.Call, set);
8279                         }
8280                         
8281                         if (temp != null)
8282                                 temp.Emit (ec);
8283                 }
8284
8285                 public void AddressOf (EmitContext ec, AddressOp mode)
8286                 {
8287                         int rank = ea.Expr.Type.GetArrayRank ();
8288                         ILGenerator ig = ec.ig;
8289
8290                         LoadArrayAndArguments (ec);
8291
8292                         if (rank == 1){
8293                                 ig.Emit (OpCodes.Ldelema, type);
8294                         } else {
8295                                 MethodInfo address = FetchAddressMethod ();
8296                                 ig.Emit (OpCodes.Call, address);
8297                         }
8298                 }
8299         }
8300
8301         
8302         class Indexers {
8303                 public ArrayList Properties;
8304                 static Hashtable map;
8305
8306                 public struct Indexer {
8307                         public readonly Type Type;
8308                         public readonly MethodInfo Getter, Setter;
8309
8310                         public Indexer (Type type, MethodInfo get, MethodInfo set)
8311                         {
8312                                 this.Type = type;
8313                                 this.Getter = get;
8314                                 this.Setter = set;
8315                         }
8316                 }
8317
8318                 static Indexers ()
8319                 {
8320                         map = new Hashtable ();
8321                 }
8322
8323                 Indexers ()
8324                 {
8325                         Properties = new ArrayList ();
8326                 }
8327                                 
8328                 void Append (MemberInfo [] mi)
8329                 {
8330                         foreach (PropertyInfo property in mi){
8331                                 MethodInfo get, set;
8332                                 
8333                                 get = property.GetGetMethod (true);
8334                                 set = property.GetSetMethod (true);
8335                                 Properties.Add (new Indexer (property.PropertyType, get, set));
8336                         }
8337                 }
8338
8339                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8340                 {
8341                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8342
8343                         MemberInfo [] mi = TypeManager.MemberLookup (
8344                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8345                                 BindingFlags.Public | BindingFlags.Instance |
8346                                 BindingFlags.DeclaredOnly, p_name, null);
8347
8348                         if (mi == null || mi.Length == 0)
8349                                 return null;
8350
8351                         return mi;
8352                 }
8353                 
8354                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8355                 {
8356                         Indexers ix = (Indexers) map [lookup_type];
8357
8358                         if (ix != null)
8359                                 return ix;
8360
8361                         Type copy = lookup_type;
8362                         while (copy != TypeManager.object_type && copy != null){
8363                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8364
8365                                 if (mi != null){
8366                                         if (ix == null)
8367                                                 ix = new Indexers ();
8368
8369                                         ix.Append (mi);
8370                                 }
8371                                         
8372                                 copy = copy.BaseType;
8373                         }
8374
8375                         if (!lookup_type.IsInterface)
8376                                 return ix;
8377
8378                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8379                         if (ifaces != null) {
8380                                 foreach (Type itype in ifaces) {
8381                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8382                                         if (mi != null){
8383                                                 if (ix == null)
8384                                                         ix = new Indexers ();
8385                                         
8386                                                 ix.Append (mi);
8387                                         }
8388                                 }
8389                         }
8390
8391                         return ix;
8392                 }
8393         }
8394
8395         /// <summary>
8396         ///   Expressions that represent an indexer call.
8397         /// </summary>
8398         public class IndexerAccess : Expression, IAssignMethod {
8399                 //
8400                 // Points to our "data" repository
8401                 //
8402                 MethodInfo get, set;
8403                 ArrayList set_arguments;
8404                 bool is_base_indexer;
8405
8406                 protected Type indexer_type;
8407                 protected Type current_type;
8408                 protected Expression instance_expr;
8409                 protected ArrayList arguments;
8410                 
8411                 public IndexerAccess (ElementAccess ea, Location loc)
8412                         : this (ea.Expr, false, loc)
8413                 {
8414                         this.arguments = ea.Arguments;
8415                 }
8416
8417                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8418                                          Location loc)
8419                 {
8420                         this.instance_expr = instance_expr;
8421                         this.is_base_indexer = is_base_indexer;
8422                         this.eclass = ExprClass.Value;
8423                         this.loc = loc;
8424                 }
8425
8426                 protected virtual bool CommonResolve (EmitContext ec)
8427                 {
8428                         indexer_type = instance_expr.Type;
8429                         current_type = ec.ContainerType;
8430
8431                         return true;
8432                 }
8433
8434                 public override Expression DoResolve (EmitContext ec)
8435                 {
8436                         ArrayList AllGetters = new ArrayList();
8437                         if (!CommonResolve (ec))
8438                                 return null;
8439
8440                         //
8441                         // Step 1: Query for all `Item' *properties*.  Notice
8442                         // that the actual methods are pointed from here.
8443                         //
8444                         // This is a group of properties, piles of them.  
8445
8446                         bool found_any = false, found_any_getters = false;
8447                         Type lookup_type = indexer_type;
8448
8449                         Indexers ilist;
8450                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8451                         if (ilist != null) {
8452                                 found_any = true;
8453                                 if (ilist.Properties != null) {
8454                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8455                                                 if (ix.Getter != null)
8456                                                         AllGetters.Add(ix.Getter);
8457                                         }
8458                                 }
8459                         }
8460
8461                         if (AllGetters.Count > 0) {
8462                                 found_any_getters = true;
8463                                 get = (MethodInfo) Invocation.OverloadResolve (
8464                                         ec, new MethodGroupExpr (AllGetters, loc),
8465                                         arguments, false, loc);
8466                         }
8467
8468                         if (!found_any) {
8469                                 Report.Error (21, loc,
8470                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8471                                               "' does not have any indexers defined");
8472                                 return null;
8473                         }
8474
8475                         if (!found_any_getters) {
8476                                 Error (154, "indexer can not be used in this context, because " +
8477                                        "it lacks a `get' accessor");
8478                                 return null;
8479                         }
8480
8481                         if (get == null) {
8482                                 Error (1501, "No Overload for method `this' takes `" +
8483                                        arguments.Count + "' arguments");
8484                                 return null;
8485                         }
8486
8487                         //
8488                         // Only base will allow this invocation to happen.
8489                         //
8490                         if (get.IsAbstract && this is BaseIndexerAccess){
8491                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8492                                 return null;
8493                         }
8494
8495                         type = get.ReturnType;
8496                         if (type.IsPointer && !ec.InUnsafe){
8497                                 UnsafeError (loc);
8498                                 return null;
8499                         }
8500
8501                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8502                         
8503                         eclass = ExprClass.IndexerAccess;
8504                         return this;
8505                 }
8506
8507                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8508                 {
8509                         ArrayList AllSetters = new ArrayList();
8510                         if (!CommonResolve (ec))
8511                                 return null;
8512
8513                         bool found_any = false, found_any_setters = false;
8514
8515                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8516                         if (ilist != null) {
8517                                 found_any = true;
8518                                 if (ilist.Properties != null) {
8519                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8520                                                 if (ix.Setter != null)
8521                                                         AllSetters.Add(ix.Setter);
8522                                         }
8523                                 }
8524                         }
8525                         if (AllSetters.Count > 0) {
8526                                 found_any_setters = true;
8527                                 set_arguments = (ArrayList) arguments.Clone ();
8528                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8529                                 set = (MethodInfo) Invocation.OverloadResolve (
8530                                         ec, new MethodGroupExpr (AllSetters, loc),
8531                                         set_arguments, false, loc);
8532                         }
8533
8534                         if (!found_any) {
8535                                 Report.Error (21, loc,
8536                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8537                                               "' does not have any indexers defined");
8538                                 return null;
8539                         }
8540
8541                         if (!found_any_setters) {
8542                                 Error (154, "indexer can not be used in this context, because " +
8543                                        "it lacks a `set' accessor");
8544                                 return null;
8545                         }
8546
8547                         if (set == null) {
8548                                 Error (1501, "No Overload for method `this' takes `" +
8549                                        arguments.Count + "' arguments");
8550                                 return null;
8551                         }
8552
8553                         //
8554                         // Only base will allow this invocation to happen.
8555                         //
8556                         if (set.IsAbstract && this is BaseIndexerAccess){
8557                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8558                                 return null;
8559                         }
8560
8561                         //
8562                         // Now look for the actual match in the list of indexers to set our "return" type
8563                         //
8564                         type = TypeManager.void_type;   // default value
8565                         foreach (Indexers.Indexer ix in ilist.Properties){
8566                                 if (ix.Setter == set){
8567                                         type = ix.Type;
8568                                         break;
8569                                 }
8570                         }
8571                         
8572                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8573
8574                         eclass = ExprClass.IndexerAccess;
8575                         return this;
8576                 }
8577                 
8578                 bool prepared = false;
8579                 LocalTemporary temp;
8580                 
8581                 public void Emit (EmitContext ec, bool leave_copy)
8582                 {
8583                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8584                         if (leave_copy) {
8585                                 ec.ig.Emit (OpCodes.Dup);
8586                                 temp = new LocalTemporary (ec, Type);
8587                                 temp.Store (ec);
8588                         }
8589                 }
8590                 
8591                 //
8592                 // source is ignored, because we already have a copy of it from the
8593                 // LValue resolution and we have already constructed a pre-cached
8594                 // version of the arguments (ea.set_arguments);
8595                 //
8596                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8597                 {
8598                         prepared = prepare_for_load;
8599                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8600                         
8601                         if (prepared) {
8602                                 source.Emit (ec);
8603                                 if (leave_copy) {
8604                                         ec.ig.Emit (OpCodes.Dup);
8605                                         temp = new LocalTemporary (ec, Type);
8606                                         temp.Store (ec);
8607                                 }
8608                         } else if (leave_copy) {
8609                                 temp = new LocalTemporary (ec, Type);
8610                                 source.Emit (ec);
8611                                 temp.Store (ec);
8612                                 a.Expr = temp;
8613                         }
8614                         
8615                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8616                         
8617                         if (temp != null)
8618                                 temp.Emit (ec);
8619                 }
8620                 
8621                 
8622                 public override void Emit (EmitContext ec)
8623                 {
8624                         Emit (ec, false);
8625                 }
8626         }
8627
8628         /// <summary>
8629         ///   The base operator for method names
8630         /// </summary>
8631         public class BaseAccess : Expression {
8632                 string member;
8633                 
8634                 public BaseAccess (string member, Location l)
8635                 {
8636                         this.member = member;
8637                         loc = l;
8638                 }
8639
8640                 public override Expression DoResolve (EmitContext ec)
8641                 {
8642                         Expression c = CommonResolve (ec);
8643
8644                         if (c == null)
8645                                 return null;
8646
8647                         //
8648                         // MethodGroups use this opportunity to flag an error on lacking ()
8649                         //
8650                         if (!(c is MethodGroupExpr))
8651                                 return c.Resolve (ec);
8652                         return c;
8653                 }
8654
8655                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8656                 {
8657                         Expression c = CommonResolve (ec);
8658
8659                         if (c == null)
8660                                 return null;
8661
8662                         //
8663                         // MethodGroups use this opportunity to flag an error on lacking ()
8664                         //
8665                         if (! (c is MethodGroupExpr))
8666                                 return c.DoResolveLValue (ec, right_side);
8667
8668                         return c;
8669                 }
8670
8671                 Expression CommonResolve (EmitContext ec)
8672                 {
8673                         Expression member_lookup;
8674                         Type current_type = ec.ContainerType;
8675                         Type base_type = current_type.BaseType;
8676                         Expression e;
8677
8678                         if (ec.IsStatic){
8679                                 Error (1511, "Keyword base is not allowed in static method");
8680                                 return null;
8681                         }
8682
8683                         if (ec.IsFieldInitializer){
8684                                 Error (1512, "Keyword base is not available in the current context");
8685                                 return null;
8686                         }
8687                         
8688                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
8689                                                       member, AllMemberTypes, AllBindingFlags,
8690                                                       loc);
8691                         if (member_lookup == null) {
8692                                 MemberLookupFailed (
8693                                         ec, base_type, base_type, member, null, loc);
8694                                 return null;
8695                         }
8696
8697                         Expression left;
8698                         
8699                         if (ec.IsStatic)
8700                                 left = new TypeExpression (base_type, loc);
8701                         else
8702                                 left = ec.GetThis (loc);
8703                         
8704                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8705
8706                         if (e is PropertyExpr){
8707                                 PropertyExpr pe = (PropertyExpr) e;
8708
8709                                 pe.IsBase = true;
8710                         }
8711
8712                         if (e is MethodGroupExpr)
8713                                 ((MethodGroupExpr) e).IsBase = true;
8714
8715                         return e;
8716                 }
8717
8718                 public override void Emit (EmitContext ec)
8719                 {
8720                         throw new Exception ("Should never be called"); 
8721                 }
8722         }
8723
8724         /// <summary>
8725         ///   The base indexer operator
8726         /// </summary>
8727         public class BaseIndexerAccess : IndexerAccess {
8728                 public BaseIndexerAccess (ArrayList args, Location loc)
8729                         : base (null, true, loc)
8730                 {
8731                         arguments = new ArrayList ();
8732                         foreach (Expression tmp in args)
8733                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8734                 }
8735
8736                 protected override bool CommonResolve (EmitContext ec)
8737                 {
8738                         instance_expr = ec.GetThis (loc);
8739
8740                         current_type = ec.ContainerType.BaseType;
8741                         indexer_type = current_type;
8742
8743                         foreach (Argument a in arguments){
8744                                 if (!a.Resolve (ec, loc))
8745                                         return false;
8746                         }
8747
8748                         return true;
8749                 }
8750         }
8751         
8752         /// <summary>
8753         ///   This class exists solely to pass the Type around and to be a dummy
8754         ///   that can be passed to the conversion functions (this is used by
8755         ///   foreach implementation to typecast the object return value from
8756         ///   get_Current into the proper type.  All code has been generated and
8757         ///   we only care about the side effect conversions to be performed
8758         ///
8759         ///   This is also now used as a placeholder where a no-action expression
8760         ///   is needed (the `New' class).
8761         /// </summary>
8762         public class EmptyExpression : Expression {
8763                 public static readonly EmptyExpression Null = new EmptyExpression ();
8764
8765                 // TODO: should be protected
8766                 public EmptyExpression ()
8767                 {
8768                         type = TypeManager.object_type;
8769                         eclass = ExprClass.Value;
8770                         loc = Location.Null;
8771                 }
8772
8773                 public EmptyExpression (Type t)
8774                 {
8775                         type = t;
8776                         eclass = ExprClass.Value;
8777                         loc = Location.Null;
8778                 }
8779                 
8780                 public override Expression DoResolve (EmitContext ec)
8781                 {
8782                         return this;
8783                 }
8784
8785                 public override void Emit (EmitContext ec)
8786                 {
8787                         // nothing, as we only exist to not do anything.
8788                 }
8789
8790                 //
8791                 // This is just because we might want to reuse this bad boy
8792                 // instead of creating gazillions of EmptyExpressions.
8793                 // (CanImplicitConversion uses it)
8794                 //
8795                 public void SetType (Type t)
8796                 {
8797                         type = t;
8798                 }
8799         }
8800
8801         public class UserCast : Expression {
8802                 MethodBase method;
8803                 Expression source;
8804                 
8805                 public UserCast (MethodInfo method, Expression source, Location l)
8806                 {
8807                         this.method = method;
8808                         this.source = source;
8809                         type = method.ReturnType;
8810                         eclass = ExprClass.Value;
8811                         loc = l;
8812                 }
8813
8814                 public Expression Source {
8815                         get {
8816                                 return source;
8817                         }
8818                 }
8819                         
8820                 public override Expression DoResolve (EmitContext ec)
8821                 {
8822                         //
8823                         // We are born fully resolved
8824                         //
8825                         return this;
8826                 }
8827
8828                 public override void Emit (EmitContext ec)
8829                 {
8830                         ILGenerator ig = ec.ig;
8831
8832                         source.Emit (ec);
8833                         
8834                         if (method is MethodInfo)
8835                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8836                         else
8837                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8838
8839                 }
8840         }
8841
8842         // <summary>
8843         //   This class is used to "construct" the type during a typecast
8844         //   operation.  Since the Type.GetType class in .NET can parse
8845         //   the type specification, we just use this to construct the type
8846         //   one bit at a time.
8847         // </summary>
8848         public class ComposedCast : TypeExpr {
8849                 Expression left;
8850                 string dim;
8851                 
8852                 public ComposedCast (Expression left, string dim, Location l)
8853                 {
8854                         this.left = left;
8855                         this.dim = dim;
8856                         loc = l;
8857                 }
8858
8859                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8860                 {
8861                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec);
8862                         if (lexpr == null)
8863                                 return null;
8864
8865                         Type ltype = lexpr.Type;
8866
8867                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8868                                 Report.Error (1547, Location,
8869                                               "Keyword 'void' cannot be used in this context");
8870                                 return null;
8871                         }
8872
8873                         if ((dim.Length > 0) && (dim [0] == '?')) {
8874                                 TypeExpr nullable = new NullableType (left, loc);
8875                                 if (dim.Length > 1)
8876                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8877                                 return nullable.ResolveAsTypeTerminal (ec);
8878                         }
8879
8880                         int pos = 0;
8881                         while ((pos < dim.Length) && (dim [pos] == '[')) {
8882                                 pos++;
8883
8884                                 if (dim [pos] == ']') {
8885                                         ltype = ltype.MakeArrayType ();
8886                                         pos++;
8887
8888                                         if (pos < dim.Length)
8889                                                 continue;
8890
8891                                         type = ltype;
8892                                         eclass = ExprClass.Type;
8893                                         return this;
8894                                 }
8895
8896                                 int rank = 0;
8897                                 while (dim [pos] == ',') {
8898                                         pos++; rank++;
8899                                 }
8900
8901                                 if ((dim [pos] != ']') || (pos != dim.Length-1))
8902                                         return null;
8903                                                 
8904                                 type = ltype.MakeArrayType (rank + 1);
8905                                 eclass = ExprClass.Type;
8906                                 return this;
8907                         }
8908
8909                         if (dim != "") {
8910                                 //
8911                                 // ltype.Fullname is already fully qualified, so we can skip
8912                                 // a lot of probes, and go directly to TypeManager.LookupType
8913                                 //
8914                                 string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
8915                                 string cname = fname + dim;
8916                                 type = TypeManager.LookupTypeDirect (cname);
8917                                 if (type == null){
8918                                         //
8919                                         // For arrays of enumerations we are having a problem
8920                                         // with the direct lookup.  Need to investigate.
8921                                         //
8922                                         // For now, fall back to the full lookup in that case.
8923                                         //
8924                                         FullNamedExpression e = ec.DeclSpace.LookupType (cname, false, loc);
8925                                         if (e is TypeExpr)
8926                                                 type = ((TypeExpr) e).ResolveType (ec);
8927                                         if (type == null)
8928                                                 return null;
8929                                 }
8930                         } else {
8931                                 type = ltype;
8932                         }
8933
8934                         if (!ec.InUnsafe && type.IsPointer){
8935                                 UnsafeError (loc);
8936                                 return null;
8937                         }
8938
8939                         if (type.IsArray && (type.GetElementType () == TypeManager.arg_iterator_type ||
8940                                 type.GetElementType () == TypeManager.typed_reference_type)) {
8941                                 Report.Error (611, loc, "Array elements cannot be of type '{0}'", TypeManager.CSharpName (type.GetElementType ()));
8942                                 return null;
8943                         }
8944                         
8945                         eclass = ExprClass.Type;
8946                         return this;
8947                 }
8948
8949                 public override string Name {
8950                         get {
8951                                 return left + dim;
8952                         }
8953                 }
8954
8955                 public override string FullName {
8956                         get {
8957                                 return type.FullName;
8958                         }
8959                 }
8960         }
8961
8962         public class FixedBufferPtr: Expression {
8963                 Expression array;
8964
8965                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8966                 {
8967                         this.array = array;
8968                         this.loc = l;
8969
8970                         type = TypeManager.GetPointerType (array_type);
8971                         eclass = ExprClass.Value;
8972                 }
8973
8974                 public override void Emit(EmitContext ec)
8975                 {
8976                         array.Emit (ec);
8977                 }
8978
8979                 public override Expression DoResolve (EmitContext ec)
8980                 {
8981                         //
8982                         // We are born fully resolved
8983                         //
8984                         return this;
8985                 }
8986         }
8987
8988
8989         //
8990         // This class is used to represent the address of an array, used
8991         // only by the Fixed statement, this generates "&a [0]" construct
8992         // for fixed (char *pa = a)
8993         //
8994         public class ArrayPtr : FixedBufferPtr {
8995                 Type array_type;
8996                 
8997                 public ArrayPtr (Expression array, Type array_type, Location l):
8998                         base (array, array_type, l)
8999                 {
9000                         this.array_type = array_type;
9001                 }
9002
9003                 public override void Emit (EmitContext ec)
9004                 {
9005                         base.Emit (ec);
9006                         
9007                         ILGenerator ig = ec.ig;
9008                         IntLiteral.EmitInt (ig, 0);
9009                         ig.Emit (OpCodes.Ldelema, array_type);
9010                 }
9011         }
9012
9013         //
9014         // Used by the fixed statement
9015         //
9016         public class StringPtr : Expression {
9017                 LocalBuilder b;
9018                 
9019                 public StringPtr (LocalBuilder b, Location l)
9020                 {
9021                         this.b = b;
9022                         eclass = ExprClass.Value;
9023                         type = TypeManager.char_ptr_type;
9024                         loc = l;
9025                 }
9026
9027                 public override Expression DoResolve (EmitContext ec)
9028                 {
9029                         // This should never be invoked, we are born in fully
9030                         // initialized state.
9031
9032                         return this;
9033                 }
9034
9035                 public override void Emit (EmitContext ec)
9036                 {
9037                         ILGenerator ig = ec.ig;
9038
9039                         ig.Emit (OpCodes.Ldloc, b);
9040                         ig.Emit (OpCodes.Conv_I);
9041                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
9042                         ig.Emit (OpCodes.Add);
9043                 }
9044         }
9045         
9046         //
9047         // Implements the `stackalloc' keyword
9048         //
9049         public class StackAlloc : Expression {
9050                 Type otype;
9051                 Expression t;
9052                 Expression count;
9053                 
9054                 public StackAlloc (Expression type, Expression count, Location l)
9055                 {
9056                         t = type;
9057                         this.count = count;
9058                         loc = l;
9059                 }
9060
9061                 public override Expression DoResolve (EmitContext ec)
9062                 {
9063                         count = count.Resolve (ec);
9064                         if (count == null)
9065                                 return null;
9066                         
9067                         if (count.Type != TypeManager.int32_type){
9068                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9069                                 if (count == null)
9070                                         return null;
9071                         }
9072
9073                         Constant c = count as Constant;
9074                         if (c != null && c.IsNegative) {
9075                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9076                                 return null;
9077                         }
9078
9079                         if (ec.CurrentBranching.InCatch () ||
9080                             ec.CurrentBranching.InFinally (true)) {
9081                                 Error (255,
9082                                               "stackalloc can not be used in a catch or finally block");
9083                                 return null;
9084                         }
9085
9086                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec);
9087                         if (texpr == null)
9088                                 return null;
9089
9090                         otype = texpr.Type;
9091
9092                         if (!TypeManager.VerifyUnManaged (otype, loc))
9093                                 return null;
9094
9095                         type = TypeManager.GetPointerType (otype);
9096                         eclass = ExprClass.Value;
9097
9098                         return this;
9099                 }
9100
9101                 public override void Emit (EmitContext ec)
9102                 {
9103                         int size = GetTypeSize (otype);
9104                         ILGenerator ig = ec.ig;
9105                                 
9106                         if (size == 0)
9107                                 ig.Emit (OpCodes.Sizeof, otype);
9108                         else
9109                                 IntConstant.EmitInt (ig, size);
9110                         count.Emit (ec);
9111                         ig.Emit (OpCodes.Mul);
9112                         ig.Emit (OpCodes.Localloc);
9113                 }
9114         }
9115 }