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