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