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