fix this up for the migster
[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                 bool emit_conv_done = false;
3078                 //
3079                 // Are we also concating objects?
3080                 //
3081                 bool is_strings_only = true;
3082                 
3083                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3084                 {
3085                         this.loc = loc;
3086                         type = TypeManager.string_type;
3087                         eclass = ExprClass.Value;
3088                 
3089                         operands = new ArrayList (2);
3090                         Append (ec, left);
3091                         Append (ec, right);
3092                 }
3093                 
3094                 public override Expression DoResolve (EmitContext ec)
3095                 {
3096                         if (invalid)
3097                                 return null;
3098                         
3099                         return this;
3100                 }
3101                 
3102                 public void Append (EmitContext ec, Expression operand)
3103                 {
3104                         //
3105                         // Constant folding
3106                         //
3107                         if (operand is StringConstant && operands.Count != 0) {
3108                                 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3109                                 if (last_operand != null) {
3110                                         operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
3111                                         return;
3112                                 }
3113                         }
3114                         
3115                         //
3116                         // Conversion to object
3117                         //
3118                         if (operand.Type != TypeManager.string_type) {
3119                                 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3120                                 
3121                                 if (no == null) {
3122                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3123                                         invalid = true;
3124                                 }
3125                                 operand = no;
3126                         }
3127                         
3128                         operands.Add (operand);
3129                 }
3130
3131                 public override void Emit (EmitContext ec)
3132                 {
3133                         MethodInfo concat_method = null;
3134                         
3135                         //
3136                         // Do conversion to arguments; check for strings only
3137                         //
3138                         
3139                         // This can get called multiple times, so we have to deal with that.
3140                         if (!emit_conv_done) {
3141                                 emit_conv_done = true;
3142                                 for (int i = 0; i < operands.Count; i ++) {
3143                                         Expression e = (Expression) operands [i];
3144                                         is_strings_only &= e.Type == TypeManager.string_type;
3145                                 }
3146                                 
3147                                 for (int i = 0; i < operands.Count; i ++) {
3148                                         Expression e = (Expression) operands [i];
3149                                         
3150                                         if (! is_strings_only && e.Type == TypeManager.string_type) {
3151                                                 // need to make sure this is an object, because the EmitParams
3152                                                 // method might look at the type of this expression, see it is a
3153                                                 // string and emit a string [] when we want an object [];
3154                                                 
3155                                                 e = new EmptyCast (e, TypeManager.object_type);
3156                                         }
3157                                         operands [i] = new Argument (e, Argument.AType.Expression);
3158                                 }
3159                         }
3160                         
3161                         //
3162                         // Find the right method
3163                         //
3164                         switch (operands.Count) {
3165                         case 1:
3166                                 //
3167                                 // This should not be possible, because simple constant folding
3168                                 // is taken care of in the Binary code.
3169                                 //
3170                                 throw new Exception ("how did you get here?");
3171                         
3172                         case 2:
3173                                 concat_method = is_strings_only ? 
3174                                         TypeManager.string_concat_string_string :
3175                                         TypeManager.string_concat_object_object ;
3176                                 break;
3177                         case 3:
3178                                 concat_method = is_strings_only ? 
3179                                         TypeManager.string_concat_string_string_string :
3180                                         TypeManager.string_concat_object_object_object ;
3181                                 break;
3182                         case 4:
3183                                 //
3184                                 // There is not a 4 param overlaod for object (the one that there is
3185                                 // is actually a varargs methods, and is only in corlib because it was
3186                                 // introduced there before.).
3187                                 //
3188                                 if (!is_strings_only)
3189                                         goto default;
3190                                 
3191                                 concat_method = TypeManager.string_concat_string_string_string_string;
3192                                 break;
3193                         default:
3194                                 concat_method = is_strings_only ? 
3195                                         TypeManager.string_concat_string_dot_dot_dot :
3196                                         TypeManager.string_concat_object_dot_dot_dot ;
3197                                 break;
3198                         }
3199                         
3200                         Invocation.EmitArguments (ec, concat_method, operands, false, null);
3201                         ec.ig.Emit (OpCodes.Call, concat_method);
3202                 }
3203         }
3204
3205         //
3206         // Object created with +/= on delegates
3207         //
3208         public class BinaryDelegate : Expression {
3209                 MethodInfo method;
3210                 ArrayList  args;
3211
3212                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3213                 {
3214                         method = mi;
3215                         this.args = args;
3216                         type = t;
3217                         eclass = ExprClass.Value;
3218                 }
3219
3220                 public override Expression DoResolve (EmitContext ec)
3221                 {
3222                         return this;
3223                 }
3224
3225                 public override void Emit (EmitContext ec)
3226                 {
3227                         ILGenerator ig = ec.ig;
3228                         
3229                         Invocation.EmitArguments (ec, method, args, false, null);
3230                         
3231                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3232                         ig.Emit (OpCodes.Castclass, type);
3233                 }
3234
3235                 public Expression Right {
3236                         get {
3237                                 Argument arg = (Argument) args [1];
3238                                 return arg.Expr;
3239                         }
3240                 }
3241
3242                 public bool IsAddition {
3243                         get {
3244                                 return method == TypeManager.delegate_combine_delegate_delegate;
3245                         }
3246                 }
3247         }
3248         
3249         //
3250         // User-defined conditional logical operator
3251         public class ConditionalLogicalOperator : Expression {
3252                 Expression left, right;
3253                 bool is_and;
3254
3255                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3256                 {
3257                         type = t;
3258                         eclass = ExprClass.Value;
3259                         this.loc = loc;
3260                         this.left = left;
3261                         this.right = right;
3262                         this.is_and = is_and;
3263                 }
3264
3265                 protected void Error19 ()
3266                 {
3267                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3268                 }
3269
3270                 protected void Error218 ()
3271                 {
3272                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3273                                "declarations of operator true and operator false");
3274                 }
3275
3276                 Expression op_true, op_false, op;
3277                 LocalTemporary left_temp;
3278
3279                 public override Expression DoResolve (EmitContext ec)
3280                 {
3281                         MethodInfo method;
3282                         Expression operator_group;
3283
3284                         operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3285                         if (operator_group == null) {
3286                                 Error19 ();
3287                                 return null;
3288                         }
3289
3290                         left_temp = new LocalTemporary (ec, type);
3291
3292                         ArrayList arguments = new ArrayList ();
3293                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3294                         arguments.Add (new Argument (right, Argument.AType.Expression));
3295                         method = Invocation.OverloadResolve (
3296                                 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3297                                 as MethodInfo;
3298                         if ((method == null) || (method.ReturnType != type)) {
3299                                 Error19 ();
3300                                 return null;
3301                         }
3302
3303                         op = new StaticCallExpr (method, arguments, loc);
3304
3305                         op_true = GetOperatorTrue (ec, left_temp, loc);
3306                         op_false = GetOperatorFalse (ec, left_temp, loc);
3307                         if ((op_true == null) || (op_false == null)) {
3308                                 Error218 ();
3309                                 return null;
3310                         }
3311
3312                         return this;
3313                 }
3314
3315                 public override void Emit (EmitContext ec)
3316                 {
3317                         ILGenerator ig = ec.ig;
3318                         Label false_target = ig.DefineLabel ();
3319                         Label end_target = ig.DefineLabel ();
3320
3321                         left.Emit (ec);
3322                         left_temp.Store (ec);
3323
3324                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3325                         left_temp.Emit (ec);
3326                         ig.Emit (OpCodes.Br, end_target);
3327                         ig.MarkLabel (false_target);
3328                         op.Emit (ec);
3329                         ig.MarkLabel (end_target);
3330                 }
3331         }
3332
3333         public class PointerArithmetic : Expression {
3334                 Expression left, right;
3335                 bool is_add;
3336
3337                 //
3338                 // We assume that `l' is always a pointer
3339                 //
3340                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3341                 {
3342                         type = t;
3343                         this.loc = loc;
3344                         left = l;
3345                         right = r;
3346                         is_add = is_addition;
3347                 }
3348
3349                 public override Expression DoResolve (EmitContext ec)
3350                 {
3351                         eclass = ExprClass.Variable;
3352                         
3353                         if (left.Type == TypeManager.void_ptr_type) {
3354                                 Error (242, "The operation in question is undefined on void pointers");
3355                                 return null;
3356                         }
3357                         
3358                         return this;
3359                 }
3360
3361                 public override void Emit (EmitContext ec)
3362                 {
3363                         Type op_type = left.Type;
3364                         ILGenerator ig = ec.ig;
3365                         Type element = TypeManager.GetElementType (op_type);
3366                         int size = GetTypeSize (element);
3367                         Type rtype = right.Type;
3368                         
3369                         if (rtype.IsPointer){
3370                                 //
3371                                 // handle (pointer - pointer)
3372                                 //
3373                                 left.Emit (ec);
3374                                 right.Emit (ec);
3375                                 ig.Emit (OpCodes.Sub);
3376
3377                                 if (size != 1){
3378                                         if (size == 0)
3379                                                 ig.Emit (OpCodes.Sizeof, element);
3380                                         else 
3381                                                 IntLiteral.EmitInt (ig, size);
3382                                         ig.Emit (OpCodes.Div);
3383                                 }
3384                                 ig.Emit (OpCodes.Conv_I8);
3385                         } else {
3386                                 //
3387                                 // handle + and - on (pointer op int)
3388                                 //
3389                                 left.Emit (ec);
3390                                 ig.Emit (OpCodes.Conv_I);
3391                                 right.Emit (ec);
3392                                 if (size != 1){
3393                                         if (size == 0)
3394                                                 ig.Emit (OpCodes.Sizeof, element);
3395                                         else 
3396                                                 IntLiteral.EmitInt (ig, size);
3397                                         if (rtype == TypeManager.int64_type)
3398                                                 ig.Emit (OpCodes.Conv_I8);
3399                                         else if (rtype == TypeManager.uint64_type)
3400                                                 ig.Emit (OpCodes.Conv_U8);
3401                                         ig.Emit (OpCodes.Mul);
3402                                 }
3403                                 
3404                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3405                                         ig.Emit (OpCodes.Conv_I);
3406                                 
3407                                 if (is_add)
3408                                         ig.Emit (OpCodes.Add);
3409                                 else
3410                                         ig.Emit (OpCodes.Sub);
3411                         }
3412                 }
3413         }
3414         
3415         /// <summary>
3416         ///   Implements the ternary conditional operator (?:)
3417         /// </summary>
3418         public class Conditional : Expression {
3419                 Expression expr, trueExpr, falseExpr;
3420                 
3421                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3422                 {
3423                         this.expr = expr;
3424                         this.trueExpr = trueExpr;
3425                         this.falseExpr = falseExpr;
3426                         this.loc = l;
3427                 }
3428
3429                 public Expression Expr {
3430                         get {
3431                                 return expr;
3432                         }
3433                 }
3434
3435                 public Expression TrueExpr {
3436                         get {
3437                                 return trueExpr;
3438                         }
3439                 }
3440
3441                 public Expression FalseExpr {
3442                         get {
3443                                 return falseExpr;
3444                         }
3445                 }
3446
3447                 public override Expression DoResolve (EmitContext ec)
3448                 {
3449                         expr = expr.Resolve (ec);
3450
3451                         if (expr == null)
3452                                 return null;
3453                         
3454                         if (expr.Type != TypeManager.bool_type){
3455                                 expr = Expression.ResolveBoolean (
3456                                         ec, expr, loc);
3457                                 
3458                                 if (expr == null)
3459                                         return null;
3460                         }
3461                         
3462                         trueExpr = trueExpr.Resolve (ec);
3463                         falseExpr = falseExpr.Resolve (ec);
3464
3465                         if (trueExpr == null || falseExpr == null)
3466                                 return null;
3467
3468                         if ((trueExpr is NullLiteral) && (falseExpr is NullLiteral))
3469                                 return trueExpr;
3470
3471                         eclass = ExprClass.Value;
3472                         if (trueExpr.Type == falseExpr.Type)
3473                                 type = trueExpr.Type;
3474                         else {
3475                                 Expression conv;
3476                                 Type true_type = trueExpr.Type;
3477                                 Type false_type = falseExpr.Type;
3478
3479                                 //
3480                                 // First, if an implicit conversion exists from trueExpr
3481                                 // to falseExpr, then the result type is of type falseExpr.Type
3482                                 //
3483                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3484                                 if (conv != null){
3485                                         //
3486                                         // Check if both can convert implicitl to each other's type
3487                                         //
3488                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3489                                                 Error (172,
3490                                                        "Can not compute type of conditional expression " +
3491                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3492                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3493                                                        "' convert implicitly to each other");
3494                                                 return null;
3495                                         }
3496                                         type = false_type;
3497                                         trueExpr = conv;
3498                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3499                                         type = true_type;
3500                                         falseExpr = conv;
3501                                 } else {
3502                                         Error (173, "The type of the conditional expression can " +
3503                                                "not be computed because there is no implicit conversion" +
3504                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3505                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3506                                         return null;
3507                                 }
3508                         }
3509
3510                         if (expr is BoolConstant){
3511                                 BoolConstant bc = (BoolConstant) expr;
3512
3513                                 if (bc.Value)
3514                                         return trueExpr;
3515                                 else
3516                                         return falseExpr;
3517                         }
3518
3519                         return this;
3520                 }
3521
3522                 public override void Emit (EmitContext ec)
3523                 {
3524                         ILGenerator ig = ec.ig;
3525                         Label false_target = ig.DefineLabel ();
3526                         Label end_target = ig.DefineLabel ();
3527
3528                         expr.EmitBranchable (ec, false_target, false);
3529                         trueExpr.Emit (ec);
3530                         ig.Emit (OpCodes.Br, end_target);
3531                         ig.MarkLabel (false_target);
3532                         falseExpr.Emit (ec);
3533                         ig.MarkLabel (end_target);
3534                 }
3535
3536         }
3537
3538         /// <summary>
3539         ///   Local variables
3540         /// </summary>
3541         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3542                 public readonly string Name;
3543                 public readonly Block Block;
3544                 public LocalInfo local_info;
3545                 bool is_readonly;
3546                 bool prepared;
3547                 LocalTemporary temp;
3548                 
3549                 public LocalVariableReference (Block block, string name, Location l)
3550                 {
3551                         Block = block;
3552                         Name = name;
3553                         loc = l;
3554                         eclass = ExprClass.Variable;
3555                 }
3556
3557                 //
3558                 // Setting `is_readonly' to false will allow you to create a writable
3559                 // reference to a read-only variable.  This is used by foreach and using.
3560                 //
3561                 public LocalVariableReference (Block block, string name, Location l,
3562                                                LocalInfo local_info, bool is_readonly)
3563                         : this (block, name, l)
3564                 {
3565                         this.local_info = local_info;
3566                         this.is_readonly = is_readonly;
3567                 }
3568
3569                 public VariableInfo VariableInfo {
3570                         get {
3571                                 return local_info.VariableInfo;
3572                         }
3573                 }
3574
3575                 public bool IsReadOnly {
3576                         get {
3577                                 return is_readonly;
3578                         }
3579                 }
3580
3581                 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3582                 {
3583                         if (local_info == null) {
3584                                 local_info = Block.GetLocalInfo (Name);
3585                                 is_readonly = local_info.ReadOnly;
3586                         }
3587
3588                         type = local_info.VariableType;
3589
3590                         VariableInfo variable_info = local_info.VariableInfo;
3591                         if (lvalue_right_side != null){
3592                                 if (is_readonly){
3593                                         Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3594                                         return null;
3595                                 }
3596                                 
3597                                 if (variable_info != null)
3598                                         variable_info.SetAssigned (ec);
3599                         }
3600                         
3601                         Expression e = Block.GetConstantExpression (Name);
3602                         if (e != null) {
3603                                 local_info.Used = true;
3604                                 eclass = ExprClass.Value;
3605                                 return e.Resolve (ec);
3606                         }
3607
3608                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3609                                 return null;
3610
3611                         if (lvalue_right_side == null)
3612                                 local_info.Used = true;
3613
3614                         if (ec.CurrentAnonymousMethod != null){
3615                                 //
3616                                 // If we are referencing a variable from the external block
3617                                 // flag it for capturing
3618                                 //
3619                                 if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){
3620                                         ec.CaptureVariable (local_info);
3621                                         //Console.WriteLine ("Capturing at " + loc);
3622                                 }
3623                         }
3624
3625                         return this;
3626                 }
3627                 
3628                 public override Expression DoResolve (EmitContext ec)
3629                 {
3630                         return DoResolveBase (ec, null);
3631                 }
3632
3633                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3634                 {
3635                         Expression ret = DoResolveBase (ec, right_side);
3636                         if (ret != null)
3637                                 CheckObsoleteAttribute (ret.Type);
3638                         
3639                         return ret;
3640                 }
3641
3642                 public bool VerifyFixed (bool is_expression)
3643                 {
3644                         return !is_expression || local_info.IsFixed;
3645                 }
3646
3647                 public override void Emit (EmitContext ec)
3648                 {
3649                         ILGenerator ig = ec.ig;
3650
3651                         if (local_info.FieldBuilder == null){
3652                                 //
3653                                 // A local variable on the local CLR stack
3654                                 //
3655                                 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3656                         } else {
3657                                 //
3658                                 // A local variable captured by anonymous methods.
3659                                 //
3660                                 if (!prepared)
3661                                         ec.EmitCapturedVariableInstance (local_info);
3662                                 
3663                                 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3664                         }
3665                 }
3666                 
3667                 public void Emit (EmitContext ec, bool leave_copy)
3668                 {
3669                         Emit (ec);
3670                         if (leave_copy){
3671                                 ec.ig.Emit (OpCodes.Dup);
3672                                 if (local_info.FieldBuilder != null){
3673                                         temp = new LocalTemporary (ec, Type);
3674                                         temp.Store (ec);
3675                                 }
3676                         }
3677                 }
3678                 
3679                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3680                 {
3681                         ILGenerator ig = ec.ig;
3682                         prepared = prepare_for_load;
3683
3684                         if (local_info.FieldBuilder == null){
3685                                 //
3686                                 // A local variable on the local CLR stack
3687                                 //
3688                                 if (local_info.LocalBuilder == null)
3689                                         throw new Exception ("This should not happen: both Field and Local are null");
3690                                 
3691                                 source.Emit (ec);
3692                                 if (leave_copy)
3693                                         ec.ig.Emit (OpCodes.Dup);
3694                                 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3695                         } else {
3696                                 //
3697                                 // A local variable captured by anonymous methods or itereators.
3698                                 //
3699                                 ec.EmitCapturedVariableInstance (local_info);
3700
3701                                 if (prepare_for_load)
3702                                         ig.Emit (OpCodes.Dup);
3703                                 source.Emit (ec);
3704                                 if (leave_copy){
3705                                         ig.Emit (OpCodes.Dup);
3706                                         temp = new LocalTemporary (ec, Type);
3707                                         temp.Store (ec);
3708                                 }
3709                                 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3710                                 if (temp != null)
3711                                         temp.Emit (ec);
3712                         }
3713                 }
3714                 
3715                 public void AddressOf (EmitContext ec, AddressOp mode)
3716                 {
3717                         ILGenerator ig = ec.ig;
3718
3719                         if (local_info.FieldBuilder == null){
3720                                 //
3721                                 // A local variable on the local CLR stack
3722                                 //
3723                                 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3724                         } else {
3725                                 //
3726                                 // A local variable captured by anonymous methods or iterators
3727                                 //
3728                                 ec.EmitCapturedVariableInstance (local_info);
3729                                 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3730                         }
3731                 }
3732
3733                 public override string ToString ()
3734                 {
3735                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3736                 }
3737         }
3738
3739         /// <summary>
3740         ///   This represents a reference to a parameter in the intermediate
3741         ///   representation.
3742         /// </summary>
3743         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3744                 Parameters pars;
3745                 String name;
3746                 int idx;
3747                 Block block;
3748                 VariableInfo vi;
3749                 public Parameter.Modifier mod;
3750                 public bool is_ref, is_out, prepared;
3751
3752                 public bool IsOut {
3753                         get {
3754                                 return is_out;
3755                         }
3756                 }
3757
3758                 public bool IsRef {
3759                         get {
3760                                 return is_ref;
3761                         }
3762                 }
3763
3764                 LocalTemporary temp;
3765                 
3766                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3767                 {
3768                         this.pars = pars;
3769                         this.block = block;
3770                         this.idx  = idx;
3771                         this.name = name;
3772                         this.loc = loc;
3773                         eclass = ExprClass.Variable;
3774                 }
3775
3776                 public VariableInfo VariableInfo {
3777                         get { return vi; }
3778                 }
3779
3780                 public bool VerifyFixed (bool is_expression)
3781                 {
3782                         return !is_expression || TypeManager.IsValueType (type);
3783                 }
3784
3785                 public bool IsAssigned (EmitContext ec, Location loc)
3786                 {
3787                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3788                                 return true;
3789
3790                         Report.Error (165, loc,
3791                                       "Use of unassigned parameter `" + name + "'");
3792                         return false;
3793                 }
3794
3795                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3796                 {
3797                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3798                                 return true;
3799
3800                         Report.Error (170, loc,
3801                                       "Use of possibly unassigned field `" + field_name + "'");
3802                         return false;
3803                 }
3804
3805                 public void SetAssigned (EmitContext ec)
3806                 {
3807                         if (is_out && ec.DoFlowAnalysis)
3808                                 ec.CurrentBranching.SetAssigned (vi);
3809                 }
3810
3811                 public void SetFieldAssigned (EmitContext ec, string field_name)        
3812                 {
3813                         if (is_out && ec.DoFlowAnalysis)
3814                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3815                 }
3816
3817                 protected void DoResolveBase (EmitContext ec)
3818                 {
3819                         type = pars.GetParameterInfo (ec, idx, out mod);
3820                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3821                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3822                         eclass = ExprClass.Variable;
3823
3824                         if (is_out)
3825                                 vi = block.ParameterMap [idx];
3826
3827                         if (ec.CurrentAnonymousMethod != null){
3828                                 if (is_ref){
3829                                         Report.Error (1628, Location,
3830                                                       "Can not reference a ref or out parameter in an anonymous method");
3831                                         return;
3832                                 }
3833                                 
3834                                 //
3835                                 // If we are referencing the parameter from the external block
3836                                 // flag it for capturing
3837                                 //
3838                                 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3839                                 if (!block.IsLocalParameter (name)){
3840                                         ec.CaptureParameter (name, type, idx);
3841                                 }
3842                         }
3843                 }
3844
3845                 //
3846                 // Notice that for ref/out parameters, the type exposed is not the
3847                 // same type exposed externally.
3848                 //
3849                 // for "ref int a":
3850                 //   externally we expose "int&"
3851                 //   here we expose       "int".
3852                 //
3853                 // We record this in "is_ref".  This means that the type system can treat
3854                 // the type as it is expected, but when we generate the code, we generate
3855                 // the alternate kind of code.
3856                 //
3857                 public override Expression DoResolve (EmitContext ec)
3858                 {
3859                         DoResolveBase (ec);
3860
3861                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3862                                 return null;
3863
3864                         if (ec.RemapToProxy)
3865                                 return ec.RemapParameter (idx);
3866                         
3867                         return this;
3868                 }
3869
3870                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3871                 {
3872                         DoResolveBase (ec);
3873
3874                         SetAssigned (ec);
3875
3876                         if (ec.RemapToProxy)
3877                                 return ec.RemapParameterLValue (idx, right_side);
3878                         
3879                         return this;
3880                 }
3881
3882                 static public void EmitLdArg (ILGenerator ig, int x)
3883                 {
3884                         if (x <= 255){
3885                                 switch (x){
3886                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3887                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3888                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3889                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3890                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3891                                 }
3892                         } else
3893                                 ig.Emit (OpCodes.Ldarg, x);
3894                 }
3895                 
3896                 //
3897                 // This method is used by parameters that are references, that are
3898                 // being passed as references:  we only want to pass the pointer (that
3899                 // is already stored in the parameter, not the address of the pointer,
3900                 // and not the value of the variable).
3901                 //
3902                 public void EmitLoad (EmitContext ec)
3903                 {
3904                         ILGenerator ig = ec.ig;
3905                         int arg_idx = idx;
3906
3907                         if (!ec.IsStatic)
3908                                 arg_idx++;
3909
3910                         EmitLdArg (ig, arg_idx);
3911
3912                         //
3913                         // FIXME: Review for anonymous methods
3914                         //
3915                 }
3916                 
3917                 public override void Emit (EmitContext ec)
3918                 {
3919                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3920                                 ec.EmitParameter (name);
3921                                 return;
3922                         }
3923                         
3924                         Emit (ec, false);
3925                 }
3926                 
3927                 public void Emit (EmitContext ec, bool leave_copy)
3928                 {
3929                         ILGenerator ig = ec.ig;
3930                         int arg_idx = idx;
3931
3932                         if (!ec.IsStatic)
3933                                 arg_idx++;
3934
3935                         EmitLdArg (ig, arg_idx);
3936
3937                         if (is_ref) {
3938                                 if (prepared)
3939                                         ec.ig.Emit (OpCodes.Dup);
3940         
3941                                 //
3942                                 // If we are a reference, we loaded on the stack a pointer
3943                                 // Now lets load the real value
3944                                 //
3945                                 LoadFromPtr (ig, type);
3946                         }
3947                         
3948                         if (leave_copy) {
3949                                 ec.ig.Emit (OpCodes.Dup);
3950                                 
3951                                 if (is_ref) {
3952                                         temp = new LocalTemporary (ec, type);
3953                                         temp.Store (ec);
3954                                 }
3955                         }
3956                 }
3957                 
3958                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3959                 {
3960                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3961                                 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
3962                                 return;
3963                         }
3964
3965                         ILGenerator ig = ec.ig;
3966                         int arg_idx = idx;
3967                         
3968                         prepared = prepare_for_load;
3969                         
3970                         if (!ec.IsStatic)
3971                                 arg_idx++;
3972
3973                         if (is_ref && !prepared)
3974                                 EmitLdArg (ig, arg_idx);
3975                         
3976                         source.Emit (ec);
3977
3978                         if (leave_copy)
3979                                 ec.ig.Emit (OpCodes.Dup);
3980                         
3981                         if (is_ref) {
3982                                 if (leave_copy) {
3983                                         temp = new LocalTemporary (ec, type);
3984                                         temp.Store (ec);
3985                                 }
3986                                 
3987                                 StoreFromPtr (ig, type);
3988                                 
3989                                 if (temp != null)
3990                                         temp.Emit (ec);
3991                         } else {
3992                                 if (arg_idx <= 255)
3993                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3994                                 else
3995                                         ig.Emit (OpCodes.Starg, arg_idx);
3996                         }
3997                 }
3998
3999                 public void AddressOf (EmitContext ec, AddressOp mode)
4000                 {
4001                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4002                                 ec.EmitAddressOfParameter (name);
4003                                 return;
4004                         }
4005                         
4006                         int arg_idx = idx;
4007
4008                         if (!ec.IsStatic)
4009                                 arg_idx++;
4010
4011                         if (is_ref){
4012                                 if (arg_idx <= 255)
4013                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4014                                 else
4015                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4016                         } else {
4017                                 if (arg_idx <= 255)
4018                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4019                                 else
4020                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4021                         }
4022                 }
4023
4024         }
4025         
4026         /// <summary>
4027         ///   Used for arguments to New(), Invocation()
4028         /// </summary>
4029         public class Argument {
4030                 public enum AType : byte {
4031                         Expression,
4032                         Ref,
4033                         Out,
4034                         ArgList
4035                 };
4036
4037                 public readonly AType ArgType;
4038                 public Expression Expr;
4039                 
4040                 public Argument (Expression expr, AType type)
4041                 {
4042                         this.Expr = expr;
4043                         this.ArgType = type;
4044                 }
4045
4046                 public Argument (Expression expr)
4047                 {
4048                         this.Expr = expr;
4049                         this.ArgType = AType.Expression;
4050                 }
4051
4052                 public Type Type {
4053                         get {
4054                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4055                                         return TypeManager.GetReferenceType (Expr.Type);
4056                                 else
4057                                         return Expr.Type;
4058                         }
4059                 }
4060
4061                 public Parameter.Modifier GetParameterModifier ()
4062                 {
4063                         switch (ArgType) {
4064                         case AType.Out:
4065                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4066
4067                         case AType.Ref:
4068                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4069
4070                         default:
4071                                 return Parameter.Modifier.NONE;
4072                         }
4073                 }
4074
4075                 public static string FullDesc (Argument a)
4076                 {
4077                         if (a.ArgType == AType.ArgList)
4078                                 return "__arglist";
4079
4080                         return (a.ArgType == AType.Ref ? "ref " :
4081                                 (a.ArgType == AType.Out ? "out " : "")) +
4082                                 TypeManager.CSharpName (a.Expr.Type);
4083                 }
4084
4085                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4086                 {
4087                         // FIXME: csc doesn't report any error if you try to use `ref' or
4088                         //        `out' in a delegate creation expression.
4089                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4090                         if (Expr == null)
4091                                 return false;
4092
4093                         return true;
4094                 }
4095                 
4096                 public bool Resolve (EmitContext ec, Location loc)
4097                 {
4098                         if (ArgType == AType.Ref) {
4099                                 Expr = Expr.Resolve (ec);
4100                                 if (Expr == null)
4101                                         return false;
4102
4103                                 if (!ec.IsConstructor) {
4104                                         FieldExpr fe = Expr as FieldExpr;
4105                                         if (fe != null && fe.FieldInfo.IsInitOnly) {
4106                                                 if (fe.FieldInfo.IsStatic)
4107                                                         Report.Error (199, loc, "A static readonly field cannot be passed ref or out (except in a static constructor)");
4108                                                 else
4109                                                         Report.Error (192, loc, "A readonly field cannot be passed ref or out (except in a constructor)");
4110                                                 return false;
4111                                         }
4112                                 }
4113                                 Expr = Expr.ResolveLValue (ec, Expr);
4114                         } else if (ArgType == AType.Out)
4115                                 Expr = Expr.ResolveLValue (ec, EmptyExpression.Null);
4116                         else
4117                                 Expr = Expr.Resolve (ec);
4118
4119                         if (Expr == null)
4120                                 return false;
4121
4122                         if (ArgType == AType.Expression)
4123                                 return true;
4124                         else {
4125                                 //
4126                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4127                                 // This is only allowed for `this'
4128                                 //
4129                                 FieldExpr fe = Expr as FieldExpr;
4130                                 if (fe != null && !fe.IsStatic){
4131                                         Expression instance = fe.InstanceExpression;
4132
4133                                         if (instance.GetType () != typeof (This)){
4134                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4135                                                         Report.Error (197, loc,
4136                                                                       "Can not pass a type that derives from MarshalByRefObject with out or ref");
4137                                                         return false;
4138                                                 }
4139                                         }
4140                                 }
4141                         }
4142
4143                         if (Expr.eclass != ExprClass.Variable){
4144                                 //
4145                                 // We just probe to match the CSC output
4146                                 //
4147                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4148                                     Expr.eclass == ExprClass.IndexerAccess){
4149                                         Report.Error (
4150                                                 206, loc,
4151                                                 "A property or indexer can not be passed as an out or ref " +
4152                                                 "parameter");
4153                                 } else {
4154                                         Report.Error (
4155                                                 1510, loc,
4156                                                 "An lvalue is required as an argument to out or ref");
4157                                 }
4158                                 return false;
4159                         }
4160                                 
4161                         return true;
4162                 }
4163
4164                 public void Emit (EmitContext ec)
4165                 {
4166                         //
4167                         // Ref and Out parameters need to have their addresses taken.
4168                         //
4169                         // ParameterReferences might already be references, so we want
4170                         // to pass just the value
4171                         //
4172                         if (ArgType == AType.Ref || ArgType == AType.Out){
4173                                 AddressOp mode = AddressOp.Store;
4174
4175                                 if (ArgType == AType.Ref)
4176                                         mode |= AddressOp.Load;
4177                                 
4178                                 if (Expr is ParameterReference){
4179                                         ParameterReference pr = (ParameterReference) Expr;
4180
4181                                         if (pr.IsRef)
4182                                                 pr.EmitLoad (ec);
4183                                         else {
4184                                                 
4185                                                 pr.AddressOf (ec, mode);
4186                                         }
4187                                 } else {
4188                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
4189                                 }
4190                         } else
4191                                 Expr.Emit (ec);
4192                 }
4193         }
4194
4195         /// <summary>
4196         ///   Invocation of methods or delegates.
4197         /// </summary>
4198         public class Invocation : ExpressionStatement {
4199                 public readonly ArrayList Arguments;
4200
4201                 Expression expr;
4202                 MethodBase method = null;
4203                 
4204                 static Hashtable method_parameter_cache;
4205
4206                 static Invocation ()
4207                 {
4208                         method_parameter_cache = new PtrHashtable ();
4209                 }
4210                         
4211                 //
4212                 // arguments is an ArrayList, but we do not want to typecast,
4213                 // as it might be null.
4214                 //
4215                 // FIXME: only allow expr to be a method invocation or a
4216                 // delegate invocation (7.5.5)
4217                 //
4218                 public Invocation (Expression expr, ArrayList arguments, Location l)
4219                 {
4220                         this.expr = expr;
4221                         Arguments = arguments;
4222                         loc = l;
4223                 }
4224
4225                 public Expression Expr {
4226                         get {
4227                                 return expr;
4228                         }
4229                 }
4230
4231                 /// <summary>
4232                 ///   Returns the Parameters (a ParameterData interface) for the
4233                 ///   Method `mb'
4234                 /// </summary>
4235                 public static ParameterData GetParameterData (MethodBase mb)
4236                 {
4237                         object pd = method_parameter_cache [mb];
4238                         object ip;
4239                         
4240                         if (pd != null)
4241                                 return (ParameterData) pd;
4242
4243                         
4244                         ip = TypeManager.LookupParametersByBuilder (mb);
4245                         if (ip != null){
4246                                 method_parameter_cache [mb] = ip;
4247
4248                                 return (ParameterData) ip;
4249                         } else {
4250                                 ReflectionParameters rp = new ReflectionParameters (mb);
4251                                 method_parameter_cache [mb] = rp;
4252
4253                                 return (ParameterData) rp;
4254                         }
4255                 }
4256
4257                 /// <summary>
4258                 ///   Determines "better conversion" as specified in 7.4.2.3
4259                 ///
4260                 ///    Returns : p    if a->p is better,
4261                 ///              q    if a->q is better,
4262                 ///              null if neither is better
4263                 /// </summary>
4264                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4265                 {
4266                         Type argument_type = a.Type;
4267                         Expression argument_expr = a.Expr;
4268
4269                         if (argument_type == null)
4270                                 throw new Exception ("Expression of type " + a.Expr +
4271                                                      " does not resolve its type");
4272
4273                         if (p == null || q == null)
4274                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
4275
4276                         if (p == q)
4277                                 return null;
4278
4279                         if (argument_expr is NullLiteral) {
4280                                 //
4281                                 // If the argument is null and one of the types to compare is 'object' and
4282                                 // the other is a reference type, we prefer the other.
4283                                 //
4284                                 // This follows from the usual rules:
4285                                 //   * There is an implicit conversion from 'null' to type 'object'
4286                                 //   * There is an implicit conversion from 'null' to any reference type
4287                                 //   * There is an implicit conversion from any reference type to type 'object'
4288                                 //   * There is no implicit conversion from type 'object' to other reference types
4289                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
4290                                 //
4291                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is 'System.Null'.
4292                                 //         I think it used to be 'object' and thus needed a special case to avoid the
4293                                 //         immediately following two checks.
4294                                 //
4295                                 if (!p.IsValueType && q == TypeManager.object_type)
4296                                         return p;
4297                                 if (!q.IsValueType && p == TypeManager.object_type)
4298                                         return q;
4299                         }
4300                                 
4301                         if (argument_type == p)
4302                                 return p;
4303
4304                         if (argument_type == q)
4305                                 return q;
4306
4307                         Expression p_tmp = new EmptyExpression (p);
4308                         Expression q_tmp = new EmptyExpression (q);
4309
4310                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4311                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4312
4313                         if (p_to_q && !q_to_p)
4314                                 return p;
4315
4316                         if (q_to_p && !p_to_q)
4317                                 return q;
4318
4319                         if (p == TypeManager.sbyte_type)
4320                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4321                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4322                                         return p;
4323                         if (q == TypeManager.sbyte_type)
4324                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4325                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4326                                         return q;
4327
4328                         if (p == TypeManager.short_type)
4329                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4330                                     q == TypeManager.uint64_type)
4331                                         return p;
4332                         if (q == TypeManager.short_type)
4333                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4334                                     p == TypeManager.uint64_type)
4335                                         return q;
4336
4337                         if (p == TypeManager.int32_type)
4338                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4339                                         return p;
4340                         if (q == TypeManager.int32_type)
4341                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4342                                         return q;
4343
4344                         if (p == TypeManager.int64_type)
4345                                 if (q == TypeManager.uint64_type)
4346                                         return p;
4347                         if (q == TypeManager.int64_type)
4348                                 if (p == TypeManager.uint64_type)
4349                                         return q;
4350
4351                         return null;
4352                 }
4353                 
4354                 /// <summary>
4355                 ///   Determines "Better function" between candidate
4356                 ///   and the current best match
4357                 /// </summary>
4358                 /// <remarks>
4359                 ///    Returns an integer indicating :
4360                 ///     false if candidate ain't better
4361                 ///     true if candidate is better than the current best match
4362                 /// </remarks>
4363                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4364                                             MethodBase candidate, bool candidate_params,
4365                                             MethodBase best, bool best_params, Location loc)
4366                 {
4367                         ParameterData candidate_pd = GetParameterData (candidate);
4368                         ParameterData best_pd = GetParameterData (best);
4369                 
4370                         int cand_count = candidate_pd.Count;
4371                         
4372                         //
4373                         // If there is no best method, than this one
4374                         // is better, however, if we already found a
4375                         // best method, we cant tell. This happens
4376                         // if we have:
4377                         // 
4378                         //      interface IFoo {
4379                         //              void DoIt ();
4380                         //      }
4381                         //      
4382                         //      interface IBar {
4383                         //              void DoIt ();
4384                         //      }
4385                         //      
4386                         //      interface IFooBar : IFoo, IBar {}
4387                         //
4388                         // We cant tell if IFoo.DoIt is better than IBar.DoIt
4389                         //
4390                         // However, we have to consider that
4391                         // Trim (); is better than Trim (params char[] chars);
4392                         //
4393                         if (cand_count == 0 && argument_count == 0)
4394                                 return !candidate_params && best_params;
4395
4396                         if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
4397                             (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
4398                                 if (cand_count != argument_count)
4399                                         return false;
4400
4401                         bool better_at_least_one = false;
4402                         for (int j = 0; j < argument_count; ++j) {
4403                                 Argument a = (Argument) args [j];
4404
4405                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4406                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4407
4408                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4409                                         if (candidate_params)
4410                                                 ct = TypeManager.GetElementType (ct);
4411
4412                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4413                                         if (best_params)
4414                                                 bt = TypeManager.GetElementType (bt);
4415
4416                                 Type better = BetterConversion (ec, a, ct, bt, loc);
4417
4418                                 // for each argument, the conversion to 'ct' should be no worse than 
4419                                 // the conversion to 'bt'.
4420                                 if (better == bt)
4421                                         return false;
4422
4423                                 // for at least one argument, the conversion to 'ct' should be better than 
4424                                 // the conversion to 'bt'.
4425                                 if (better == ct)
4426                                         better_at_least_one = true;
4427                         }
4428
4429                         //
4430                         // If a method (in the normal form) with the
4431                         // same signature as the expanded form of the
4432                         // current best params method already exists,
4433                         // the expanded form is not applicable so we
4434                         // force it to select the candidate
4435                         //
4436                         if (!candidate_params && best_params && cand_count == argument_count)
4437                                 return true;
4438
4439                         return better_at_least_one;
4440                 }
4441
4442                 public static string FullMethodDesc (MethodBase mb)
4443                 {
4444                         string ret_type = "";
4445
4446                         if (mb == null)
4447                                 return "";
4448
4449                         if (mb is MethodInfo)
4450                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4451                         
4452                         StringBuilder sb = new StringBuilder (ret_type);
4453                         sb.Append (" ");
4454                         sb.Append (mb.ReflectedType.ToString ());
4455                         sb.Append (".");
4456                         sb.Append (mb.Name);
4457                         
4458                         ParameterData pd = GetParameterData (mb);
4459
4460                         int count = pd.Count;
4461                         sb.Append (" (");
4462                         
4463                         for (int i = count; i > 0; ) {
4464                                 i--;
4465
4466                                 sb.Append (pd.ParameterDesc (count - i - 1));
4467                                 if (i != 0)
4468                                         sb.Append (", ");
4469                         }
4470                         
4471                         sb.Append (")");
4472                         return sb.ToString ();
4473                 }
4474
4475                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4476                 {
4477                         MemberInfo [] miset;
4478                         MethodGroupExpr union;
4479
4480                         if (mg1 == null) {
4481                                 if (mg2 == null)
4482                                         return null;
4483                                 return (MethodGroupExpr) mg2;
4484                         } else {
4485                                 if (mg2 == null)
4486                                         return (MethodGroupExpr) mg1;
4487                         }
4488                         
4489                         MethodGroupExpr left_set = null, right_set = null;
4490                         int length1 = 0, length2 = 0;
4491                         
4492                         left_set = (MethodGroupExpr) mg1;
4493                         length1 = left_set.Methods.Length;
4494                         
4495                         right_set = (MethodGroupExpr) mg2;
4496                         length2 = right_set.Methods.Length;
4497                         
4498                         ArrayList common = new ArrayList ();
4499
4500                         foreach (MethodBase r in right_set.Methods){
4501                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4502                                         common.Add (r);
4503                         }
4504
4505                         miset = new MemberInfo [length1 + length2 - common.Count];
4506                         left_set.Methods.CopyTo (miset, 0);
4507                         
4508                         int k = length1;
4509
4510                         foreach (MethodBase r in right_set.Methods) {
4511                                 if (!common.Contains (r))
4512                                         miset [k++] = r;
4513                         }
4514
4515                         union = new MethodGroupExpr (miset, loc);
4516                         
4517                         return union;
4518                 }
4519
4520                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4521                                                       ArrayList arguments, int arg_count,
4522                                                       ref MethodBase candidate)
4523                 {
4524                         return IsParamsMethodApplicable (
4525                                 ec, me, arguments, arg_count, false, ref candidate) ||
4526                                 IsParamsMethodApplicable (
4527                                         ec, me, arguments, arg_count, true, ref candidate);
4528
4529
4530                 }
4531
4532                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4533                                                       ArrayList arguments, int arg_count,
4534                                                       bool do_varargs, ref MethodBase candidate)
4535                 {
4536                         return IsParamsMethodApplicable (
4537                                 ec, arguments, arg_count, candidate, do_varargs);
4538                 }
4539
4540                 /// <summary>
4541                 ///   Determines if the candidate method, if a params method, is applicable
4542                 ///   in its expanded form to the given set of arguments
4543                 /// </summary>
4544                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4545                                                       int arg_count, MethodBase candidate,
4546                                                       bool do_varargs)
4547                 {
4548                         ParameterData pd = GetParameterData (candidate);
4549
4550                         int pd_count = pd.Count;
4551                         if (pd_count == 0)
4552                                 return false;
4553
4554                         int count = pd_count - 1;
4555                         if (do_varargs) {
4556                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4557                                         return false;
4558                                 if (pd_count != arg_count)
4559                                         return false;
4560                         } else {
4561                                 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4562                                         return false;
4563                         }
4564                         
4565                         if (count > arg_count)
4566                                 return false;
4567                         
4568                         if (pd_count == 1 && arg_count == 0)
4569                                 return true;
4570
4571                         //
4572                         // If we have come this far, the case which
4573                         // remains is when the number of parameters is
4574                         // less than or equal to the argument count.
4575                         //
4576                         for (int i = 0; i < count; ++i) {
4577
4578                                 Argument a = (Argument) arguments [i];
4579
4580                                 Parameter.Modifier a_mod = a.GetParameterModifier () & 
4581                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4582                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4583                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4584
4585                                 if (a_mod == p_mod) {
4586
4587                                         if (a_mod == Parameter.Modifier.NONE)
4588                                                 if (!Convert.ImplicitConversionExists (ec,
4589                                                                                        a.Expr,
4590                                                                                        pd.ParameterType (i)))
4591                                                         return false;
4592                                                                                 
4593                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4594                                                 Type pt = pd.ParameterType (i);
4595
4596                                                 if (!pt.IsByRef)
4597                                                         pt = TypeManager.GetReferenceType (pt);
4598                                                 
4599                                                 if (pt != a.Type)
4600                                                         return false;
4601                                         }
4602                                 } else
4603                                         return false;
4604                                 
4605                         }
4606
4607                         if (do_varargs) {
4608                                 Argument a = (Argument) arguments [count];
4609                                 if (!(a.Expr is Arglist))
4610                                         return false;
4611
4612                                 return true;
4613                         }
4614
4615                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4616
4617                         for (int i = pd_count - 1; i < arg_count; i++) {
4618                                 Argument a = (Argument) arguments [i];
4619
4620                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4621                                         return false;
4622                         }
4623                         
4624                         return true;
4625                 }
4626
4627                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4628                                           ArrayList arguments, int arg_count,
4629                                           ref MethodBase candidate)
4630                 {
4631                         return IsApplicable (ec, arguments, arg_count, candidate);
4632                 }
4633
4634                 /// <summary>
4635                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4636                 ///   to the given set of arguments
4637                 /// </summary>
4638                 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4639                                           MethodBase candidate)
4640                 {
4641                         ParameterData pd = GetParameterData (candidate);
4642
4643                         if (arg_count != pd.Count)
4644                                 return false;
4645
4646                         for (int i = arg_count; i > 0; ) {
4647                                 i--;
4648
4649                                 Argument a = (Argument) arguments [i];
4650
4651                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4652                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4653                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4654                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4655
4656
4657                                 if (a_mod == p_mod ||
4658                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4659                                         if (a_mod == Parameter.Modifier.NONE) {
4660                                                 if (!Convert.ImplicitConversionExists (ec,
4661                                                                                        a.Expr,
4662                                                                                        pd.ParameterType (i)))
4663                                                         return false;
4664                                         }
4665                                         
4666                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4667                                                 Type pt = pd.ParameterType (i);
4668
4669                                                 if (!pt.IsByRef)
4670                                                         pt = TypeManager.GetReferenceType (pt);
4671                                                 
4672                                                 if (pt != a.Type)
4673                                                         return false;
4674                                         }
4675                                 } else
4676                                         return false;
4677                         }
4678
4679                         return true;
4680                 }
4681
4682                 static private bool IsAncestralType (Type first_type, Type second_type)
4683                 {
4684                         return first_type != second_type &&
4685                                 (second_type.IsSubclassOf (first_type) ||
4686                                  TypeManager.ImplementsInterface (second_type, first_type));
4687                 }
4688                 
4689                 /// <summary>
4690                 ///   Find the Applicable Function Members (7.4.2.1)
4691                 ///
4692                 ///   me: Method Group expression with the members to select.
4693                 ///       it might contain constructors or methods (or anything
4694                 ///       that maps to a method).
4695                 ///
4696                 ///   Arguments: ArrayList containing resolved Argument objects.
4697                 ///
4698                 ///   loc: The location if we want an error to be reported, or a Null
4699                 ///        location for "probing" purposes.
4700                 ///
4701                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4702                 ///            that is the best match of me on Arguments.
4703                 ///
4704                 /// </summary>
4705                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4706                                                           ArrayList Arguments, bool may_fail, 
4707                                                           Location loc)
4708                 {
4709                         MethodBase method = null;
4710                         bool method_params = false;
4711                         Type applicable_type = null;
4712                         int arg_count = 0;
4713                         ArrayList candidates = new ArrayList ();
4714
4715                         //
4716                         // Used to keep a map between the candidate
4717                         // and whether it is being considered in its
4718                         // normal or expanded form
4719                         //
4720                         // false is normal form, true is expanded form
4721                         //
4722                         Hashtable candidate_to_form = null;
4723
4724                         if (Arguments != null)
4725                                 arg_count = Arguments.Count;
4726
4727                         if ((me.Name == "Invoke") &&
4728                             TypeManager.IsDelegateType (me.DeclaringType)) {
4729                                 Error_InvokeOnDelegate (loc);
4730                                 return null;
4731                         }
4732
4733                         MethodBase[] methods = me.Methods;
4734
4735                         //
4736                         // First we construct the set of applicable methods
4737                         //
4738                         bool is_sorted = true;
4739                         for (int i = 0; i < methods.Length; i++){
4740                                 Type decl_type = methods [i].DeclaringType;
4741
4742                                 //
4743                                 // If we have already found an applicable method
4744                                 // we eliminate all base types (Section 14.5.5.1)
4745                                 //
4746                                 if ((applicable_type != null) &&
4747                                     IsAncestralType (decl_type, applicable_type))
4748                                         continue;
4749
4750                                 //
4751                                 // Check if candidate is applicable (section 14.4.2.1)
4752                                 //   Is candidate applicable in normal form?
4753                                 //
4754                                 bool is_applicable = IsApplicable (
4755                                         ec, me, Arguments, arg_count, ref methods [i]);
4756
4757                                 if (!is_applicable &&
4758                                     (IsParamsMethodApplicable (
4759                                             ec, me, Arguments, arg_count, ref methods [i]))) {
4760                                         MethodBase candidate = methods [i];
4761                                         if (candidate_to_form == null)
4762                                                 candidate_to_form = new PtrHashtable ();
4763                                         candidate_to_form [candidate] = candidate;
4764                                         // Candidate is applicable in expanded form
4765                                         is_applicable = true;
4766                                 }
4767
4768                                 if (!is_applicable)
4769                                         continue;
4770
4771                                 candidates.Add (methods [i]);
4772
4773                                 if (applicable_type == null)
4774                                         applicable_type = decl_type;
4775                                 else if (applicable_type != decl_type) {
4776                                         is_sorted = false;
4777                                         if (IsAncestralType (applicable_type, decl_type))
4778                                                 applicable_type = decl_type;
4779                                 }
4780                         }
4781
4782                         int candidate_top = candidates.Count;
4783
4784                         if (candidate_top == 0) {
4785                                 //
4786                                 // Okay so we have failed to find anything so we
4787                                 // return by providing info about the closest match
4788                                 //
4789                                 for (int i = 0; i < methods.Length; ++i) {
4790                                         MethodBase c = (MethodBase) methods [i];
4791                                         ParameterData pd = GetParameterData (c);
4792
4793                                         if (pd.Count != arg_count)
4794                                                 continue;
4795
4796                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4797                                                                c, false, null, may_fail, loc);
4798                                         break;
4799                                 }
4800
4801                                 if (!may_fail) {
4802                                         string report_name = me.Name;
4803                                         if (report_name == ".ctor")
4804                                                 report_name = me.DeclaringType.ToString ();
4805                                         
4806                                         Error_WrongNumArguments (
4807                                                 loc, report_name, arg_count);
4808                                         return null;
4809                                 }
4810                                 
4811                                 return null;
4812                         }
4813
4814                         if (!is_sorted) {
4815                                 //
4816                                 // At this point, applicable_type is _one_ of the most derived types
4817                                 // in the set of types containing the methods in this MethodGroup.
4818                                 // Filter the candidates so that they only contain methods from the
4819                                 // most derived types.
4820                                 //
4821
4822                                 int finalized = 0; // Number of finalized candidates
4823
4824                                 do {
4825                                         // Invariant: applicable_type is a most derived type
4826
4827                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4828                                         // eliminating all it's base types.  At the same time, we'll also move
4829                                         // every unrelated type to the end of the array, and pick the next
4830                                         // 'applicable_type'.
4831
4832                                         Type next_applicable_type = null;
4833                                         int j = finalized; // where to put the next finalized candidate
4834                                         int k = finalized; // where to put the next undiscarded candidate
4835                                         for (int i = finalized; i < candidate_top; ++i) {
4836                                                 Type decl_type = ((MethodBase) candidates[i]).DeclaringType;
4837
4838                                                 if (decl_type == applicable_type) {
4839                                                         candidates[k++] = candidates[j];
4840                                                         candidates[j++] = candidates[i];
4841                                                         continue;
4842                                                 }
4843
4844                                                 if (IsAncestralType (decl_type, applicable_type))
4845                                                         continue;
4846
4847                                                 if (next_applicable_type != null &&
4848                                                     IsAncestralType (decl_type, next_applicable_type))
4849                                                         continue;
4850
4851                                                 candidates[k++] = candidates[i];
4852
4853                                                 if (next_applicable_type == null ||
4854                                                     IsAncestralType (next_applicable_type, decl_type))
4855                                                         next_applicable_type = decl_type;
4856                                         }
4857
4858                                         applicable_type = next_applicable_type;
4859                                         finalized = j;
4860                                         candidate_top = k;
4861                                 } while (applicable_type != null);
4862                         }
4863
4864                         //
4865                         // Now we actually find the best method
4866                         //
4867
4868                         method = (MethodBase) candidates[0];
4869                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4870                         for (int ix = 1; ix < candidate_top; ix++){
4871                                 MethodBase candidate = (MethodBase) candidates [ix];
4872                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4873                                 
4874                                 if (BetterFunction (ec, Arguments, arg_count, 
4875                                                     candidate, cand_params,
4876                                                     method, method_params, loc)) {
4877                                         method = candidate;
4878                                         method_params = cand_params;
4879                                 }
4880                         }
4881
4882                         //
4883                         // Now check that there are no ambiguities i.e the selected method
4884                         // should be better than all the others
4885                         //
4886                         bool ambiguous = false;
4887                         for (int ix = 0; ix < candidate_top; ix++){
4888                                 MethodBase candidate = (MethodBase) candidates [ix];
4889
4890                                 if (candidate == method)
4891                                         continue;
4892
4893                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4894                                 if (!BetterFunction (ec, Arguments, arg_count,
4895                                                      method, method_params,
4896                                                      candidate, cand_params,
4897                                                      loc)) {
4898                                         Report.SymbolRelatedToPreviousError (candidate);
4899                                         ambiguous = true;
4900                                 }
4901                         }
4902
4903                         if (ambiguous) {
4904                                 Report.SymbolRelatedToPreviousError (method);
4905                                 Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts");
4906                                 return null;
4907                         }
4908
4909
4910                         //
4911                         // And now check if the arguments are all
4912                         // compatible, perform conversions if
4913                         // necessary etc. and return if everything is
4914                         // all right
4915                         //
4916                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4917                                                     method_params, null, may_fail, loc))
4918                                 return null;
4919
4920                         return method;
4921                 }
4922
4923                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4924                 {
4925                         Report.Error (1501, loc,
4926                                       "No overload for method `" + name + "' takes `" +
4927                                       arg_count + "' arguments");
4928                 }
4929
4930                 static void Error_InvokeOnDelegate (Location loc)
4931                 {
4932                         Report.Error (1533, loc,
4933                                       "Invoke cannot be called directly on a delegate");
4934                 }
4935                         
4936                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4937                                                     Type delegate_type, string arg_sig, string par_desc)
4938                 {
4939                         if (delegate_type == null) 
4940                                 Report.Error (1502, loc,
4941                                               "The best overloaded match for method '" +
4942                                               FullMethodDesc (method) +
4943                                               "' has some invalid arguments");
4944                         else
4945                                 Report.Error (1594, loc,
4946                                               "Delegate '" + delegate_type.ToString () +
4947                                               "' has some invalid arguments.");
4948                         Report.Error (1503, loc,
4949                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4950                                                      idx, arg_sig, par_desc));
4951                 }
4952                 
4953                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4954                                                           int arg_count, MethodBase method, 
4955                                                           bool chose_params_expanded,
4956                                                           Type delegate_type, bool may_fail,
4957                                                           Location loc)
4958                 {
4959                         ParameterData pd = GetParameterData (method);
4960                         int pd_count = pd.Count;
4961
4962                         for (int j = 0; j < arg_count; j++) {
4963                                 Argument a = (Argument) Arguments [j];
4964                                 Expression a_expr = a.Expr;
4965                                 Type parameter_type = pd.ParameterType (j);
4966                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4967                                 
4968                                 if (pm == Parameter.Modifier.PARAMS){
4969                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4970                                                 if (!may_fail)
4971                                                         Error_InvalidArguments (
4972                                                                 loc, j, method, delegate_type,
4973                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4974                                                 return false;
4975                                         }
4976
4977                                         if (chose_params_expanded)
4978                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4979                                 } else if (pm == Parameter.Modifier.ARGLIST){
4980                                         continue;
4981                                 } else {
4982                                         //
4983                                         // Check modifiers
4984                                         //
4985                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4986                                                 if (!may_fail)
4987                                                         Error_InvalidArguments (
4988                                                                 loc, j, method, delegate_type,
4989                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4990                                                 return false;
4991                                         }
4992                                 }
4993
4994                                 //
4995                                 // Check Type
4996                                 //
4997                                 if (!a.Type.Equals (parameter_type)){
4998                                         Expression conv;
4999                                         
5000                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5001
5002                                         if (conv == null) {
5003                                                 if (!may_fail)
5004                                                         Error_InvalidArguments (
5005                                                                 loc, j, method, delegate_type,
5006                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5007                                                 return false;
5008                                         }
5009                                         
5010                                         //
5011                                         // Update the argument with the implicit conversion
5012                                         //
5013                                         if (a_expr != conv)
5014                                                 a.Expr = conv;
5015                                 }
5016
5017                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
5018                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5019                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5020                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5021                                 
5022                                 if (a_mod != p_mod &&
5023                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5024                                         if (!may_fail) {
5025                                                 Report.Error (1502, loc,
5026                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
5027                                                        "' has some invalid arguments");
5028                                                 Report.Error (1503, loc,
5029                                                        "Argument " + (j+1) +
5030                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
5031                                                        + "' to '" + pd.ParameterDesc (j) + "'");
5032                                         }
5033                                         
5034                                         return false;
5035                                 }
5036                         }
5037
5038                         return true;
5039                 }
5040
5041                 public override Expression DoResolve (EmitContext ec)
5042                 {
5043                         //
5044                         // First, resolve the expression that is used to
5045                         // trigger the invocation
5046                         //
5047                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5048                         if (expr == null)
5049                                 return null;
5050
5051                         if (!(expr is MethodGroupExpr)) {
5052                                 Type expr_type = expr.Type;
5053
5054                                 if (expr_type != null){
5055                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5056                                         if (IsDelegate)
5057                                                 return (new DelegateInvocation (
5058                                                         this.expr, Arguments, loc)).Resolve (ec);
5059                                 }
5060                         }
5061
5062                         if (!(expr is MethodGroupExpr)){
5063                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5064                                 return null;
5065                         }
5066
5067                         //
5068                         // Next, evaluate all the expressions in the argument list
5069                         //
5070                         if (Arguments != null){
5071                                 foreach (Argument a in Arguments){
5072                                         if (!a.Resolve (ec, loc))
5073                                                 return null;
5074                                 }
5075                         }
5076
5077                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5078                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5079
5080                         if (method == null)
5081                                 return null;
5082
5083                         MethodInfo mi = method as MethodInfo;
5084                         if (mi != null) {
5085                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5086                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5087                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5088                                         return null;
5089                                 }
5090
5091                                 Expression iexpr = mg.InstanceExpression;
5092                                 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5093                                         if (mg.IdenticalTypeName)
5094                                                 mg.InstanceExpression = null;
5095                                         else {
5096                                                 MemberAccess.error176 (loc, mi.Name);
5097                                                 return null;
5098                                         }
5099                                 }
5100                         }
5101
5102                         if (type.IsPointer){
5103                                 if (!ec.InUnsafe){
5104                                         UnsafeError (loc);
5105                                         return null;
5106                                 }
5107                         }
5108                         
5109                         //
5110                         // Only base will allow this invocation to happen.
5111                         //
5112                         if (mg.IsBase && method.IsAbstract){
5113                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5114                                               FullMethodDesc (method));
5115                                 return null;
5116                         }
5117
5118                         if (method.Name == "Finalize" && Arguments == null) {
5119                                 if (mg.IsBase)
5120                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5121                                 else
5122                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5123                                 return null;
5124                         }
5125
5126                         if ((method.Attributes & MethodAttributes.SpecialName) != 0) {
5127                                 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5128                                         Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor");
5129                                         return null;
5130                                 }
5131                         }
5132
5133                         eclass = ExprClass.Value;
5134                         return this;
5135                 }
5136
5137                 // <summary>
5138                 //   Emits the list of arguments as an array
5139                 // </summary>
5140                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5141                 {
5142                         ILGenerator ig = ec.ig;
5143                         int count = arguments.Count - idx;
5144                         Argument a = (Argument) arguments [idx];
5145                         Type t = a.Expr.Type;
5146                         
5147                         IntConstant.EmitInt (ig, count);
5148                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5149
5150                         int top = arguments.Count;
5151                         for (int j = idx; j < top; j++){
5152                                 a = (Argument) arguments [j];
5153                                 
5154                                 ig.Emit (OpCodes.Dup);
5155                                 IntConstant.EmitInt (ig, j - idx);
5156
5157                                 bool is_stobj;
5158                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
5159                                 if (is_stobj)
5160                                         ig.Emit (OpCodes.Ldelema, t);
5161
5162                                 a.Emit (ec);
5163
5164                                 if (is_stobj)
5165                                         ig.Emit (OpCodes.Stobj, t);
5166                                 else
5167                                         ig.Emit (op);
5168                         }
5169                 }
5170                 
5171                 /// <summary>
5172                 ///   Emits a list of resolved Arguments that are in the arguments
5173                 ///   ArrayList.
5174                 /// 
5175                 ///   The MethodBase argument might be null if the
5176                 ///   emission of the arguments is known not to contain
5177                 ///   a `params' field (for example in constructors or other routines
5178                 ///   that keep their arguments in this structure)
5179                 ///   
5180                 ///   if `dup_args' is true, a copy of the arguments will be left
5181                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5182                 ///   which will be duplicated before any other args. Only EmitCall
5183                 ///   should be using this interface.
5184                 /// </summary>
5185                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5186                 {
5187                         ParameterData pd;
5188                         if (mb != null)
5189                                 pd = GetParameterData (mb);
5190                         else
5191                                 pd = null;
5192                         
5193                         LocalTemporary [] temps = null;
5194                         
5195                         if (dup_args)
5196                                 temps = new LocalTemporary [arguments.Count];
5197
5198                         //
5199                         // If we are calling a params method with no arguments, special case it
5200                         //
5201                         if (arguments == null){
5202                                 if (pd != null && pd.Count > 0 &&
5203                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5204                                         ILGenerator ig = ec.ig;
5205
5206                                         IntConstant.EmitInt (ig, 0);
5207                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5208                                 }
5209
5210                                 return;
5211                         }
5212
5213                         int top = arguments.Count;
5214
5215                         for (int i = 0; i < top; i++){
5216                                 Argument a = (Argument) arguments [i];
5217
5218                                 if (pd != null){
5219                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5220                                                 //
5221                                                 // Special case if we are passing the same data as the
5222                                                 // params argument, do not put it in an array.
5223                                                 //
5224                                                 if (pd.ParameterType (i) == a.Type)
5225                                                         a.Emit (ec);
5226                                                 else
5227                                                         EmitParams (ec, i, arguments);
5228                                                 return;
5229                                         }
5230                                 }
5231                                             
5232                                 a.Emit (ec);
5233                                 if (dup_args) {
5234                                         ec.ig.Emit (OpCodes.Dup);
5235                                         (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5236                                 }
5237                         }
5238                         
5239                         if (dup_args) {
5240                                 if (this_arg != null)
5241                                         this_arg.Emit (ec);
5242                                 
5243                                 for (int i = 0; i < top; i ++)
5244                                         temps [i].Emit (ec);
5245                         }
5246
5247                         if (pd != null && pd.Count > top &&
5248                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5249                                 ILGenerator ig = ec.ig;
5250
5251                                 IntConstant.EmitInt (ig, 0);
5252                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5253                         }
5254                 }
5255
5256                 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5257                                                ArrayList arguments)
5258                 {
5259                         ParameterData pd = GetParameterData (mb);
5260
5261                         if (arguments == null)
5262                                 return new Type [0];
5263
5264                         Argument a = (Argument) arguments [pd.Count - 1];
5265                         Arglist list = (Arglist) a.Expr;
5266
5267                         return list.ArgumentTypes;
5268                 }
5269
5270                 /// <summary>
5271                 /// This checks the ConditionalAttribute on the method 
5272                 /// </summary>
5273                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5274                 {
5275                         if (method.IsConstructor)
5276                                 return false;
5277
5278                         IMethodData md = TypeManager.GetMethod (method);
5279                         if (md != null)
5280                                 return md.IsExcluded (ec);
5281
5282                         // For some methods (generated by delegate class) GetMethod returns null
5283                         // because they are not included in builder_to_method table
5284                         if (method.DeclaringType is TypeBuilder)
5285                                 return false;
5286
5287                         return AttributeTester.IsConditionalMethodExcluded (method);
5288                 }
5289
5290                 /// <remarks>
5291                 ///   is_base tells whether we want to force the use of the `call'
5292                 ///   opcode instead of using callvirt.  Call is required to call
5293                 ///   a specific method, while callvirt will always use the most
5294                 ///   recent method in the vtable.
5295                 ///
5296                 ///   is_static tells whether this is an invocation on a static method
5297                 ///
5298                 ///   instance_expr is an expression that represents the instance
5299                 ///   it must be non-null if is_static is false.
5300                 ///
5301                 ///   method is the method to invoke.
5302                 ///
5303                 ///   Arguments is the list of arguments to pass to the method or constructor.
5304                 /// </remarks>
5305                 public static void EmitCall (EmitContext ec, bool is_base,
5306                                              bool is_static, Expression instance_expr,
5307                                              MethodBase method, ArrayList Arguments, Location loc)
5308                 {
5309                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5310                 }
5311                 
5312                 // `dup_args' leaves an extra copy of the arguments on the stack
5313                 // `omit_args' does not leave any arguments at all.
5314                 // So, basically, you could make one call with `dup_args' set to true,
5315                 // and then another with `omit_args' set to true, and the two calls
5316                 // would have the same set of arguments. However, each argument would
5317                 // only have been evaluated once.
5318                 public static void EmitCall (EmitContext ec, bool is_base,
5319                                              bool is_static, Expression instance_expr,
5320                                              MethodBase method, ArrayList Arguments, Location loc,
5321                                              bool dup_args, bool omit_args)
5322                 {
5323                         ILGenerator ig = ec.ig;
5324                         bool struct_call = false;
5325                         bool this_call = false;
5326                         LocalTemporary this_arg = null;
5327
5328                         Type decl_type = method.DeclaringType;
5329
5330                         if (!RootContext.StdLib) {
5331                                 // Replace any calls to the system's System.Array type with calls to
5332                                 // the newly created one.
5333                                 if (method == TypeManager.system_int_array_get_length)
5334                                         method = TypeManager.int_array_get_length;
5335                                 else if (method == TypeManager.system_int_array_get_rank)
5336                                         method = TypeManager.int_array_get_rank;
5337                                 else if (method == TypeManager.system_object_array_clone)
5338                                         method = TypeManager.object_array_clone;
5339                                 else if (method == TypeManager.system_int_array_get_length_int)
5340                                         method = TypeManager.int_array_get_length_int;
5341                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5342                                         method = TypeManager.int_array_get_lower_bound_int;
5343                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5344                                         method = TypeManager.int_array_get_upper_bound_int;
5345                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5346                                         method = TypeManager.void_array_copyto_array_int;
5347                         }
5348
5349                         if (ec.TestObsoleteMethodUsage) {
5350                                 //
5351                                 // This checks ObsoleteAttribute on the method and on the declaring type
5352                                 //
5353                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5354                                 if (oa != null)
5355                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5356
5357
5358                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5359                                 if (oa != null) {
5360                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5361                                 }
5362                         }
5363
5364                         if (IsMethodExcluded (method, ec))
5365                 return; 
5366                         
5367                         if (!is_static){
5368                                 this_call = instance_expr == null;
5369                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5370                                         struct_call = true;
5371                                 
5372                                 //
5373                                 // If this is ourselves, push "this"
5374                                 //
5375                                 if (!omit_args) {
5376                                 Type t = null;
5377                                 if (this_call) {
5378                                         ig.Emit (OpCodes.Ldarg_0);
5379                                         t = decl_type;
5380                                 } else {
5381                                         //
5382                                         // Push the instance expression
5383                                         //
5384                                         if (instance_expr.Type.IsValueType) {
5385                                                 //
5386                                                 // Special case: calls to a function declared in a 
5387                                                 // reference-type with a value-type argument need
5388                                                 // to have their value boxed.
5389                                                 if (decl_type.IsValueType) {
5390                                                         //
5391                                                         // If the expression implements IMemoryLocation, then
5392                                                         // we can optimize and use AddressOf on the
5393                                                         // return.
5394                                                         //
5395                                                         // If not we have to use some temporary storage for
5396                                                         // it.
5397                                                         if (instance_expr is IMemoryLocation) {
5398                                                                 ((IMemoryLocation)instance_expr).
5399                                                                         AddressOf (ec, AddressOp.LoadStore);
5400                                                         } else {
5401                                                                 LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type);
5402                                                                 instance_expr.Emit (ec);
5403                                                                 temp.Store (ec);
5404                                                                 temp.AddressOf (ec, AddressOp.Load);
5405                                                         }
5406                                                         
5407                                                         // avoid the overhead of doing this all the time.
5408                                                         if (dup_args)
5409                                                                 t = TypeManager.GetReferenceType (instance_expr.Type);
5410                                                 } else {
5411                                                         instance_expr.Emit (ec);
5412                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5413                                                         t = TypeManager.object_type;
5414                                                 } 
5415                                         } else {
5416                                                 instance_expr.Emit (ec);
5417                                                 t = instance_expr.Type;
5418                                         }
5419                                 }
5420                                 
5421                                 if (dup_args) {
5422                                         this_arg = new LocalTemporary (ec, t);
5423                                         ig.Emit (OpCodes.Dup);
5424                                         this_arg.Store (ec);
5425                                 }
5426                                 }
5427                         }
5428
5429                         if (!omit_args)
5430                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5431
5432                         OpCode call_op;
5433                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5434                                 call_op = OpCodes.Call;
5435                         else
5436                                 call_op = OpCodes.Callvirt;
5437
5438                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5439                                 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5440                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5441                                 return;
5442                         }
5443
5444                         //
5445                         // If you have:
5446                         // this.DoFoo ();
5447                         // and DoFoo is not virtual, you can omit the callvirt,
5448                         // because you don't need the null checking behavior.
5449                         //
5450                         if (method is MethodInfo)
5451                                 ig.Emit (call_op, (MethodInfo) method);
5452                         else
5453                                 ig.Emit (call_op, (ConstructorInfo) method);
5454                 }
5455                 
5456                 public override void Emit (EmitContext ec)
5457                 {
5458                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5459
5460                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5461                 }
5462                 
5463                 public override void EmitStatement (EmitContext ec)
5464                 {
5465                         Emit (ec);
5466
5467                         // 
5468                         // Pop the return value if there is one
5469                         //
5470                         if (method is MethodInfo){
5471                                 Type ret = ((MethodInfo)method).ReturnType;
5472                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5473                                         ec.ig.Emit (OpCodes.Pop);
5474                         }
5475                 }
5476         }
5477
5478         public class InvocationOrCast : ExpressionStatement
5479         {
5480                 Expression expr;
5481                 Expression argument;
5482
5483                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5484                 {
5485                         this.expr = expr;
5486                         this.argument = argument;
5487                         this.loc = loc;
5488                 }
5489
5490                 public override Expression DoResolve (EmitContext ec)
5491                 {
5492                         //
5493                         // First try to resolve it as a cast.
5494                         //
5495                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5496                         if (te != null) {
5497                                 Cast cast = new Cast (te, argument, loc);
5498                                 return cast.Resolve (ec);
5499                         }
5500
5501                         //
5502                         // This can either be a type or a delegate invocation.
5503                         // Let's just resolve it and see what we'll get.
5504                         //
5505                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5506                         if (expr == null)
5507                                 return null;
5508
5509                         //
5510                         // Ok, so it's a Cast.
5511                         //
5512                         if (expr.eclass == ExprClass.Type) {
5513                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5514                                 return cast.Resolve (ec);
5515                         }
5516
5517                         //
5518                         // It's a delegate invocation.
5519                         //
5520                         if (!TypeManager.IsDelegateType (expr.Type)) {
5521                                 Error (149, "Method name expected");
5522                                 return null;
5523                         }
5524
5525                         ArrayList args = new ArrayList ();
5526                         args.Add (new Argument (argument, Argument.AType.Expression));
5527                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5528                         return invocation.Resolve (ec);
5529                 }
5530
5531                 void error201 ()
5532                 {
5533                         Error (201, "Only assignment, call, increment, decrement and new object " +
5534                                "expressions can be used as a statement");
5535                 }
5536
5537                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5538                 {
5539                         //
5540                         // First try to resolve it as a cast.
5541                         //
5542                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5543                         if (te != null) {
5544                                 error201 ();
5545                                 return null;
5546                         }
5547
5548                         //
5549                         // This can either be a type or a delegate invocation.
5550                         // Let's just resolve it and see what we'll get.
5551                         //
5552                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5553                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5554                                 error201 ();
5555                                 return null;
5556                         }
5557
5558                         //
5559                         // It's a delegate invocation.
5560                         //
5561                         if (!TypeManager.IsDelegateType (expr.Type)) {
5562                                 Error (149, "Method name expected");
5563                                 return null;
5564                         }
5565
5566                         ArrayList args = new ArrayList ();
5567                         args.Add (new Argument (argument, Argument.AType.Expression));
5568                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5569                         return invocation.ResolveStatement (ec);
5570                 }
5571
5572                 public override void Emit (EmitContext ec)
5573                 {
5574                         throw new Exception ("Cannot happen");
5575                 }
5576
5577                 public override void EmitStatement (EmitContext ec)
5578                 {
5579                         throw new Exception ("Cannot happen");
5580                 }
5581         }
5582
5583         //
5584         // This class is used to "disable" the code generation for the
5585         // temporary variable when initializing value types.
5586         //
5587         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5588                 public void AddressOf (EmitContext ec, AddressOp Mode)
5589                 {
5590                         // nothing
5591                 }
5592         }
5593         
5594         /// <summary>
5595         ///    Implements the new expression 
5596         /// </summary>
5597         public class New : ExpressionStatement, IMemoryLocation {
5598                 public readonly ArrayList Arguments;
5599
5600                 //
5601                 // During bootstrap, it contains the RequestedType,
5602                 // but if `type' is not null, it *might* contain a NewDelegate
5603                 // (because of field multi-initialization)
5604                 //
5605                 public Expression RequestedType;
5606
5607                 MethodBase method = null;
5608
5609                 //
5610                 // If set, the new expression is for a value_target, and
5611                 // we will not leave anything on the stack.
5612                 //
5613                 Expression value_target;
5614                 bool value_target_set = false;
5615                 
5616                 public New (Expression requested_type, ArrayList arguments, Location l)
5617                 {
5618                         RequestedType = requested_type;
5619                         Arguments = arguments;
5620                         loc = l;
5621                 }
5622
5623                 public bool SetValueTypeVariable (Expression value)
5624                 {
5625                         value_target = value;
5626                         value_target_set = true;
5627                         if (!(value_target is IMemoryLocation)){
5628                                 Error_UnexpectedKind ("variable", loc);
5629                                 return false;
5630                         }
5631                         return true;
5632                 }
5633
5634                 //
5635                 // This function is used to disable the following code sequence for
5636                 // value type initialization:
5637                 //
5638                 // AddressOf (temporary)
5639                 // Construct/Init
5640                 // LoadTemporary
5641                 //
5642                 // Instead the provide will have provided us with the address on the
5643                 // stack to store the results.
5644                 //
5645                 static Expression MyEmptyExpression;
5646                 
5647                 public void DisableTemporaryValueType ()
5648                 {
5649                         if (MyEmptyExpression == null)
5650                                 MyEmptyExpression = new EmptyAddressOf ();
5651
5652                         //
5653                         // To enable this, look into:
5654                         // test-34 and test-89 and self bootstrapping.
5655                         //
5656                         // For instance, we can avoid a copy by using `newobj'
5657                         // instead of Call + Push-temp on value types.
5658 //                      value_target = MyEmptyExpression;
5659                 }
5660
5661                 public override Expression DoResolve (EmitContext ec)
5662                 {
5663                         //
5664                         // The New DoResolve might be called twice when initializing field
5665                         // expressions (see EmitFieldInitializers, the call to
5666                         // GetInitializerExpression will perform a resolve on the expression,
5667                         // and later the assign will trigger another resolution
5668                         //
5669                         // This leads to bugs (#37014)
5670                         //
5671                         if (type != null){
5672                                 if (RequestedType is NewDelegate)
5673                                         return RequestedType;
5674                                 return this;
5675                         }
5676                         
5677                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5678                         if (texpr == null)
5679                                 return null;
5680
5681                         type = texpr.ResolveType (ec);
5682                         
5683                         CheckObsoleteAttribute (type);
5684
5685                         bool IsDelegate = TypeManager.IsDelegateType (type);
5686                         
5687                         if (IsDelegate){
5688                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5689                                 if (RequestedType != null)
5690                                         if (!(RequestedType is NewDelegate))
5691                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5692                                 return RequestedType;
5693                         }
5694
5695                         if (type.IsAbstract && type.IsSealed) {
5696                                 Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type));
5697                                 return null;
5698                         }
5699
5700                         if (type.IsInterface || type.IsAbstract){
5701                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5702                                 return null;
5703                         }
5704                         
5705                         bool is_struct = type.IsValueType;
5706                         eclass = ExprClass.Value;
5707
5708                         //
5709                         // SRE returns a match for .ctor () on structs (the object constructor), 
5710                         // so we have to manually ignore it.
5711                         //
5712                         if (is_struct && Arguments == null)
5713                                 return this;
5714                         
5715                         Expression ml;
5716                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5717                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5718                                                 MemberTypes.Constructor,
5719                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5720
5721                         if (ml == null)
5722                                 return null;
5723                         
5724                         if (! (ml is MethodGroupExpr)){
5725                                 if (!is_struct){
5726                                         ml.Error_UnexpectedKind ("method group", loc);
5727                                         return null;
5728                                 }
5729                         }
5730
5731                         if (ml != null) {
5732                                 if (Arguments != null){
5733                                         foreach (Argument a in Arguments){
5734                                                 if (!a.Resolve (ec, loc))
5735                                                         return null;
5736                                         }
5737                                 }
5738
5739                                 method = Invocation.OverloadResolve (
5740                                         ec, (MethodGroupExpr) ml, Arguments, false, loc);
5741                                 
5742                         }
5743
5744                         if (method == null) { 
5745                                 if (!is_struct || Arguments.Count > 0) {
5746                                         Error (1501, String.Format (
5747                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5748                                             TypeManager.CSharpName (type)));
5749                                         return null;
5750                                 }
5751                         }
5752
5753                         return this;
5754                 }
5755
5756                 //
5757                 // This DoEmit can be invoked in two contexts:
5758                 //    * As a mechanism that will leave a value on the stack (new object)
5759                 //    * As one that wont (init struct)
5760                 //
5761                 // You can control whether a value is required on the stack by passing
5762                 // need_value_on_stack.  The code *might* leave a value on the stack
5763                 // so it must be popped manually
5764                 //
5765                 // If we are dealing with a ValueType, we have a few
5766                 // situations to deal with:
5767                 //
5768                 //    * The target is a ValueType, and we have been provided
5769                 //      the instance (this is easy, we are being assigned).
5770                 //
5771                 //    * The target of New is being passed as an argument,
5772                 //      to a boxing operation or a function that takes a
5773                 //      ValueType.
5774                 //
5775                 //      In this case, we need to create a temporary variable
5776                 //      that is the argument of New.
5777                 //
5778                 // Returns whether a value is left on the stack
5779                 //
5780                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5781                 {
5782                         bool is_value_type = type.IsValueType;
5783                         ILGenerator ig = ec.ig;
5784
5785                         if (is_value_type){
5786                                 IMemoryLocation ml;
5787
5788                                 // Allow DoEmit() to be called multiple times.
5789                                 // We need to create a new LocalTemporary each time since
5790                                 // you can't share LocalBuilders among ILGeneators.
5791                                 if (!value_target_set)
5792                                         value_target = new LocalTemporary (ec, type);
5793
5794                                 ml = (IMemoryLocation) value_target;
5795                                 ml.AddressOf (ec, AddressOp.Store);
5796                         }
5797
5798                         if (method != null)
5799                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5800
5801                         if (is_value_type){
5802                                 if (method == null)
5803                                         ig.Emit (OpCodes.Initobj, type);
5804                                 else 
5805                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5806                                 if (need_value_on_stack){
5807                                         value_target.Emit (ec);
5808                                         return true;
5809                                 }
5810                                 return false;
5811                         } else {
5812                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5813                                 return true;
5814                         }
5815                 }
5816
5817                 public override void Emit (EmitContext ec)
5818                 {
5819                         DoEmit (ec, true);
5820                 }
5821                 
5822                 public override void EmitStatement (EmitContext ec)
5823                 {
5824                         if (DoEmit (ec, false))
5825                                 ec.ig.Emit (OpCodes.Pop);
5826                 }
5827
5828                 public void AddressOf (EmitContext ec, AddressOp Mode)
5829                 {
5830                         if (!type.IsValueType){
5831                                 //
5832                                 // We throw an exception.  So far, I believe we only need to support
5833                                 // value types:
5834                                 // foreach (int j in new StructType ())
5835                                 // see bug 42390
5836                                 //
5837                                 throw new Exception ("AddressOf should not be used for classes");
5838                         }
5839
5840                         if (!value_target_set)
5841                                 value_target = new LocalTemporary (ec, type);
5842                                         
5843                         IMemoryLocation ml = (IMemoryLocation) value_target;
5844                         ml.AddressOf (ec, AddressOp.Store);
5845                         if (method != null)
5846                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5847
5848                         if (method == null)
5849                                 ec.ig.Emit (OpCodes.Initobj, type);
5850                         else 
5851                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5852                         
5853                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5854                 }
5855         }
5856
5857         /// <summary>
5858         ///   14.5.10.2: Represents an array creation expression.
5859         /// </summary>
5860         ///
5861         /// <remarks>
5862         ///   There are two possible scenarios here: one is an array creation
5863         ///   expression that specifies the dimensions and optionally the
5864         ///   initialization data and the other which does not need dimensions
5865         ///   specified but where initialization data is mandatory.
5866         /// </remarks>
5867         public class ArrayCreation : Expression {
5868                 Expression requested_base_type;
5869                 ArrayList initializers;
5870
5871                 //
5872                 // The list of Argument types.
5873                 // This is used to construct the `newarray' or constructor signature
5874                 //
5875                 ArrayList arguments;
5876
5877                 //
5878                 // Method used to create the array object.
5879                 //
5880                 MethodBase new_method = null;
5881                 
5882                 Type array_element_type;
5883                 Type underlying_type;
5884                 bool is_one_dimensional = false;
5885                 bool is_builtin_type = false;
5886                 bool expect_initializers = false;
5887                 int num_arguments = 0;
5888                 int dimensions = 0;
5889                 string rank;
5890
5891                 ArrayList array_data;
5892
5893                 Hashtable bounds;
5894
5895                 //
5896                 // The number of array initializers that we can handle
5897                 // via the InitializeArray method - through EmitStaticInitializers
5898                 //
5899                 int num_automatic_initializers;
5900
5901                 const int max_automatic_initializers = 6;
5902                 
5903                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5904                 {
5905                         this.requested_base_type = requested_base_type;
5906                         this.initializers = initializers;
5907                         this.rank = rank;
5908                         loc = l;
5909
5910                         arguments = new ArrayList ();
5911
5912                         foreach (Expression e in exprs) {
5913                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5914                                 num_arguments++;
5915                         }
5916                 }
5917
5918                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5919                 {
5920                         this.requested_base_type = requested_base_type;
5921                         this.initializers = initializers;
5922                         this.rank = rank;
5923                         loc = l;
5924
5925                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5926                         //
5927                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5928                         //
5929                         //dimensions = tmp.Length - 1;
5930                         expect_initializers = true;
5931                 }
5932
5933                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5934                 {
5935                         StringBuilder sb = new StringBuilder (rank);
5936                         
5937                         sb.Append ("[");
5938                         for (int i = 1; i < idx_count; i++)
5939                                 sb.Append (",");
5940                         
5941                         sb.Append ("]");
5942
5943                         return new ComposedCast (base_type, sb.ToString (), loc);
5944                 }
5945
5946                 void Error_IncorrectArrayInitializer ()
5947                 {
5948                         Error (178, "Incorrectly structured array initializer");
5949                 }
5950                 
5951                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5952                 {
5953                         if (specified_dims) { 
5954                                 Argument a = (Argument) arguments [idx];
5955                                 
5956                                 if (!a.Resolve (ec, loc))
5957                                         return false;
5958                                 
5959                                 if (!(a.Expr is Constant)) {
5960                                         Error (150, "A constant value is expected");
5961                                         return false;
5962                                 }
5963                                 
5964                                 int value = (int) ((Constant) a.Expr).GetValue ();
5965                                 
5966                                 if (value != probe.Count) {
5967                                         Error_IncorrectArrayInitializer ();
5968                                         return false;
5969                                 }
5970                                 
5971                                 bounds [idx] = value;
5972                         }
5973
5974                         int child_bounds = -1;
5975                         foreach (object o in probe) {
5976                                 if (o is ArrayList) {
5977                                         int current_bounds = ((ArrayList) o).Count;
5978                                         
5979                                         if (child_bounds == -1) 
5980                                                 child_bounds = current_bounds;
5981
5982                                         else if (child_bounds != current_bounds){
5983                                                 Error_IncorrectArrayInitializer ();
5984                                                 return false;
5985                                         }
5986                                         if (specified_dims && (idx + 1 >= arguments.Count)){
5987                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5988                                                 return false;
5989                                         }
5990                                         
5991                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5992                                         if (!ret)
5993                                                 return false;
5994                                 } else {
5995                                         if (child_bounds != -1){
5996                                                 Error_IncorrectArrayInitializer ();
5997                                                 return false;
5998                                         }
5999                                         
6000                                         Expression tmp = (Expression) o;
6001                                         tmp = tmp.Resolve (ec);
6002                                         if (tmp == null)
6003                                                 return false;
6004
6005                                         // Console.WriteLine ("I got: " + tmp);
6006                                         // Handle initialization from vars, fields etc.
6007
6008                                         Expression conv = Convert.ImplicitConversionRequired (
6009                                                 ec, tmp, underlying_type, loc);
6010                                         
6011                                         if (conv == null) 
6012                                                 return false;
6013                                         
6014                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6015                                                 // These are subclasses of Constant that can appear as elements of an
6016                                                 // array that cannot be statically initialized (with num_automatic_initializers
6017                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6018                                                 array_data.Add (conv);
6019                                         } else if (conv is Constant) {
6020                                                 // These are the types of Constant that can appear in arrays that can be
6021                                                 // statically allocated.
6022                                                 array_data.Add (conv);
6023                                                 num_automatic_initializers++;
6024                                         } else
6025                                                 array_data.Add (conv);
6026                                 }
6027                         }
6028
6029                         return true;
6030                 }
6031                 
6032                 public void UpdateIndices (EmitContext ec)
6033                 {
6034                         int i = 0;
6035                         for (ArrayList probe = initializers; probe != null;) {
6036                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6037                                         Expression e = new IntConstant (probe.Count);
6038                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6039
6040                                         bounds [i++] =  probe.Count;
6041                                         
6042                                         probe = (ArrayList) probe [0];
6043                                         
6044                                 } else {
6045                                         Expression e = new IntConstant (probe.Count);
6046                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6047
6048                                         bounds [i++] = probe.Count;
6049                                         probe = null;
6050                                 }
6051                         }
6052
6053                 }
6054                 
6055                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6056                 {
6057                         if (initializers == null) {
6058                                 if (expect_initializers)
6059                                         return false;
6060                                 else
6061                                         return true;
6062                         }
6063                         
6064                         if (underlying_type == null)
6065                                 return false;
6066                         
6067                         //
6068                         // We use this to store all the date values in the order in which we
6069                         // will need to store them in the byte blob later
6070                         //
6071                         array_data = new ArrayList ();
6072                         bounds = new Hashtable ();
6073                         
6074                         bool ret;
6075
6076                         if (arguments != null) {
6077                                 ret = CheckIndices (ec, initializers, 0, true);
6078                                 return ret;
6079                         } else {
6080                                 arguments = new ArrayList ();
6081
6082                                 ret = CheckIndices (ec, initializers, 0, false);
6083                                 
6084                                 if (!ret)
6085                                         return false;
6086                                 
6087                                 UpdateIndices (ec);
6088                                 
6089                                 if (arguments.Count != dimensions) {
6090                                         Error_IncorrectArrayInitializer ();
6091                                         return false;
6092                                 }
6093
6094                                 return ret;
6095                         }
6096                 }
6097
6098                 //
6099                 // Converts `source' to an int, uint, long or ulong.
6100                 //
6101                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6102                 {
6103                         Expression target;
6104                         
6105                         bool old_checked = ec.CheckState;
6106                         ec.CheckState = true;
6107                         
6108                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6109                         if (target == null){
6110                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6111                                 if (target == null){
6112                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6113                                         if (target == null){
6114                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6115                                                 if (target == null)
6116                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6117                                         }
6118                                 }
6119                         } 
6120                         ec.CheckState = old_checked;
6121
6122                         //
6123                         // Only positive constants are allowed at compile time
6124                         //
6125                         if (target is Constant){
6126                                 if (target is IntConstant){
6127                                         if (((IntConstant) target).Value < 0){
6128                                                 Expression.Error_NegativeArrayIndex (loc);
6129                                                 return null;
6130                                         }
6131                                 }
6132
6133                                 if (target is LongConstant){
6134                                         if (((LongConstant) target).Value < 0){
6135                                                 Expression.Error_NegativeArrayIndex (loc);
6136                                                 return null;
6137                                         }
6138                                 }
6139                                 
6140                         }
6141
6142                         return target;
6143                 }
6144
6145                 //
6146                 // Creates the type of the array
6147                 //
6148                 bool LookupType (EmitContext ec)
6149                 {
6150                         StringBuilder array_qualifier = new StringBuilder (rank);
6151
6152                         //
6153                         // `In the first form allocates an array instace of the type that results
6154                         // from deleting each of the individual expression from the expression list'
6155                         //
6156                         if (num_arguments > 0) {
6157                                 array_qualifier.Append ("[");
6158                                 for (int i = num_arguments-1; i > 0; i--)
6159                                         array_qualifier.Append (",");
6160                                 array_qualifier.Append ("]");                           
6161                         }
6162
6163                         //
6164                         // Lookup the type
6165                         //
6166                         TypeExpr array_type_expr;
6167                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6168                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6169                         if (array_type_expr == null)
6170                                 return false;
6171
6172                         type = array_type_expr.ResolveType (ec);
6173                         
6174                         if (!type.IsArray) {
6175                                 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6176                                 return false;
6177                         }
6178                         underlying_type = TypeManager.GetElementType (type);
6179                         dimensions = type.GetArrayRank ();
6180
6181                         return true;
6182                 }
6183                 
6184                 public override Expression DoResolve (EmitContext ec)
6185                 {
6186                         int arg_count;
6187
6188                         if (!LookupType (ec))
6189                                 return null;
6190                         
6191                         //
6192                         // First step is to validate the initializers and fill
6193                         // in any missing bits
6194                         //
6195                         if (!ValidateInitializers (ec, type))
6196                                 return null;
6197
6198                         if (arguments == null)
6199                                 arg_count = 0;
6200                         else {
6201                                 arg_count = arguments.Count;
6202                                 foreach (Argument a in arguments){
6203                                         if (!a.Resolve (ec, loc))
6204                                                 return null;
6205
6206                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6207                                         if (real_arg == null)
6208                                                 return null;
6209
6210                                         a.Expr = real_arg;
6211                                 }
6212                         }
6213                         
6214                         array_element_type = TypeManager.GetElementType (type);
6215
6216                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6217                                 Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6218                                 return null;
6219                         }
6220
6221                         if (arg_count == 1) {
6222                                 is_one_dimensional = true;
6223                                 eclass = ExprClass.Value;
6224                                 return this;
6225                         }
6226
6227                         is_builtin_type = TypeManager.IsBuiltinType (type);
6228
6229                         if (is_builtin_type) {
6230                                 Expression ml;
6231                                 
6232                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6233                                                    AllBindingFlags, loc);
6234                                 
6235                                 if (!(ml is MethodGroupExpr)) {
6236                                         ml.Error_UnexpectedKind ("method group", loc);
6237                                         return null;
6238                                 }
6239                                 
6240                                 if (ml == null) {
6241                                         Error (-6, "New invocation: Can not find a constructor for " +
6242                                                       "this argument list");
6243                                         return null;
6244                                 }
6245                                 
6246                                 new_method = Invocation.OverloadResolve (
6247                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6248
6249                                 if (new_method == null) {
6250                                         Error (-6, "New invocation: Can not find a constructor for " +
6251                                                       "this argument list");
6252                                         return null;
6253                                 }
6254                                 
6255                                 eclass = ExprClass.Value;
6256                                 return this;
6257                         } else {
6258                                 ModuleBuilder mb = CodeGen.Module.Builder;
6259                                 ArrayList args = new ArrayList ();
6260                                 
6261                                 if (arguments != null) {
6262                                         for (int i = 0; i < arg_count; i++)
6263                                                 args.Add (TypeManager.int32_type);
6264                                 }
6265                                 
6266                                 Type [] arg_types = null;
6267
6268                                 if (args.Count > 0)
6269                                         arg_types = new Type [args.Count];
6270                                 
6271                                 args.CopyTo (arg_types, 0);
6272                                 
6273                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6274                                                             arg_types);
6275
6276                                 if (new_method == null) {
6277                                         Error (-6, "New invocation: Can not find a constructor for " +
6278                                                       "this argument list");
6279                                         return null;
6280                                 }
6281                                 
6282                                 eclass = ExprClass.Value;
6283                                 return this;
6284                         }
6285                 }
6286
6287                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6288                 {
6289                         int factor;
6290                         byte [] data;
6291                         byte [] element;
6292                         int count = array_data.Count;
6293
6294                         if (underlying_type.IsEnum)
6295                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6296                         
6297                         factor = GetTypeSize (underlying_type);
6298                         if (factor == 0)
6299                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6300
6301                         data = new byte [(count * factor + 4) & ~3];
6302                         int idx = 0;
6303                         
6304                         for (int i = 0; i < count; ++i) {
6305                                 object v = array_data [i];
6306
6307                                 if (v is EnumConstant)
6308                                         v = ((EnumConstant) v).Child;
6309                                 
6310                                 if (v is Constant && !(v is StringConstant))
6311                                         v = ((Constant) v).GetValue ();
6312                                 else {
6313                                         idx += factor;
6314                                         continue;
6315                                 }
6316                                 
6317                                 if (underlying_type == TypeManager.int64_type){
6318                                         if (!(v is Expression)){
6319                                                 long val = (long) v;
6320                                                 
6321                                                 for (int j = 0; j < factor; ++j) {
6322                                                         data [idx + j] = (byte) (val & 0xFF);
6323                                                         val = (val >> 8);
6324                                                 }
6325                                         }
6326                                 } else if (underlying_type == TypeManager.uint64_type){
6327                                         if (!(v is Expression)){
6328                                                 ulong val = (ulong) v;
6329
6330                                                 for (int j = 0; j < factor; ++j) {
6331                                                         data [idx + j] = (byte) (val & 0xFF);
6332                                                         val = (val >> 8);
6333                                                 }
6334                                         }
6335                                 } else if (underlying_type == TypeManager.float_type) {
6336                                         if (!(v is Expression)){
6337                                                 element = BitConverter.GetBytes ((float) v);
6338                                                         
6339                                                 for (int j = 0; j < factor; ++j)
6340                                                         data [idx + j] = element [j];
6341                                         }
6342                                 } else if (underlying_type == TypeManager.double_type) {
6343                                         if (!(v is Expression)){
6344                                                 element = BitConverter.GetBytes ((double) v);
6345
6346                                                 for (int j = 0; j < factor; ++j)
6347                                                         data [idx + j] = element [j];
6348                                         }
6349                                 } else if (underlying_type == TypeManager.char_type){
6350                                         if (!(v is Expression)){
6351                                                 int val = (int) ((char) v);
6352                                                 
6353                                                 data [idx] = (byte) (val & 0xff);
6354                                                 data [idx+1] = (byte) (val >> 8);
6355                                         }
6356                                 } else if (underlying_type == TypeManager.short_type){
6357                                         if (!(v is Expression)){
6358                                                 int val = (int) ((short) v);
6359                                         
6360                                                 data [idx] = (byte) (val & 0xff);
6361                                                 data [idx+1] = (byte) (val >> 8);
6362                                         }
6363                                 } else if (underlying_type == TypeManager.ushort_type){
6364                                         if (!(v is Expression)){
6365                                                 int val = (int) ((ushort) v);
6366                                         
6367                                                 data [idx] = (byte) (val & 0xff);
6368                                                 data [idx+1] = (byte) (val >> 8);
6369                                         }
6370                                 } else if (underlying_type == TypeManager.int32_type) {
6371                                         if (!(v is Expression)){
6372                                                 int val = (int) v;
6373                                         
6374                                                 data [idx]   = (byte) (val & 0xff);
6375                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6376                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6377                                                 data [idx+3] = (byte) (val >> 24);
6378                                         }
6379                                 } else if (underlying_type == TypeManager.uint32_type) {
6380                                         if (!(v is Expression)){
6381                                                 uint val = (uint) v;
6382                                         
6383                                                 data [idx]   = (byte) (val & 0xff);
6384                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6385                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6386                                                 data [idx+3] = (byte) (val >> 24);
6387                                         }
6388                                 } else if (underlying_type == TypeManager.sbyte_type) {
6389                                         if (!(v is Expression)){
6390                                                 sbyte val = (sbyte) v;
6391                                                 data [idx] = (byte) val;
6392                                         }
6393                                 } else if (underlying_type == TypeManager.byte_type) {
6394                                         if (!(v is Expression)){
6395                                                 byte val = (byte) v;
6396                                                 data [idx] = (byte) val;
6397                                         }
6398                                 } else if (underlying_type == TypeManager.bool_type) {
6399                                         if (!(v is Expression)){
6400                                                 bool val = (bool) v;
6401                                                 data [idx] = (byte) (val ? 1 : 0);
6402                                         }
6403                                 } else if (underlying_type == TypeManager.decimal_type){
6404                                         if (!(v is Expression)){
6405                                                 int [] bits = Decimal.GetBits ((decimal) v);
6406                                                 int p = idx;
6407
6408                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6409                                                 int [] nbits = new int [4];
6410                                                 nbits [0] = bits [3];
6411                                                 nbits [1] = bits [2];
6412                                                 nbits [2] = bits [0];
6413                                                 nbits [3] = bits [1];
6414                                                 
6415                                                 for (int j = 0; j < 4; j++){
6416                                                         data [p++] = (byte) (nbits [j] & 0xff);
6417                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6418                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6419                                                         data [p++] = (byte) (nbits [j] >> 24);
6420                                                 }
6421                                         }
6422                                 } else
6423                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6424
6425                                 idx += factor;
6426                         }
6427
6428                         return data;
6429                 }
6430
6431                 //
6432                 // Emits the initializers for the array
6433                 //
6434                 void EmitStaticInitializers (EmitContext ec)
6435                 {
6436                         //
6437                         // First, the static data
6438                         //
6439                         FieldBuilder fb;
6440                         ILGenerator ig = ec.ig;
6441                         
6442                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6443
6444                         fb = RootContext.MakeStaticData (data);
6445
6446                         ig.Emit (OpCodes.Dup);
6447                         ig.Emit (OpCodes.Ldtoken, fb);
6448                         ig.Emit (OpCodes.Call,
6449                                  TypeManager.void_initializearray_array_fieldhandle);
6450                 }
6451
6452                 //
6453                 // Emits pieces of the array that can not be computed at compile
6454                 // time (variables and string locations).
6455                 //
6456                 // This always expect the top value on the stack to be the array
6457                 //
6458                 void EmitDynamicInitializers (EmitContext ec)
6459                 {
6460                         ILGenerator ig = ec.ig;
6461                         int dims = bounds.Count;
6462                         int [] current_pos = new int [dims];
6463                         int top = array_data.Count;
6464
6465                         MethodInfo set = null;
6466
6467                         if (dims != 1){
6468                                 Type [] args;
6469                                 ModuleBuilder mb = null;
6470                                 mb = CodeGen.Module.Builder;
6471                                 args = new Type [dims + 1];
6472
6473                                 int j;
6474                                 for (j = 0; j < dims; j++)
6475                                         args [j] = TypeManager.int32_type;
6476
6477                                 args [j] = array_element_type;
6478                                 
6479                                 set = mb.GetArrayMethod (
6480                                         type, "Set",
6481                                         CallingConventions.HasThis | CallingConventions.Standard,
6482                                         TypeManager.void_type, args);
6483                         }
6484                         
6485                         for (int i = 0; i < top; i++){
6486
6487                                 Expression e = null;
6488
6489                                 if (array_data [i] is Expression)
6490                                         e = (Expression) array_data [i];
6491
6492                                 if (e != null) {
6493                                         //
6494                                         // Basically we do this for string literals and
6495                                         // other non-literal expressions
6496                                         //
6497                                         if (e is EnumConstant){
6498                                                 e = ((EnumConstant) e).Child;
6499                                         }
6500                                         
6501                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6502                                             num_automatic_initializers <= max_automatic_initializers) {
6503                                                 Type etype = e.Type;
6504                                                 
6505                                                 ig.Emit (OpCodes.Dup);
6506
6507                                                 for (int idx = 0; idx < dims; idx++) 
6508                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6509
6510                                                 //
6511                                                 // If we are dealing with a struct, get the
6512                                                 // address of it, so we can store it.
6513                                                 //
6514                                                 if ((dims == 1) && 
6515                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6516                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6517                                                      etype == TypeManager.decimal_type)) {
6518                                                         if (e is New){
6519                                                                 New n = (New) e;
6520
6521                                                                 //
6522                                                                 // Let new know that we are providing
6523                                                                 // the address where to store the results
6524                                                                 //
6525                                                                 n.DisableTemporaryValueType ();
6526                                                         }
6527
6528                                                         ig.Emit (OpCodes.Ldelema, etype);
6529                                                 }
6530
6531                                                 e.Emit (ec);
6532
6533                                                 if (dims == 1) {
6534                                                         bool is_stobj;
6535                                                         OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj);
6536                                                         if (is_stobj)
6537                                                                 ig.Emit (OpCodes.Stobj, etype);
6538                                                         else
6539                                                                 ig.Emit (op);
6540                                                 } else 
6541                                                         ig.Emit (OpCodes.Call, set);
6542
6543                                         }
6544                                 }
6545                                 
6546                                 //
6547                                 // Advance counter
6548                                 //
6549                                 for (int j = dims - 1; j >= 0; j--){
6550                                         current_pos [j]++;
6551                                         if (current_pos [j] < (int) bounds [j])
6552                                                 break;
6553                                         current_pos [j] = 0;
6554                                 }
6555                         }
6556                 }
6557
6558                 void EmitArrayArguments (EmitContext ec)
6559                 {
6560                         ILGenerator ig = ec.ig;
6561                         
6562                         foreach (Argument a in arguments) {
6563                                 Type atype = a.Type;
6564                                 a.Emit (ec);
6565
6566                                 if (atype == TypeManager.uint64_type)
6567                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6568                                 else if (atype == TypeManager.int64_type)
6569                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6570                         }
6571                 }
6572                 
6573                 public override void Emit (EmitContext ec)
6574                 {
6575                         ILGenerator ig = ec.ig;
6576                         
6577                         EmitArrayArguments (ec);
6578                         if (is_one_dimensional)
6579                                 ig.Emit (OpCodes.Newarr, array_element_type);
6580                         else {
6581                                 if (is_builtin_type) 
6582                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6583                                 else 
6584                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6585                         }
6586                         
6587                         if (initializers != null){
6588                                 //
6589                                 // FIXME: Set this variable correctly.
6590                                 // 
6591                                 bool dynamic_initializers = true;
6592
6593                                 // This will never be true for array types that cannot be statically
6594                                 // initialized. num_automatic_initializers will always be zero.  See
6595                                 // CheckIndices.
6596                                 if (num_automatic_initializers > max_automatic_initializers)
6597                                         EmitStaticInitializers (ec);
6598                                 
6599                                 if (dynamic_initializers)
6600                                         EmitDynamicInitializers (ec);
6601                         }
6602                 }
6603
6604                 public object EncodeAsAttribute ()
6605                 {
6606                         if (!is_one_dimensional){
6607                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6608                                 return null;
6609                         }
6610
6611                         if (array_data == null){
6612                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6613                                 return null;
6614                         }
6615                         
6616                         object [] ret = new object [array_data.Count];
6617                         int i = 0;
6618                         foreach (Expression e in array_data){
6619                                 object v;
6620                                 
6621                                 if (e is NullLiteral)
6622                                         v = null;
6623                                 else {
6624                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6625                                                 return null;
6626                                 }
6627                                 ret [i++] = v;
6628                         }
6629                         return ret;
6630                 }
6631         }
6632         
6633         /// <summary>
6634         ///   Represents the `this' construct
6635         /// </summary>
6636         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6637
6638                 Block block;
6639                 VariableInfo variable_info;
6640                 
6641                 public This (Block block, Location loc)
6642                 {
6643                         this.loc = loc;
6644                         this.block = block;
6645                 }
6646
6647                 public This (Location loc)
6648                 {
6649                         this.loc = loc;
6650                 }
6651
6652                 public VariableInfo VariableInfo {
6653                         get { return variable_info; }
6654                 }
6655
6656                 public bool VerifyFixed (bool is_expression)
6657                 {
6658                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6659                                 return false;
6660                         else
6661                                 return variable_info.LocalInfo.IsFixed;
6662                 }
6663
6664                 public bool ResolveBase (EmitContext ec)
6665                 {
6666                         eclass = ExprClass.Variable;
6667                         type = ec.ContainerType;
6668
6669                         if (ec.IsStatic) {
6670                                 Error (26, "Keyword this not valid in static code");
6671                                 return false;
6672                         }
6673
6674                         if ((block != null) && (block.ThisVariable != null))
6675                                 variable_info = block.ThisVariable.VariableInfo;
6676
6677                         return true;
6678                 }
6679
6680                 public override Expression DoResolve (EmitContext ec)
6681                 {
6682                         if (!ResolveBase (ec))
6683                                 return null;
6684
6685                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6686                                 Error (188, "The this object cannot be used before all " +
6687                                        "of its fields are assigned to");
6688                                 variable_info.SetAssigned (ec);
6689                                 return this;
6690                         }
6691
6692                         if (ec.IsFieldInitializer) {
6693                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6694                                        "a method or a property.");
6695                                 return null;
6696                         }
6697
6698                         return this;
6699                 }
6700
6701                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6702                 {
6703                         if (!ResolveBase (ec))
6704                                 return null;
6705
6706                         if (variable_info != null)
6707                                 variable_info.SetAssigned (ec);
6708                         
6709                         if (ec.TypeContainer is Class){
6710                                 Error (1604, "Cannot assign to `this'");
6711                                 return null;
6712                         }
6713
6714                         return this;
6715                 }
6716
6717                 public void Emit (EmitContext ec, bool leave_copy)
6718                 {
6719                         Emit (ec);
6720                         if (leave_copy)
6721                                 ec.ig.Emit (OpCodes.Dup);
6722                 }
6723                 
6724                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6725                 {
6726                         ILGenerator ig = ec.ig;
6727                         
6728                         if (ec.TypeContainer is Struct){
6729                                 ec.EmitThis ();
6730                                 source.Emit (ec);
6731                                 if (leave_copy)
6732                                         ec.ig.Emit (OpCodes.Dup);
6733                                 ig.Emit (OpCodes.Stobj, type);
6734                         } else {
6735                                 throw new Exception ("how did you get here");
6736                         }
6737                 }
6738                 
6739                 public override void Emit (EmitContext ec)
6740                 {
6741                         ILGenerator ig = ec.ig;
6742
6743                         ec.EmitThis ();
6744                         if (ec.TypeContainer is Struct)
6745                                 ig.Emit (OpCodes.Ldobj, type);
6746                 }
6747
6748                 public void AddressOf (EmitContext ec, AddressOp mode)
6749                 {
6750                         ec.EmitThis ();
6751
6752                         // FIMXE
6753                         // FIGURE OUT WHY LDARG_S does not work
6754                         //
6755                         // consider: struct X { int val; int P { set { val = value; }}}
6756                         //
6757                         // Yes, this looks very bad. Look at `NOTAS' for
6758                         // an explanation.
6759                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6760                 }
6761         }
6762
6763         /// <summary>
6764         ///   Represents the `__arglist' construct
6765         /// </summary>
6766         public class ArglistAccess : Expression
6767         {
6768                 public ArglistAccess (Location loc)
6769                 {
6770                         this.loc = loc;
6771                 }
6772
6773                 public bool ResolveBase (EmitContext ec)
6774                 {
6775                         eclass = ExprClass.Variable;
6776                         type = TypeManager.runtime_argument_handle_type;
6777                         return true;
6778                 }
6779
6780                 public override Expression DoResolve (EmitContext ec)
6781                 {
6782                         if (!ResolveBase (ec))
6783                                 return null;
6784
6785                         if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
6786                                 Error (190, "The __arglist construct is valid only within " +
6787                                        "a variable argument method.");
6788                                 return null;
6789                         }
6790
6791                         return this;
6792                 }
6793
6794                 public override void Emit (EmitContext ec)
6795                 {
6796                         ec.ig.Emit (OpCodes.Arglist);
6797                 }
6798         }
6799
6800         /// <summary>
6801         ///   Represents the `__arglist (....)' construct
6802         /// </summary>
6803         public class Arglist : Expression
6804         {
6805                 public readonly Argument[] Arguments;
6806
6807                 public Arglist (Argument[] args, Location l)
6808                 {
6809                         Arguments = args;
6810                         loc = l;
6811                 }
6812
6813                 public Type[] ArgumentTypes {
6814                         get {
6815                                 Type[] retval = new Type [Arguments.Length];
6816                                 for (int i = 0; i < Arguments.Length; i++)
6817                                         retval [i] = Arguments [i].Type;
6818                                 return retval;
6819                         }
6820                 }
6821
6822                 public override Expression DoResolve (EmitContext ec)
6823                 {
6824                         eclass = ExprClass.Variable;
6825                         type = TypeManager.runtime_argument_handle_type;
6826
6827                         foreach (Argument arg in Arguments) {
6828                                 if (!arg.Resolve (ec, loc))
6829                                         return null;
6830                         }
6831
6832                         return this;
6833                 }
6834
6835                 public override void Emit (EmitContext ec)
6836                 {
6837                         foreach (Argument arg in Arguments)
6838                                 arg.Emit (ec);
6839                 }
6840         }
6841
6842         //
6843         // This produces the value that renders an instance, used by the iterators code
6844         //
6845         public class ProxyInstance : Expression, IMemoryLocation  {
6846                 public override Expression DoResolve (EmitContext ec)
6847                 {
6848                         eclass = ExprClass.Variable;
6849                         type = ec.ContainerType;
6850                         return this;
6851                 }
6852                 
6853                 public override void Emit (EmitContext ec)
6854                 {
6855                         ec.ig.Emit (OpCodes.Ldarg_0);
6856
6857                 }
6858                 
6859                 public void AddressOf (EmitContext ec, AddressOp mode)
6860                 {
6861                         ec.ig.Emit (OpCodes.Ldarg_0);
6862                 }
6863         }
6864
6865         /// <summary>
6866         ///   Implements the typeof operator
6867         /// </summary>
6868         public class TypeOf : Expression {
6869                 public Expression QueriedType;
6870                 protected Type typearg;
6871                 
6872                 public TypeOf (Expression queried_type, Location l)
6873                 {
6874                         QueriedType = queried_type;
6875                         loc = l;
6876                 }
6877
6878                 public override Expression DoResolve (EmitContext ec)
6879                 {
6880                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6881                         if (texpr == null)
6882                                 return null;
6883
6884                         typearg = texpr.ResolveType (ec);
6885
6886                         if (typearg == TypeManager.void_type) {
6887                                 Error (673, "System.Void cannot be used from C# - " +
6888                                        "use typeof (void) to get the void type object");
6889                                 return null;
6890                         }
6891
6892                         if (typearg.IsPointer && !ec.InUnsafe){
6893                                 UnsafeError (loc);
6894                                 return null;
6895                         }
6896                         CheckObsoleteAttribute (typearg);
6897
6898                         type = TypeManager.type_type;
6899                         eclass = ExprClass.Type;
6900                         return this;
6901                 }
6902
6903                 public override void Emit (EmitContext ec)
6904                 {
6905                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6906                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6907                 }
6908
6909                 public Type TypeArg { 
6910                         get { return typearg; }
6911                 }
6912         }
6913
6914         /// <summary>
6915         ///   Implements the `typeof (void)' operator
6916         /// </summary>
6917         public class TypeOfVoid : TypeOf {
6918                 public TypeOfVoid (Location l) : base (null, l)
6919                 {
6920                         loc = l;
6921                 }
6922
6923                 public override Expression DoResolve (EmitContext ec)
6924                 {
6925                         type = TypeManager.type_type;
6926                         typearg = TypeManager.void_type;
6927                         eclass = ExprClass.Type;
6928                         return this;
6929                 }
6930         }
6931
6932         /// <summary>
6933         ///   Implements the sizeof expression
6934         /// </summary>
6935         public class SizeOf : Expression {
6936                 public Expression QueriedType;
6937                 Type type_queried;
6938                 
6939                 public SizeOf (Expression queried_type, Location l)
6940                 {
6941                         this.QueriedType = queried_type;
6942                         loc = l;
6943                 }
6944
6945                 public override Expression DoResolve (EmitContext ec)
6946                 {
6947                         if (!ec.InUnsafe) {
6948                                 Report.Error (
6949                                         233, loc, "Sizeof may only be used in an unsafe context " +
6950                                         "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6951                                 return null;
6952                         }
6953
6954                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6955                         if (texpr == null)
6956                                 return null;
6957
6958                         type_queried = texpr.ResolveType (ec);
6959
6960                         CheckObsoleteAttribute (type_queried);
6961
6962                         if (!TypeManager.IsUnmanagedType (type_queried)){
6963                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6964                                 return null;
6965                         }
6966                         
6967                         type = TypeManager.int32_type;
6968                         eclass = ExprClass.Value;
6969                         return this;
6970                 }
6971
6972                 public override void Emit (EmitContext ec)
6973                 {
6974                         int size = GetTypeSize (type_queried);
6975
6976                         if (size == 0)
6977                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6978                         else
6979                                 IntConstant.EmitInt (ec.ig, size);
6980                 }
6981         }
6982
6983         /// <summary>
6984         ///   Implements the member access expression
6985         /// </summary>
6986         public class MemberAccess : Expression {
6987                 public readonly string Identifier;
6988                 Expression expr;
6989                 
6990                 public MemberAccess (Expression expr, string id, Location l)
6991                 {
6992                         this.expr = expr;
6993                         Identifier = id;
6994                         loc = l;
6995                 }
6996
6997                 public Expression Expr {
6998                         get {
6999                                 return expr;
7000                         }
7001                 }
7002
7003                 public static void error176 (Location loc, string name)
7004                 {
7005                         Report.Error (176, loc, "Static member `" +
7006                                       name + "' cannot be accessed " +
7007                                       "with an instance reference, qualify with a " +
7008                                       "type name instead");
7009                 }
7010
7011                 public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
7012                 {
7013                         SimpleName sn = left_original as SimpleName;
7014                         if (sn == null || left == null || left.Type.Name != sn.Name)
7015                                 return false;
7016
7017                         return RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc) != null;
7018                 }
7019                 
7020                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7021                                                               Expression left, Location loc,
7022                                                               Expression left_original)
7023                 {
7024                         bool left_is_type, left_is_explicit;
7025
7026                         // If `left' is null, then we're called from SimpleNameResolve and this is
7027                         // a member in the currently defining class.
7028                         if (left == null) {
7029                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7030                                 left_is_explicit = false;
7031
7032                                 // Implicitly default to `this' unless we're static.
7033                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7034                                         left = ec.GetThis (loc);
7035                         } else {
7036                                 left_is_type = left is TypeExpr;
7037                                 left_is_explicit = true;
7038                         }
7039
7040                         if (member_lookup is FieldExpr){
7041                                 FieldExpr fe = (FieldExpr) member_lookup;
7042                                 FieldInfo fi = fe.FieldInfo;
7043                                 Type decl_type = fi.DeclaringType;
7044
7045                                 if (fi is FieldBuilder) {
7046                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7047                                         
7048                                         if (c != null) {
7049                                                 object o;
7050                                                 if (!c.LookupConstantValue (out o))
7051                                                         return null;
7052
7053                                                 object real_value = ((Constant) c.Expr).GetValue ();
7054
7055                                                 return Constantify (real_value, fi.FieldType);
7056                                         }
7057                                 }
7058
7059                                 if (fi.IsLiteral) {
7060                                         Type t = fi.FieldType;
7061                                         
7062                                         object o;
7063
7064                                         if (fi is FieldBuilder)
7065                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
7066                                         else
7067                                                 o = fi.GetValue (fi);
7068                                         
7069                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7070                                                 if (left_is_explicit && !left_is_type &&
7071                                                     !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) {
7072                                                         error176 (loc, fe.FieldInfo.Name);
7073                                                         return null;
7074                                                 }                                       
7075                                                 
7076                                                 Expression enum_member = MemberLookup (
7077                                                         ec, decl_type, "value__", MemberTypes.Field,
7078                                                         AllBindingFlags, loc); 
7079
7080                                                 Enum en = TypeManager.LookupEnum (decl_type);
7081
7082                                                 Constant c;
7083                                                 if (en != null)
7084                                                         c = Constantify (o, en.UnderlyingType);
7085                                                 else 
7086                                                         c = Constantify (o, enum_member.Type);
7087                                                 
7088                                                 return new EnumConstant (c, decl_type);
7089                                         }
7090                                         
7091                                         Expression exp = Constantify (o, t);
7092
7093                                         if (left_is_explicit && !left_is_type) {
7094                                                 error176 (loc, fe.FieldInfo.Name);
7095                                                 return null;
7096                                         }
7097                                         
7098                                         return exp;
7099                                 }
7100
7101                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
7102                                         UnsafeError (loc);
7103                                         return null;
7104                                 }
7105                         }
7106
7107                         if (member_lookup is EventExpr) {
7108                                 EventExpr ee = (EventExpr) member_lookup;
7109                                 
7110                                 //
7111                                 // If the event is local to this class, we transform ourselves into
7112                                 // a FieldExpr
7113                                 //
7114
7115                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7116                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7117                                         MemberInfo mi = GetFieldFromEvent (ee);
7118
7119                                         if (mi == null) {
7120                                                 //
7121                                                 // If this happens, then we have an event with its own
7122                                                 // accessors and private field etc so there's no need
7123                                                 // to transform ourselves.
7124                                                 //
7125                                                 ee.InstanceExpression = left;
7126                                                 return ee;
7127                                         }
7128
7129                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7130                                         
7131                                         if (ml == null) {
7132                                                 Report.Error (-200, loc, "Internal error!!");
7133                                                 return null;
7134                                         }
7135
7136                                         if (!left_is_explicit)
7137                                                 left = null;
7138
7139                                         ee.InstanceExpression = left;
7140
7141                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7142                                 }
7143                         }
7144
7145                         if (member_lookup is IMemberExpr) {
7146                                 IMemberExpr me = (IMemberExpr) member_lookup;
7147                                 MethodGroupExpr mg = me as MethodGroupExpr;
7148
7149                                 if (left_is_type){
7150                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7151                                                 mg.IsExplicitImpl = left_is_explicit;
7152
7153                                         if (!me.IsStatic){
7154                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7155                                                     IdenticalNameAndTypeName (ec, left_original, member_lookup, loc))
7156                                                         return member_lookup;
7157                                                 
7158                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7159                                                 return null;
7160                                         }
7161
7162                                 } else {
7163                                         if (!me.IsInstance) {
7164                                                 if (IdenticalNameAndTypeName (ec, left_original, left, loc))
7165                                                         return member_lookup;
7166
7167                                                 if (left_is_explicit) {
7168                                                         error176 (loc, me.Name);
7169                                                         return null;
7170                                                 }
7171                                         }                       
7172
7173                                         //
7174                                         // Since we can not check for instance objects in SimpleName,
7175                                         // becaue of the rule that allows types and variables to share
7176                                         // the name (as long as they can be de-ambiguated later, see 
7177                                         // IdenticalNameAndTypeName), we have to check whether left 
7178                                         // is an instance variable in a static context
7179                                         //
7180                                         // However, if the left-hand value is explicitly given, then
7181                                         // it is already our instance expression, so we aren't in
7182                                         // static context.
7183                                         //
7184
7185                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7186                                                 IMemberExpr mexp = (IMemberExpr) left;
7187
7188                                                 if (!mexp.IsStatic){
7189                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7190                                                         return null;
7191                                                 }
7192                                         }
7193
7194                                         if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc))
7195                                                 mg.IdenticalTypeName = true;
7196
7197                                         me.InstanceExpression = left;
7198                                 }
7199
7200                                 return member_lookup;
7201                         }
7202
7203                         Console.WriteLine ("Left is: " + left);
7204                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7205                         Environment.Exit (1);
7206                         return null;
7207                 }
7208                 
7209                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
7210                 {
7211                         if (type != null)
7212                                 throw new Exception ();
7213
7214                         //
7215                         // Resolve the expression with flow analysis turned off, we'll do the definite
7216                         // assignment checks later.  This is because we don't know yet what the expression
7217                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7218                         // definite assignment check on the actual field and not on the whole struct.
7219                         //
7220
7221                         Expression original = expr;
7222                         expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7223                         if (expr == null)
7224                                 return null;
7225
7226                         if (expr is SimpleName){
7227                                 SimpleName child_expr = (SimpleName) expr;
7228
7229                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7230
7231                                 return new_expr.Resolve (ec, flags);
7232                         }
7233                                         
7234                         //
7235                         // TODO: I mailed Ravi about this, and apparently we can get rid
7236                         // of this and put it in the right place.
7237                         // 
7238                         // Handle enums here when they are in transit.
7239                         // Note that we cannot afford to hit MemberLookup in this case because
7240                         // it will fail to find any members at all
7241                         //
7242
7243                         Type expr_type = expr.Type;
7244                         if (expr is TypeExpr){
7245                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7246                                         Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type);
7247                                         return null;
7248                                 }
7249
7250                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7251                                         Enum en = TypeManager.LookupEnum (expr_type);
7252
7253                                         if (en != null) {
7254                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7255                                                 
7256                                                 if (value != null){
7257                                                         MemberCore mc = en.GetDefinition (Identifier);
7258                                                         ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7259                                                         if (oa != null) {
7260                                                                 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7261                                                         }
7262                                                         oa = en.GetObsoleteAttribute (en);
7263                                                         if (oa != null) {
7264                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7265                                                         }
7266
7267                                                         Constant c = Constantify (value, en.UnderlyingType);
7268                                                         return new EnumConstant (c, expr_type);
7269                                                 }
7270                                         } else {
7271                                                 CheckObsoleteAttribute (expr_type);
7272
7273                                                 FieldInfo fi = expr_type.GetField (Identifier);
7274                                                 if (fi != null) {
7275                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7276                                                         if (oa != null)
7277                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7278                                                 }
7279                                         }
7280                                 }
7281                         }
7282                         
7283                         if (expr_type.IsPointer){
7284                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7285                                        TypeManager.CSharpName (expr_type) + ")");
7286                                 return null;
7287                         }
7288
7289                         Expression member_lookup;
7290                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7291                         if (member_lookup == null)
7292                                 return null;
7293
7294                         if (member_lookup is TypeExpr) {
7295                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7296                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7297                                                member_lookup.Type + "' instead");
7298                                         return null;
7299                                 }
7300
7301                                 return member_lookup;
7302                         }
7303                         
7304                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7305                         if (member_lookup == null)
7306                                 return null;
7307
7308                         // The following DoResolve/DoResolveLValue will do the definite assignment
7309                         // check.
7310
7311                         if (right_side != null)
7312                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7313                         else
7314                                 member_lookup = member_lookup.DoResolve (ec);
7315
7316                         return member_lookup;
7317                 }
7318
7319                 public override Expression DoResolve (EmitContext ec)
7320                 {
7321                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7322                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7323                 }
7324
7325                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7326                 {
7327                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7328                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7329                 }
7330
7331                 public override Expression ResolveAsTypeStep (EmitContext ec)
7332                 {
7333                         string fname = null;
7334                         MemberAccess full_expr = this;
7335                         while (full_expr != null) {
7336                                 if (fname != null)
7337                                         fname = String.Concat (full_expr.Identifier, ".", fname);
7338                                 else
7339                                         fname = full_expr.Identifier;
7340
7341                                 if (full_expr.Expr is SimpleName) {
7342                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7343                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
7344                                         if (fully_qualified != null)
7345                                                 return new TypeExpression (fully_qualified, loc);
7346                                 }
7347
7348                                 full_expr = full_expr.Expr as MemberAccess;
7349                         }
7350
7351                         Expression new_expr = expr.ResolveAsTypeStep (ec);
7352
7353                         if (new_expr == null)
7354                                 return null;
7355
7356                         if (new_expr is SimpleName){
7357                                 SimpleName child_expr = (SimpleName) new_expr;
7358                                 
7359                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7360
7361                                 return new_expr.ResolveAsTypeStep (ec);
7362                         }
7363
7364                         Type expr_type = new_expr.Type;
7365                       
7366                         if (expr_type.IsPointer){
7367                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7368                                        TypeManager.CSharpName (expr_type) + ")");
7369                                 return null;
7370                         }
7371                         
7372                         Expression member_lookup;
7373                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7374                         if (member_lookup == null)
7375                                 return null;
7376
7377                         if (member_lookup is TypeExpr){
7378                                 member_lookup.Resolve (ec, ResolveFlags.Type);
7379                                 return member_lookup;
7380                         } 
7381
7382                         return null;                    
7383                 }
7384
7385                 public override void Emit (EmitContext ec)
7386                 {
7387                         throw new Exception ("Should not happen");
7388                 }
7389
7390                 public override string ToString ()
7391                 {
7392                         return expr + "." + Identifier;
7393                 }
7394         }
7395
7396         /// <summary>
7397         ///   Implements checked expressions
7398         /// </summary>
7399         public class CheckedExpr : Expression {
7400
7401                 public Expression Expr;
7402
7403                 public CheckedExpr (Expression e, Location l)
7404                 {
7405                         Expr = e;
7406                         loc = l;
7407                 }
7408
7409                 public override Expression DoResolve (EmitContext ec)
7410                 {
7411                         bool last_check = ec.CheckState;
7412                         bool last_const_check = ec.ConstantCheckState;
7413
7414                         ec.CheckState = true;
7415                         ec.ConstantCheckState = true;
7416                         Expr = Expr.Resolve (ec);
7417                         ec.CheckState = last_check;
7418                         ec.ConstantCheckState = last_const_check;
7419                         
7420                         if (Expr == null)
7421                                 return null;
7422
7423                         if (Expr is Constant)
7424                                 return Expr;
7425                         
7426                         eclass = Expr.eclass;
7427                         type = Expr.Type;
7428                         return this;
7429                 }
7430
7431                 public override void Emit (EmitContext ec)
7432                 {
7433                         bool last_check = ec.CheckState;
7434                         bool last_const_check = ec.ConstantCheckState;
7435                         
7436                         ec.CheckState = true;
7437                         ec.ConstantCheckState = true;
7438                         Expr.Emit (ec);
7439                         ec.CheckState = last_check;
7440                         ec.ConstantCheckState = last_const_check;
7441                 }
7442                 
7443         }
7444
7445         /// <summary>
7446         ///   Implements the unchecked expression
7447         /// </summary>
7448         public class UnCheckedExpr : Expression {
7449
7450                 public Expression Expr;
7451
7452                 public UnCheckedExpr (Expression e, Location l)
7453                 {
7454                         Expr = e;
7455                         loc = l;
7456                 }
7457
7458                 public override Expression DoResolve (EmitContext ec)
7459                 {
7460                         bool last_check = ec.CheckState;
7461                         bool last_const_check = ec.ConstantCheckState;
7462
7463                         ec.CheckState = false;
7464                         ec.ConstantCheckState = false;
7465                         Expr = Expr.Resolve (ec);
7466                         ec.CheckState = last_check;
7467                         ec.ConstantCheckState = last_const_check;
7468
7469                         if (Expr == null)
7470                                 return null;
7471
7472                         if (Expr is Constant)
7473                                 return Expr;
7474                         
7475                         eclass = Expr.eclass;
7476                         type = Expr.Type;
7477                         return this;
7478                 }
7479
7480                 public override void Emit (EmitContext ec)
7481                 {
7482                         bool last_check = ec.CheckState;
7483                         bool last_const_check = ec.ConstantCheckState;
7484                         
7485                         ec.CheckState = false;
7486                         ec.ConstantCheckState = false;
7487                         Expr.Emit (ec);
7488                         ec.CheckState = last_check;
7489                         ec.ConstantCheckState = last_const_check;
7490                 }
7491                 
7492         }
7493
7494         /// <summary>
7495         ///   An Element Access expression.
7496         ///
7497         ///   During semantic analysis these are transformed into 
7498         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7499         /// </summary>
7500         public class ElementAccess : Expression {
7501                 public ArrayList  Arguments;
7502                 public Expression Expr;
7503                 
7504                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7505                 {
7506                         Expr = e;
7507
7508                         loc  = l;
7509                         
7510                         if (e_list == null)
7511                                 return;
7512                         
7513                         Arguments = new ArrayList ();
7514                         foreach (Expression tmp in e_list)
7515                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7516                         
7517                 }
7518
7519                 bool CommonResolve (EmitContext ec)
7520                 {
7521                         Expr = Expr.Resolve (ec);
7522
7523                         if (Expr == null) 
7524                                 return false;
7525
7526                         if (Arguments == null)
7527                                 return false;
7528
7529                         foreach (Argument a in Arguments){
7530                                 if (!a.Resolve (ec, loc))
7531                                         return false;
7532                         }
7533
7534                         return true;
7535                 }
7536
7537                 Expression MakePointerAccess (EmitContext ec)
7538                 {
7539                         Type t = Expr.Type;
7540
7541                         if (t == TypeManager.void_ptr_type){
7542                                 Error (242, "The array index operation is not valid for void pointers");
7543                                 return null;
7544                         }
7545                         if (Arguments.Count != 1){
7546                                 Error (196, "A pointer must be indexed by a single value");
7547                                 return null;
7548                         }
7549                         Expression p;
7550
7551                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7552                         if (p == null)
7553                                 return null;
7554                         return new Indirection (p, loc).Resolve (ec);
7555                 }
7556                 
7557                 public override Expression DoResolve (EmitContext ec)
7558                 {
7559                         if (!CommonResolve (ec))
7560                                 return null;
7561
7562                         //
7563                         // We perform some simple tests, and then to "split" the emit and store
7564                         // code we create an instance of a different class, and return that.
7565                         //
7566                         // I am experimenting with this pattern.
7567                         //
7568                         Type t = Expr.Type;
7569
7570                         if (t == TypeManager.array_type){
7571                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7572                                 return null;
7573                         }
7574                         
7575                         if (t.IsArray)
7576                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7577                         else if (t.IsPointer)
7578                                 return MakePointerAccess (ec);
7579                         else
7580                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7581                 }
7582
7583                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7584                 {
7585                         if (!CommonResolve (ec))
7586                                 return null;
7587
7588                         Type t = Expr.Type;
7589                         if (t.IsArray)
7590                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7591                         else if (t.IsPointer)
7592                                 return MakePointerAccess (ec);
7593                         else
7594                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7595                 }
7596                 
7597                 public override void Emit (EmitContext ec)
7598                 {
7599                         throw new Exception ("Should never be reached");
7600                 }
7601         }
7602
7603         /// <summary>
7604         ///   Implements array access 
7605         /// </summary>
7606         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7607                 //
7608                 // Points to our "data" repository
7609                 //
7610                 ElementAccess ea;
7611
7612                 LocalTemporary temp;
7613                 bool prepared;
7614                 
7615                 public ArrayAccess (ElementAccess ea_data, Location l)
7616                 {
7617                         ea = ea_data;
7618                         eclass = ExprClass.Variable;
7619                         loc = l;
7620                 }
7621
7622                 public override Expression DoResolve (EmitContext ec)
7623                 {
7624 #if false
7625                         ExprClass eclass = ea.Expr.eclass;
7626
7627                         // As long as the type is valid
7628                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7629                               eclass == ExprClass.Value)) {
7630                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7631                                 return null;
7632                         }
7633 #endif
7634
7635                         Type t = ea.Expr.Type;
7636                         if (t.GetArrayRank () != ea.Arguments.Count){
7637                                 ea.Error (22,
7638                                           "Incorrect number of indexes for array " +
7639                                           " expected: " + t.GetArrayRank () + " got: " +
7640                                           ea.Arguments.Count);
7641                                 return null;
7642                         }
7643
7644                         type = TypeManager.GetElementType (t);
7645                         if (type.IsPointer && !ec.InUnsafe){
7646                                 UnsafeError (ea.Location);
7647                                 return null;
7648                         }
7649
7650                         foreach (Argument a in ea.Arguments){
7651                                 Type argtype = a.Type;
7652
7653                                 if (argtype == TypeManager.int32_type ||
7654                                     argtype == TypeManager.uint32_type ||
7655                                     argtype == TypeManager.int64_type ||
7656                                     argtype == TypeManager.uint64_type) {
7657                                         Constant c = a.Expr as Constant;
7658                                         if (c != null && c.IsNegative) {
7659                                                 Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)");
7660                                         }
7661                                         continue;
7662                                 }
7663
7664                                 //
7665                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7666                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7667                                 //
7668                                 // Wonder if I will run into trouble for this.
7669                                 //
7670                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7671                                 if (a.Expr == null)
7672                                         return null;
7673                         }
7674                         
7675                         eclass = ExprClass.Variable;
7676
7677                         return this;
7678                 }
7679
7680                 /// <summary>
7681                 ///    Emits the right opcode to load an object of Type `t'
7682                 ///    from an array of T
7683                 /// </summary>
7684                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7685                 {
7686                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7687                                 ig.Emit (OpCodes.Ldelem_U1);
7688                         else if (type == TypeManager.sbyte_type)
7689                                 ig.Emit (OpCodes.Ldelem_I1);
7690                         else if (type == TypeManager.short_type)
7691                                 ig.Emit (OpCodes.Ldelem_I2);
7692                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7693                                 ig.Emit (OpCodes.Ldelem_U2);
7694                         else if (type == TypeManager.int32_type)
7695                                 ig.Emit (OpCodes.Ldelem_I4);
7696                         else if (type == TypeManager.uint32_type)
7697                                 ig.Emit (OpCodes.Ldelem_U4);
7698                         else if (type == TypeManager.uint64_type)
7699                                 ig.Emit (OpCodes.Ldelem_I8);
7700                         else if (type == TypeManager.int64_type)
7701                                 ig.Emit (OpCodes.Ldelem_I8);
7702                         else if (type == TypeManager.float_type)
7703                                 ig.Emit (OpCodes.Ldelem_R4);
7704                         else if (type == TypeManager.double_type)
7705                                 ig.Emit (OpCodes.Ldelem_R8);
7706                         else if (type == TypeManager.intptr_type)
7707                                 ig.Emit (OpCodes.Ldelem_I);
7708                         else if (TypeManager.IsEnumType (type)){
7709                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7710                         } else if (type.IsValueType){
7711                                 ig.Emit (OpCodes.Ldelema, type);
7712                                 ig.Emit (OpCodes.Ldobj, type);
7713                         } else 
7714                                 ig.Emit (OpCodes.Ldelem_Ref);
7715                 }
7716
7717                 /// <summary>
7718                 ///    Returns the right opcode to store an object of Type `t'
7719                 ///    from an array of T.  
7720                 /// </summary>
7721                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7722                 {
7723                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7724                         is_stobj = false;
7725                         t = TypeManager.TypeToCoreType (t);
7726                         if (TypeManager.IsEnumType (t))
7727                                 t = TypeManager.EnumToUnderlying (t);
7728                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7729                             t == TypeManager.bool_type)
7730                                 return OpCodes.Stelem_I1;
7731                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7732                                  t == TypeManager.char_type)
7733                                 return OpCodes.Stelem_I2;
7734                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7735                                 return OpCodes.Stelem_I4;
7736                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7737                                 return OpCodes.Stelem_I8;
7738                         else if (t == TypeManager.float_type)
7739                                 return OpCodes.Stelem_R4;
7740                         else if (t == TypeManager.double_type)
7741                                 return OpCodes.Stelem_R8;
7742                         else if (t == TypeManager.intptr_type) {
7743                                 is_stobj = true;
7744                                 return OpCodes.Stobj;
7745                         } else if (t.IsValueType) {
7746                                 is_stobj = true;
7747                                 return OpCodes.Stobj;
7748                         } else
7749                                 return OpCodes.Stelem_Ref;
7750                 }
7751
7752                 MethodInfo FetchGetMethod ()
7753                 {
7754                         ModuleBuilder mb = CodeGen.Module.Builder;
7755                         int arg_count = ea.Arguments.Count;
7756                         Type [] args = new Type [arg_count];
7757                         MethodInfo get;
7758                         
7759                         for (int i = 0; i < arg_count; i++){
7760                                 //args [i++] = a.Type;
7761                                 args [i] = TypeManager.int32_type;
7762                         }
7763                         
7764                         get = mb.GetArrayMethod (
7765                                 ea.Expr.Type, "Get",
7766                                 CallingConventions.HasThis |
7767                                 CallingConventions.Standard,
7768                                 type, args);
7769                         return get;
7770                 }
7771                                 
7772
7773                 MethodInfo FetchAddressMethod ()
7774                 {
7775                         ModuleBuilder mb = CodeGen.Module.Builder;
7776                         int arg_count = ea.Arguments.Count;
7777                         Type [] args = new Type [arg_count];
7778                         MethodInfo address;
7779                         Type ret_type;
7780                         
7781                         ret_type = TypeManager.GetReferenceType (type);
7782                         
7783                         for (int i = 0; i < arg_count; i++){
7784                                 //args [i++] = a.Type;
7785                                 args [i] = TypeManager.int32_type;
7786                         }
7787                         
7788                         address = mb.GetArrayMethod (
7789                                 ea.Expr.Type, "Address",
7790                                 CallingConventions.HasThis |
7791                                 CallingConventions.Standard,
7792                                 ret_type, args);
7793
7794                         return address;
7795                 }
7796
7797                 //
7798                 // Load the array arguments into the stack.
7799                 //
7800                 // If we have been requested to cache the values (cached_locations array
7801                 // initialized), then load the arguments the first time and store them
7802                 // in locals.  otherwise load from local variables.
7803                 //
7804                 void LoadArrayAndArguments (EmitContext ec)
7805                 {
7806                         ILGenerator ig = ec.ig;
7807                         
7808                         ea.Expr.Emit (ec);
7809                         foreach (Argument a in ea.Arguments){
7810                                 Type argtype = a.Expr.Type;
7811                                 
7812                                 a.Expr.Emit (ec);
7813                                 
7814                                 if (argtype == TypeManager.int64_type)
7815                                         ig.Emit (OpCodes.Conv_Ovf_I);
7816                                 else if (argtype == TypeManager.uint64_type)
7817                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7818                         }
7819                 }
7820
7821                 public void Emit (EmitContext ec, bool leave_copy)
7822                 {
7823                         int rank = ea.Expr.Type.GetArrayRank ();
7824                         ILGenerator ig = ec.ig;
7825
7826                         if (!prepared) {
7827                                 LoadArrayAndArguments (ec);
7828                                 
7829                                 if (rank == 1)
7830                                         EmitLoadOpcode (ig, type);
7831                                 else {
7832                                         MethodInfo method;
7833                                         
7834                                         method = FetchGetMethod ();
7835                                         ig.Emit (OpCodes.Call, method);
7836                                 }
7837                         } else
7838                                 LoadFromPtr (ec.ig, this.type);
7839                         
7840                         if (leave_copy) {
7841                                 ec.ig.Emit (OpCodes.Dup);
7842                                 temp = new LocalTemporary (ec, this.type);
7843                                 temp.Store (ec);
7844                         }
7845                 }
7846                 
7847                 public override void Emit (EmitContext ec)
7848                 {
7849                         Emit (ec, false);
7850                 }
7851
7852                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7853                 {
7854                         int rank = ea.Expr.Type.GetArrayRank ();
7855                         ILGenerator ig = ec.ig;
7856                         Type t = source.Type;
7857                         prepared = prepare_for_load;
7858
7859                         if (prepare_for_load) {
7860                                 AddressOf (ec, AddressOp.LoadStore);
7861                                 ec.ig.Emit (OpCodes.Dup);
7862                                 source.Emit (ec);
7863                                 if (leave_copy) {
7864                                         ec.ig.Emit (OpCodes.Dup);
7865                                         temp = new LocalTemporary (ec, this.type);
7866                                         temp.Store (ec);
7867                                 }
7868                                 StoreFromPtr (ec.ig, t);
7869                                 
7870                                 if (temp != null)
7871                                         temp.Emit (ec);
7872                                 
7873                                 return;
7874                         }
7875                         
7876                         LoadArrayAndArguments (ec);
7877
7878                         if (rank == 1) {
7879                                 bool is_stobj;
7880                                 OpCode op = GetStoreOpcode (t, out is_stobj);
7881                                 //
7882                                 // The stobj opcode used by value types will need
7883                                 // an address on the stack, not really an array/array
7884                                 // pair
7885                                 //
7886                                 if (is_stobj)
7887                                         ig.Emit (OpCodes.Ldelema, t);
7888                                 
7889                                 source.Emit (ec);
7890                                 if (leave_copy) {
7891                                         ec.ig.Emit (OpCodes.Dup);
7892                                         temp = new LocalTemporary (ec, this.type);
7893                                         temp.Store (ec);
7894                                 }
7895                                 
7896                                 if (is_stobj)
7897                                         ig.Emit (OpCodes.Stobj, t);
7898                                 else
7899                                         ig.Emit (op);
7900                         } else {
7901                                 ModuleBuilder mb = CodeGen.Module.Builder;
7902                                 int arg_count = ea.Arguments.Count;
7903                                 Type [] args = new Type [arg_count + 1];
7904                                 MethodInfo set;
7905                                 
7906                                 source.Emit (ec);
7907                                 if (leave_copy) {
7908                                         ec.ig.Emit (OpCodes.Dup);
7909                                         temp = new LocalTemporary (ec, this.type);
7910                                         temp.Store (ec);
7911                                 }
7912                                 
7913                                 for (int i = 0; i < arg_count; i++){
7914                                         //args [i++] = a.Type;
7915                                         args [i] = TypeManager.int32_type;
7916                                 }
7917
7918                                 args [arg_count] = type;
7919                                 
7920                                 set = mb.GetArrayMethod (
7921                                         ea.Expr.Type, "Set",
7922                                         CallingConventions.HasThis |
7923                                         CallingConventions.Standard,
7924                                         TypeManager.void_type, args);
7925                                 
7926                                 ig.Emit (OpCodes.Call, set);
7927                         }
7928                         
7929                         if (temp != null)
7930                                 temp.Emit (ec);
7931                 }
7932
7933                 public void AddressOf (EmitContext ec, AddressOp mode)
7934                 {
7935                         int rank = ea.Expr.Type.GetArrayRank ();
7936                         ILGenerator ig = ec.ig;
7937
7938                         LoadArrayAndArguments (ec);
7939
7940                         if (rank == 1){
7941                                 ig.Emit (OpCodes.Ldelema, type);
7942                         } else {
7943                                 MethodInfo address = FetchAddressMethod ();
7944                                 ig.Emit (OpCodes.Call, address);
7945                         }
7946                 }
7947         }
7948
7949         
7950         class Indexers {
7951                 public ArrayList Properties;
7952                 static Hashtable map;
7953
7954                 public struct Indexer {
7955                         public readonly Type Type;
7956                         public readonly MethodInfo Getter, Setter;
7957
7958                         public Indexer (Type type, MethodInfo get, MethodInfo set)
7959                         {
7960                                 this.Type = type;
7961                                 this.Getter = get;
7962                                 this.Setter = set;
7963                         }
7964                 }
7965
7966                 static Indexers ()
7967                 {
7968                         map = new Hashtable ();
7969                 }
7970
7971                 Indexers ()
7972                 {
7973                         Properties = new ArrayList ();
7974                 }
7975                                 
7976                 void Append (MemberInfo [] mi)
7977                 {
7978                         foreach (PropertyInfo property in mi){
7979                                 MethodInfo get, set;
7980                                 
7981                                 get = property.GetGetMethod (true);
7982                                 set = property.GetSetMethod (true);
7983                                 Properties.Add (new Indexer (property.PropertyType, get, set));
7984                         }
7985                 }
7986
7987                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7988                 {
7989                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7990
7991                         MemberInfo [] mi = TypeManager.MemberLookup (
7992                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7993                                 BindingFlags.Public | BindingFlags.Instance |
7994                                 BindingFlags.DeclaredOnly, p_name, null);
7995
7996                         if (mi == null || mi.Length == 0)
7997                                 return null;
7998
7999                         return mi;
8000                 }
8001                 
8002                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8003                 {
8004                         Indexers ix = (Indexers) map [lookup_type];
8005
8006                         if (ix != null)
8007                                 return ix;
8008
8009                         Type copy = lookup_type;
8010                         while (copy != TypeManager.object_type && copy != null){
8011                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8012
8013                                 if (mi != null){
8014                                         if (ix == null)
8015                                                 ix = new Indexers ();
8016
8017                                         ix.Append (mi);
8018                                 }
8019                                         
8020                                 copy = copy.BaseType;
8021                         }
8022
8023                         if (!lookup_type.IsInterface)
8024                                 return ix;
8025
8026                         TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
8027                         if (ifaces != null) {
8028                                 foreach (TypeExpr iface in ifaces) {
8029                                         Type itype = iface.Type;
8030                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8031                                         if (mi != null){
8032                                                 if (ix == null)
8033                                                         ix = new Indexers ();
8034                                         
8035                                                 ix.Append (mi);
8036                                         }
8037                                 }
8038                         }
8039
8040                         return ix;
8041                 }
8042         }
8043
8044         /// <summary>
8045         ///   Expressions that represent an indexer call.
8046         /// </summary>
8047         public class IndexerAccess : Expression, IAssignMethod {
8048                 //
8049                 // Points to our "data" repository
8050                 //
8051                 MethodInfo get, set;
8052                 ArrayList set_arguments;
8053                 bool is_base_indexer;
8054
8055                 protected Type indexer_type;
8056                 protected Type current_type;
8057                 protected Expression instance_expr;
8058                 protected ArrayList arguments;
8059                 
8060                 public IndexerAccess (ElementAccess ea, Location loc)
8061                         : this (ea.Expr, false, loc)
8062                 {
8063                         this.arguments = ea.Arguments;
8064                 }
8065
8066                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8067                                          Location loc)
8068                 {
8069                         this.instance_expr = instance_expr;
8070                         this.is_base_indexer = is_base_indexer;
8071                         this.eclass = ExprClass.Value;
8072                         this.loc = loc;
8073                 }
8074
8075                 protected virtual bool CommonResolve (EmitContext ec)
8076                 {
8077                         indexer_type = instance_expr.Type;
8078                         current_type = ec.ContainerType;
8079
8080                         return true;
8081                 }
8082
8083                 public override Expression DoResolve (EmitContext ec)
8084                 {
8085                         ArrayList AllGetters = new ArrayList();
8086                         if (!CommonResolve (ec))
8087                                 return null;
8088
8089                         //
8090                         // Step 1: Query for all `Item' *properties*.  Notice
8091                         // that the actual methods are pointed from here.
8092                         //
8093                         // This is a group of properties, piles of them.  
8094
8095                         bool found_any = false, found_any_getters = false;
8096                         Type lookup_type = indexer_type;
8097
8098                         Indexers ilist;
8099                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8100                         if (ilist != null) {
8101                                 found_any = true;
8102                                 if (ilist.Properties != null) {
8103                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8104                                                 if (ix.Getter != null)
8105                                                         AllGetters.Add(ix.Getter);
8106                                         }
8107                                 }
8108                         }
8109
8110                         if (AllGetters.Count > 0) {
8111                                 found_any_getters = true;
8112                                 get = (MethodInfo) Invocation.OverloadResolve (
8113                                         ec, new MethodGroupExpr (AllGetters, loc),
8114                                         arguments, false, loc);
8115                         }
8116
8117                         if (!found_any) {
8118                                 Report.Error (21, loc,
8119                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8120                                               "' does not have any indexers defined");
8121                                 return null;
8122                         }
8123
8124                         if (!found_any_getters) {
8125                                 Error (154, "indexer can not be used in this context, because " +
8126                                        "it lacks a `get' accessor");
8127                                 return null;
8128                         }
8129
8130                         if (get == null) {
8131                                 Error (1501, "No Overload for method `this' takes `" +
8132                                        arguments.Count + "' arguments");
8133                                 return null;
8134                         }
8135
8136                         //
8137                         // Only base will allow this invocation to happen.
8138                         //
8139                         if (get.IsAbstract && this is BaseIndexerAccess){
8140                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8141                                 return null;
8142                         }
8143
8144                         type = get.ReturnType;
8145                         if (type.IsPointer && !ec.InUnsafe){
8146                                 UnsafeError (loc);
8147                                 return null;
8148                         }
8149                         
8150                         eclass = ExprClass.IndexerAccess;
8151                         return this;
8152                 }
8153
8154                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8155                 {
8156                         ArrayList AllSetters = new ArrayList();
8157                         if (!CommonResolve (ec))
8158                                 return null;
8159
8160                         bool found_any = false, found_any_setters = false;
8161
8162                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8163                         if (ilist != null) {
8164                                 found_any = true;
8165                                 if (ilist.Properties != null) {
8166                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8167                                                 if (ix.Setter != null)
8168                                                         AllSetters.Add(ix.Setter);
8169                                         }
8170                                 }
8171                         }
8172                         if (AllSetters.Count > 0) {
8173                                 found_any_setters = true;
8174                                 set_arguments = (ArrayList) arguments.Clone ();
8175                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8176                                 set = (MethodInfo) Invocation.OverloadResolve (
8177                                         ec, new MethodGroupExpr (AllSetters, loc),
8178                                         set_arguments, false, loc);
8179                         }
8180
8181                         if (!found_any) {
8182                                 Report.Error (21, loc,
8183                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8184                                               "' does not have any indexers defined");
8185                                 return null;
8186                         }
8187
8188                         if (!found_any_setters) {
8189                                 Error (154, "indexer can not be used in this context, because " +
8190                                        "it lacks a `set' accessor");
8191                                 return null;
8192                         }
8193
8194                         if (set == null) {
8195                                 Error (1501, "No Overload for method `this' takes `" +
8196                                        arguments.Count + "' arguments");
8197                                 return null;
8198                         }
8199
8200                         //
8201                         // Only base will allow this invocation to happen.
8202                         //
8203                         if (set.IsAbstract && this is BaseIndexerAccess){
8204                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8205                                 return null;
8206                         }
8207
8208                         //
8209                         // Now look for the actual match in the list of indexers to set our "return" type
8210                         //
8211                         type = TypeManager.void_type;   // default value
8212                         foreach (Indexers.Indexer ix in ilist.Properties){
8213                                 if (ix.Setter == set){
8214                                         type = ix.Type;
8215                                         break;
8216                                 }
8217                         }
8218                         
8219                         eclass = ExprClass.IndexerAccess;
8220                         return this;
8221                 }
8222                 
8223                 bool prepared = false;
8224                 LocalTemporary temp;
8225                 
8226                 public void Emit (EmitContext ec, bool leave_copy)
8227                 {
8228                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8229                         if (leave_copy) {
8230                                 ec.ig.Emit (OpCodes.Dup);
8231                                 temp = new LocalTemporary (ec, Type);
8232                                 temp.Store (ec);
8233                         }
8234                 }
8235                 
8236                 //
8237                 // source is ignored, because we already have a copy of it from the
8238                 // LValue resolution and we have already constructed a pre-cached
8239                 // version of the arguments (ea.set_arguments);
8240                 //
8241                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8242                 {
8243                         prepared = prepare_for_load;
8244                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8245                         
8246                         if (prepared) {
8247                                 source.Emit (ec);
8248                                 if (leave_copy) {
8249                                         ec.ig.Emit (OpCodes.Dup);
8250                                         temp = new LocalTemporary (ec, Type);
8251                                         temp.Store (ec);
8252                                 }
8253                         } else if (leave_copy) {
8254                                 temp = new LocalTemporary (ec, Type);
8255                                 source.Emit (ec);
8256                                 temp.Store (ec);
8257                                 a.Expr = temp;
8258                         }
8259                         
8260                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8261                         
8262                         if (temp != null)
8263                                 temp.Emit (ec);
8264                 }
8265                 
8266                 
8267                 public override void Emit (EmitContext ec)
8268                 {
8269                         Emit (ec, false);
8270                 }
8271         }
8272
8273         /// <summary>
8274         ///   The base operator for method names
8275         /// </summary>
8276         public class BaseAccess : Expression {
8277                 string member;
8278                 
8279                 public BaseAccess (string member, Location l)
8280                 {
8281                         this.member = member;
8282                         loc = l;
8283                 }
8284
8285                 public override Expression DoResolve (EmitContext ec)
8286                 {
8287                         Expression c = CommonResolve (ec);
8288
8289                         if (c == null)
8290                                 return null;
8291
8292                         //
8293                         // MethodGroups use this opportunity to flag an error on lacking ()
8294                         //
8295                         if (!(c is MethodGroupExpr))
8296                                 return c.Resolve (ec);
8297                         return c;
8298                 }
8299
8300                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8301                 {
8302                         Expression c = CommonResolve (ec);
8303
8304                         if (c == null)
8305                                 return null;
8306
8307                         //
8308                         // MethodGroups use this opportunity to flag an error on lacking ()
8309                         //
8310                         if (! (c is MethodGroupExpr))
8311                                 return c.DoResolveLValue (ec, right_side);
8312
8313                         return c;
8314                 }
8315
8316                 Expression CommonResolve (EmitContext ec)
8317                 {
8318                         Expression member_lookup;
8319                         Type current_type = ec.ContainerType;
8320                         Type base_type = current_type.BaseType;
8321                         Expression e;
8322
8323                         if (ec.IsStatic){
8324                                 Error (1511, "Keyword base is not allowed in static method");
8325                                 return null;
8326                         }
8327
8328                         if (ec.IsFieldInitializer){
8329                                 Error (1512, "Keyword base is not available in the current context");
8330                                 return null;
8331                         }
8332                         
8333                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
8334                                                       AllMemberTypes, AllBindingFlags, loc);
8335                         if (member_lookup == null) {
8336                                 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
8337                                 return null;
8338                         }
8339
8340                         Expression left;
8341                         
8342                         if (ec.IsStatic)
8343                                 left = new TypeExpression (base_type, loc);
8344                         else
8345                                 left = ec.GetThis (loc);
8346                         
8347                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8348
8349                         if (e is PropertyExpr){
8350                                 PropertyExpr pe = (PropertyExpr) e;
8351
8352                                 pe.IsBase = true;
8353                         }
8354                         
8355                         if (e is MethodGroupExpr)
8356                                 ((MethodGroupExpr) e).IsBase = true;
8357
8358                         return e;
8359                 }
8360
8361                 public override void Emit (EmitContext ec)
8362                 {
8363                         throw new Exception ("Should never be called"); 
8364                 }
8365         }
8366
8367         /// <summary>
8368         ///   The base indexer operator
8369         /// </summary>
8370         public class BaseIndexerAccess : IndexerAccess {
8371                 public BaseIndexerAccess (ArrayList args, Location loc)
8372                         : base (null, true, loc)
8373                 {
8374                         arguments = new ArrayList ();
8375                         foreach (Expression tmp in args)
8376                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8377                 }
8378
8379                 protected override bool CommonResolve (EmitContext ec)
8380                 {
8381                         instance_expr = ec.GetThis (loc);
8382
8383                         current_type = ec.ContainerType.BaseType;
8384                         indexer_type = current_type;
8385
8386                         foreach (Argument a in arguments){
8387                                 if (!a.Resolve (ec, loc))
8388                                         return false;
8389                         }
8390
8391                         return true;
8392                 }
8393         }
8394         
8395         /// <summary>
8396         ///   This class exists solely to pass the Type around and to be a dummy
8397         ///   that can be passed to the conversion functions (this is used by
8398         ///   foreach implementation to typecast the object return value from
8399         ///   get_Current into the proper type.  All code has been generated and
8400         ///   we only care about the side effect conversions to be performed
8401         ///
8402         ///   This is also now used as a placeholder where a no-action expression
8403         ///   is needed (the `New' class).
8404         /// </summary>
8405         public class EmptyExpression : Expression {
8406                 public static readonly EmptyExpression Null = new EmptyExpression ();
8407
8408                 // TODO: should be protected
8409                 public EmptyExpression ()
8410                 {
8411                         type = TypeManager.object_type;
8412                         eclass = ExprClass.Value;
8413                         loc = Location.Null;
8414                 }
8415
8416                 public EmptyExpression (Type t)
8417                 {
8418                         type = t;
8419                         eclass = ExprClass.Value;
8420                         loc = Location.Null;
8421                 }
8422                 
8423                 public override Expression DoResolve (EmitContext ec)
8424                 {
8425                         return this;
8426                 }
8427
8428                 public override void Emit (EmitContext ec)
8429                 {
8430                         // nothing, as we only exist to not do anything.
8431                 }
8432
8433                 //
8434                 // This is just because we might want to reuse this bad boy
8435                 // instead of creating gazillions of EmptyExpressions.
8436                 // (CanImplicitConversion uses it)
8437                 //
8438                 public void SetType (Type t)
8439                 {
8440                         type = t;
8441                 }
8442         }
8443
8444         public class UserCast : Expression {
8445                 MethodBase method;
8446                 Expression source;
8447                 
8448                 public UserCast (MethodInfo method, Expression source, Location l)
8449                 {
8450                         this.method = method;
8451                         this.source = source;
8452                         type = method.ReturnType;
8453                         eclass = ExprClass.Value;
8454                         loc = l;
8455                 }
8456
8457                 public override Expression DoResolve (EmitContext ec)
8458                 {
8459                         //
8460                         // We are born fully resolved
8461                         //
8462                         return this;
8463                 }
8464
8465                 public override void Emit (EmitContext ec)
8466                 {
8467                         ILGenerator ig = ec.ig;
8468
8469                         source.Emit (ec);
8470                         
8471                         if (method is MethodInfo)
8472                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8473                         else
8474                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8475
8476                 }
8477         }
8478
8479         // <summary>
8480         //   This class is used to "construct" the type during a typecast
8481         //   operation.  Since the Type.GetType class in .NET can parse
8482         //   the type specification, we just use this to construct the type
8483         //   one bit at a time.
8484         // </summary>
8485         public class ComposedCast : TypeExpr {
8486                 Expression left;
8487                 string dim;
8488                 
8489                 public ComposedCast (Expression left, string dim, Location l)
8490                 {
8491                         this.left = left;
8492                         this.dim = dim;
8493                         loc = l;
8494                 }
8495
8496                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8497                 {
8498                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8499                         if (lexpr == null)
8500                                 return null;
8501
8502                         Type ltype = lexpr.ResolveType (ec);
8503
8504                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8505                                 Report.Error (1547, Location,
8506                                               "Keyword 'void' cannot be used in this context");
8507                                 return null;
8508                         }
8509
8510                         //
8511                         // ltype.Fullname is already fully qualified, so we can skip
8512                         // a lot of probes, and go directly to TypeManager.LookupType
8513                         //
8514                         string cname = ltype.FullName + dim;
8515                         type = TypeManager.LookupTypeDirect (cname);
8516                         if (type == null){
8517                                 //
8518                                 // For arrays of enumerations we are having a problem
8519                                 // with the direct lookup.  Need to investigate.
8520                                 //
8521                                 // For now, fall back to the full lookup in that case.
8522                                 //
8523                                 type = RootContext.LookupType (
8524                                         ec.DeclSpace, cname, false, loc);
8525
8526                                 if (type == null)
8527                                         return null;
8528                         }
8529
8530                         if (!ec.InUnsafe && type.IsPointer){
8531                                 UnsafeError (loc);
8532                                 return null;
8533                         }
8534                         
8535                         eclass = ExprClass.Type;
8536                         return this;
8537                 }
8538
8539                 public override string Name {
8540                         get {
8541                                 return left + dim;
8542                         }
8543                 }
8544         }
8545
8546         //
8547         // This class is used to represent the address of an array, used
8548         // only by the Fixed statement, this is like the C "&a [0]" construct.
8549         //
8550         public class ArrayPtr : Expression {
8551                 Expression array;
8552                 
8553                 public ArrayPtr (Expression array, Location l)
8554                 {
8555                         Type array_type = TypeManager.GetElementType (array.Type);
8556
8557                         this.array = array;
8558
8559                         type = TypeManager.GetPointerType (array_type);
8560                         eclass = ExprClass.Value;
8561                         loc = l;
8562                 }
8563
8564                 public override void Emit (EmitContext ec)
8565                 {
8566                         ILGenerator ig = ec.ig;
8567                         
8568                         array.Emit (ec);
8569                         IntLiteral.EmitInt (ig, 0);
8570                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8571                 }
8572
8573                 public override Expression DoResolve (EmitContext ec)
8574                 {
8575                         //
8576                         // We are born fully resolved
8577                         //
8578                         return this;
8579                 }
8580         }
8581
8582         //
8583         // Used by the fixed statement
8584         //
8585         public class StringPtr : Expression {
8586                 LocalBuilder b;
8587                 
8588                 public StringPtr (LocalBuilder b, Location l)
8589                 {
8590                         this.b = b;
8591                         eclass = ExprClass.Value;
8592                         type = TypeManager.char_ptr_type;
8593                         loc = l;
8594                 }
8595
8596                 public override Expression DoResolve (EmitContext ec)
8597                 {
8598                         // This should never be invoked, we are born in fully
8599                         // initialized state.
8600
8601                         return this;
8602                 }
8603
8604                 public override void Emit (EmitContext ec)
8605                 {
8606                         ILGenerator ig = ec.ig;
8607
8608                         ig.Emit (OpCodes.Ldloc, b);
8609                         ig.Emit (OpCodes.Conv_I);
8610                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8611                         ig.Emit (OpCodes.Add);
8612                 }
8613         }
8614         
8615         //
8616         // Implements the `stackalloc' keyword
8617         //
8618         public class StackAlloc : Expression {
8619                 Type otype;
8620                 Expression t;
8621                 Expression count;
8622                 
8623                 public StackAlloc (Expression type, Expression count, Location l)
8624                 {
8625                         t = type;
8626                         this.count = count;
8627                         loc = l;
8628                 }
8629
8630                 public override Expression DoResolve (EmitContext ec)
8631                 {
8632                         count = count.Resolve (ec);
8633                         if (count == null)
8634                                 return null;
8635                         
8636                         if (count.Type != TypeManager.int32_type){
8637                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8638                                 if (count == null)
8639                                         return null;
8640                         }
8641
8642                         Constant c = count as Constant;
8643                         if (c != null && c.IsNegative) {
8644                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8645                                 return null;
8646                         }
8647
8648                         if (ec.CurrentBranching.InCatch () ||
8649                             ec.CurrentBranching.InFinally (true)) {
8650                                 Error (255,
8651                                        "stackalloc can not be used in a catch or finally block");
8652                                 return null;
8653                         }
8654
8655                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8656                         if (texpr == null)
8657                                 return null;
8658
8659                         otype = texpr.ResolveType (ec);
8660
8661                         if (!TypeManager.VerifyUnManaged (otype, loc))
8662                                 return null;
8663
8664                         type = TypeManager.GetPointerType (otype);
8665                         eclass = ExprClass.Value;
8666
8667                         return this;
8668                 }
8669
8670                 public override void Emit (EmitContext ec)
8671                 {
8672                         int size = GetTypeSize (otype);
8673                         ILGenerator ig = ec.ig;
8674                                 
8675                         if (size == 0)
8676                                 ig.Emit (OpCodes.Sizeof, otype);
8677                         else
8678                                 IntConstant.EmitInt (ig, size);
8679                         count.Emit (ec);
8680                         ig.Emit (OpCodes.Mul);
8681                         ig.Emit (OpCodes.Localloc);
8682                 }
8683         }
8684 }