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