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