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