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