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