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