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