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