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