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