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