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