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