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