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