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