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