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