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