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