2002-01-01 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 //
10 #define USE_OLD
11
12 namespace Mono.CSharp {
13         using System;
14         using System.Collections;
15         using System.Diagnostics;
16         using System.Reflection;
17         using System.Reflection.Emit;
18         using System.Text;
19
20         /// <summary>
21         ///   This is just a helper class, it is generated by Unary, UnaryMutator
22         ///   when an overloaded method has been found.  It just emits the code for a
23         ///   static call.
24         /// </summary>
25         public class StaticCallExpr : ExpressionStatement {
26                 ArrayList args;
27                 MethodInfo mi;
28
29                 StaticCallExpr (MethodInfo m, ArrayList a)
30                 {
31                         mi = m;
32                         args = a;
33
34                         type = m.ReturnType;
35                         eclass = ExprClass.Value;
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);
69                 }
70
71                 public override void EmitStatement (EmitContext ec)
72                 {
73                         Emit (ec);
74                         if (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                 Operator   oper;
95                 Expression expr;
96                 Location   loc;
97                 
98                 public Unary (Operator op, Expression expr, Location loc)
99                 {
100                         this.oper = op;
101                         this.expr = expr;
102                         this.loc = loc;
103                 }
104
105                 public Expression Expr {
106                         get {
107                                 return expr;
108                         }
109
110                         set {
111                                 expr = value;
112                         }
113                 }
114
115                 public Operator Oper {
116                         get {
117                                 return oper;
118                         }
119
120                         set {
121                                 oper = value;
122                         }
123                 }
124
125                 /// <summary>
126                 ///   Returns a stringified representation of the Operator
127                 /// </summary>
128                 string OperName ()
129                 {
130                         switch (oper){
131                         case Operator.UnaryPlus:
132                                 return "+";
133                         case Operator.UnaryNegation:
134                                 return "-";
135                         case Operator.LogicalNot:
136                                 return "!";
137                         case Operator.OnesComplement:
138                                 return "~";
139                         case Operator.AddressOf:
140                                 return "&";
141                         case Operator.Indirection:
142                                 return "*";
143                         }
144
145                         return oper.ToString ();
146                 }
147
148                 static string [] oper_names;
149
150                 static Unary ()
151                 {
152                         oper_names = new string [(int)Operator.TOP];
153
154                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
155                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
156                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
157                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
158                         oper_names [(int) Operator.Indirection] = "op_Indirection";
159                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
160                 }
161
162                 void error23 (Type t)
163                 {
164                         Report.Error (
165                                 23, loc, "Operator " + OperName () +
166                                 " cannot be applied to operand of type `" +
167                                 TypeManager.CSharpName (t) + "'");
168                 }
169
170                 /// <remarks>
171                 ///   The result has been already resolved:
172                 ///
173                 ///   FIXME: a minus constant -128 sbyte cant be turned into a
174                 ///   constant byte.
175                 /// </remarks>
176                 static Expression TryReduceNegative (Expression expr)
177                 {
178                         Expression e = null;
179                         
180                         if (expr is IntConstant)
181                                 e = new IntConstant (-((IntConstant) expr).Value);
182                         else if (expr is UIntConstant)
183                                 e = new LongConstant (-((UIntConstant) expr).Value);
184                         else if (expr is LongConstant)
185                                 e = new LongConstant (-((LongConstant) expr).Value);
186                         else if (expr is FloatConstant)
187                                 e = new FloatConstant (-((FloatConstant) expr).Value);
188                         else if (expr is DoubleConstant)
189                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);
190                         else if (expr is DecimalConstant)
191                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);
192                         else if (expr is ShortConstant)
193                                 e = new IntConstant (-((ShortConstant) expr).Value);
194                         else if (expr is UShortConstant)
195                                 e = new IntConstant (-((UShortConstant) expr).Value);
196
197                         return e;
198                 }
199                 
200                 Expression Reduce (EmitContext ec, Expression e)
201                 {
202                         Type expr_type = e.Type;
203                         
204                         switch (oper){
205                         case Operator.UnaryPlus:
206                                 return e;
207                                 
208                         case Operator.UnaryNegation:
209                                 return TryReduceNegative (e);
210                                 
211                         case Operator.LogicalNot:
212                                 if (expr_type != TypeManager.bool_type) {
213                                         error23 (expr_type);
214                                         return null;
215                                 }
216                                 
217                                 BoolConstant b = (BoolConstant) e;
218                                 return new BoolConstant (!(b.Value));
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                                         error23 (expr_type);
227                                         return null;
228                                 }
229
230                                 if (e is EnumConstant){
231                                         EnumConstant enum_constant = (EnumConstant) e;
232                                         
233                                         Expression reduced = Reduce (ec, enum_constant.Child);
234
235                                         return new EnumConstant ((Constant) reduced, enum_constant.Type);
236                                 }
237
238                                 if (expr_type == TypeManager.int32_type)
239                                         return new IntConstant (~ ((IntConstant) e).Value);
240                                 if (expr_type == TypeManager.uint32_type)
241                                         return new UIntConstant (~ ((UIntConstant) e).Value);
242                                 if (expr_type == TypeManager.int64_type)
243                                         return new LongConstant (~ ((LongConstant) e).Value);
244                                 if (expr_type == TypeManager.uint64_type)
245                                         return new ULongConstant (~ ((ULongConstant) e).Value);
246
247                                 throw new Exception (
248                                         "FIXME: Implement constant OnesComplement of:" +
249                                         expr_type);
250                         }
251                         throw new Exception ("Can not constant fold");
252                 }
253
254                 Expression ResolveOperator (EmitContext ec)
255                 {
256                         Type expr_type = expr.Type;
257
258                         //
259                         // Step 1: Perform Operator Overload location
260                         //
261                         Expression mg;
262                         string op_name;
263                         
264                         op_name = oper_names [(int) oper];
265
266                         mg = MemberLookup (ec, expr_type, op_name, false, loc);
267                         
268                         if (mg == null && expr_type.BaseType != null)
269                                 mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc);
270                         
271                         if (mg != null) {
272                                 Expression e = StaticCallExpr.MakeSimpleCall (
273                                         ec, (MethodGroupExpr) mg, expr, loc);
274
275                                 if (e == null){
276                                         error23 (expr_type);
277                                         return null;
278                                 }
279                                 
280                                 return e;
281                         }
282
283                         // Only perform numeric promotions on:
284                         // +, - 
285
286                         if (expr_type == null)
287                                 return null;
288                         
289                         //
290                         // Step 2: Default operations on CLI native types.
291                         //
292                         if (expr is Constant)
293                                 return Reduce (ec, expr);
294
295                         if (oper == Operator.LogicalNot){
296                                 if (expr_type != TypeManager.bool_type) {
297                                         error23 (expr.Type);
298                                         return null;
299                                 }
300                                 
301                                 type = TypeManager.bool_type;
302                                 return this;
303                         }
304
305                         if (oper == Operator.OnesComplement) {
306                                 if (!((expr_type == TypeManager.int32_type) ||
307                                       (expr_type == TypeManager.uint32_type) ||
308                                       (expr_type == TypeManager.int64_type) ||
309                                       (expr_type == TypeManager.uint64_type) ||
310                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
311                                         error23 (expr.Type);
312                                         return null;
313                                 }
314                                 type = expr_type;
315                                 return this;
316                         }
317
318                         if (oper == Operator.UnaryPlus) {
319                                 //
320                                 // A plus in front of something is just a no-op, so return the child.
321                                 //
322                                 return expr;
323                         }
324
325                         //
326                         // Deals with -literals
327                         // int     operator- (int x)
328                         // long    operator- (long x)
329                         // float   operator- (float f)
330                         // double  operator- (double d)
331                         // decimal operator- (decimal d)
332                         //
333                         if (oper == Operator.UnaryNegation){
334                                 Expression e = null;
335
336                                 //
337                                 // perform numeric promotions to int,
338                                 // long, double.
339                                 //
340                                 //
341                                 // The following is inneficient, because we call
342                                 // ConvertImplicit too many times.
343                                 //
344                                 // It is also not clear if we should convert to Float
345                                 // or Double initially.
346                                 //
347                                 if (expr_type == TypeManager.uint32_type){
348                                         //
349                                         // FIXME: handle exception to this rule that
350                                         // permits the int value -2147483648 (-2^31) to
351                                         // bt wrote as a decimal interger literal
352                                         //
353                                         type = TypeManager.int64_type;
354                                         expr = ConvertImplicit (ec, expr, type, loc);
355                                         return this;
356                                 }
357
358                                 if (expr_type == TypeManager.uint64_type){
359                                         //
360                                         // FIXME: Handle exception of `long value'
361                                         // -92233720368547758087 (-2^63) to be wrote as
362                                         // decimal integer literal.
363                                         //
364                                         error23 (expr_type);
365                                         return null;
366                                 }
367
368                                 if (expr_type == TypeManager.float_type){
369                                         type = expr_type;
370                                         return this;
371                                 }
372                                 
373                                 e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc);
374                                 if (e != null){
375                                         expr = e;
376                                         type = e.Type;
377                                         return this;
378                                 } 
379
380                                 e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc);
381                                 if (e != null){
382                                         expr = e;
383                                         type = e.Type;
384                                         return this;
385                                 }
386
387                                 e = ConvertImplicit (ec, expr, TypeManager.double_type, loc);
388                                 if (e != null){
389                                         expr = e;
390                                         type = e.Type;
391                                         return this;
392                                 }
393
394                                 error23 (expr_type);
395                                 return null;
396                         }
397
398                         if (oper == Operator.AddressOf){
399                                 if (expr.eclass != ExprClass.Variable){
400                                         Error (211, loc, "Cannot take the address of non-variables");
401                                         return null;
402                                 }
403                                 type = Type.GetType (expr.Type.ToString () + "*");
404
405                                 return this;
406                         }
407                         
408                         Error (187, loc, "No such operator '" + OperName () + "' defined for type '" +
409                                TypeManager.CSharpName (expr_type) + "'");
410                         return null;
411                 }
412
413                 public override Expression DoResolve (EmitContext ec)
414                 {
415                         expr = expr.Resolve (ec);
416                         
417                         if (expr == null)
418                                 return null;
419
420                         eclass = ExprClass.Value;
421                         return ResolveOperator (ec);
422                 }
423
424                 public override void Emit (EmitContext ec)
425                 {
426                         ILGenerator ig = ec.ig;
427                         Type expr_type = expr.Type;
428                         
429                         switch (oper) {
430                         case Operator.UnaryPlus:
431                                 throw new Exception ("This should be caught by Resolve");
432                                 
433                         case Operator.UnaryNegation:
434                                 expr.Emit (ec);
435                                 ig.Emit (OpCodes.Neg);
436                                 break;
437                                 
438                         case Operator.LogicalNot:
439                                 expr.Emit (ec);
440                                 ig.Emit (OpCodes.Ldc_I4_0);
441                                 ig.Emit (OpCodes.Ceq);
442                                 break;
443                                 
444                         case Operator.OnesComplement:
445                                 expr.Emit (ec);
446                                 ig.Emit (OpCodes.Not);
447                                 break;
448                                 
449                         case Operator.AddressOf:
450                                 ((IMemoryLocation)expr).AddressOf (ec);
451                                 break;
452                                 
453                         case Operator.Indirection:
454                                 throw new Exception ("Not implemented yet");
455                                 
456                         default:
457                                 throw new Exception ("This should not happen: Operator = "
458                                                      + oper.ToString ());
459                         }
460                 }
461
462                 /// <summary>
463                 ///   This will emit the child expression for `ec' avoiding the logical
464                 ///   not.  The parent will take care of changing brfalse/brtrue
465                 /// </summary>
466                 public void EmitLogicalNot (EmitContext ec)
467                 {
468                         if (oper != Operator.LogicalNot)
469                                 throw new Exception ("EmitLogicalNot can only be called with !expr");
470
471                         expr.Emit (ec);
472                 }
473                 
474         }
475
476         /// <summary>
477         ///   Unary Mutator expressions (pre and post ++ and --)
478         /// </summary>
479         ///
480         /// <remarks>
481         ///   UnaryMutator implements ++ and -- expressions.   It derives from
482         ///   ExpressionStatement becuase the pre/post increment/decrement
483         ///   operators can be used in a statement context.
484         ///
485         /// FIXME: Idea, we could split this up in two classes, one simpler
486         /// for the common case, and one with the extra fields for more complex
487         /// classes (indexers require temporary access;  overloaded require method)
488         ///
489         /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
490         /// PostDecrement, that way we could save the `Mode' byte as well.  
491         /// </remarks>
492         public class UnaryMutator : ExpressionStatement {
493                 public enum Mode : byte {
494                         PreIncrement, PreDecrement, PostIncrement, PostDecrement
495                 }
496                 
497                 Mode mode;
498                 Location loc;
499                 Expression expr;
500                 LocalTemporary temp_storage;
501
502                 //
503                 // This is expensive for the simplest case.
504                 //
505                 Expression method;
506                         
507                 public UnaryMutator (Mode m, Expression e, Location l)
508                 {
509                         mode = m;
510                         loc = l;
511                         expr = e;
512                 }
513
514                 string OperName ()
515                 {
516                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
517                                 "++" : "--";
518                 }
519                 
520                 void error23 (Type t)
521                 {
522                         Report.Error (
523                                 23, loc, "Operator " + OperName () + 
524                                 " cannot be applied to operand of type `" +
525                                 TypeManager.CSharpName (t) + "'");
526                 }
527
528                 /// <summary>
529                 ///   Returns whether an object of type `t' can be incremented
530                 ///   or decremented with add/sub (ie, basically whether we can
531                 ///   use pre-post incr-decr operations on it, but it is not a
532                 ///   System.Decimal, which we require operator overloading to catch)
533                 /// </summary>
534                 static bool IsIncrementableNumber (Type t)
535                 {
536                         return (t == TypeManager.sbyte_type) ||
537                                 (t == TypeManager.byte_type) ||
538                                 (t == TypeManager.short_type) ||
539                                 (t == TypeManager.ushort_type) ||
540                                 (t == TypeManager.int32_type) ||
541                                 (t == TypeManager.uint32_type) ||
542                                 (t == TypeManager.int64_type) ||
543                                 (t == TypeManager.uint64_type) ||
544                                 (t == TypeManager.char_type) ||
545                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
546                                 (t == TypeManager.float_type) ||
547                                 (t == TypeManager.double_type);
548                 }
549
550                 Expression ResolveOperator (EmitContext ec)
551                 {
552                         Type expr_type = expr.Type;
553
554                         //
555                         // Step 1: Perform Operator Overload location
556                         //
557                         Expression mg;
558                         string op_name;
559                         
560                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
561                                 op_name = "op_Increment";
562                         else 
563                                 op_name = "op_Decrement";
564
565                         mg = MemberLookup (ec, expr_type, op_name, false, loc);
566
567                         if (mg == null && expr_type.BaseType != null)
568                                 mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc);
569                         
570                         if (mg != null) {
571                                 method = StaticCallExpr.MakeSimpleCall (
572                                         ec, (MethodGroupExpr) mg, expr, loc);
573
574                                 type = method.Type;
575                                 return this;
576                         }
577
578                         //
579                         // The operand of the prefix/postfix increment decrement operators
580                         // should be an expression that is classified as a variable,
581                         // a property access or an indexer access
582                         //
583                         type = expr_type;
584                         if (expr.eclass == ExprClass.Variable){
585                                 if (IsIncrementableNumber (expr_type) ||
586                                     expr_type == TypeManager.decimal_type){
587                                         return this;
588                                 }
589                         } else if (expr.eclass == ExprClass.IndexerAccess){
590                                 IndexerAccess ia = (IndexerAccess) expr;
591                                 
592                                 temp_storage = new LocalTemporary (ec, expr.Type);
593                                 
594                                 expr = ia.ResolveLValue (ec, temp_storage);
595                                 if (expr == null)
596                                         return null;
597
598                                 return this;
599                         } else if (expr.eclass == ExprClass.PropertyAccess){
600                                 PropertyExpr pe = (PropertyExpr) expr;
601
602                                 if (pe.VerifyAssignable ())
603                                         return this;
604
605                                 return null;
606                         } else {
607                                 report118 (loc, expr, "variable, indexer or property access");
608                                 return null;
609                         }
610
611                         Error (187, loc, "No such operator '" + OperName () + "' defined for type '" +
612                                TypeManager.CSharpName (expr_type) + "'");
613                         return null;
614                 }
615
616                 public override Expression DoResolve (EmitContext ec)
617                 {
618                         expr = expr.Resolve (ec);
619                         
620                         if (expr == null)
621                                 return null;
622
623                         eclass = ExprClass.Value;
624                         return ResolveOperator (ec);
625                 }
626                 
627
628                 //
629                 // FIXME: We need some way of avoiding the use of temp_storage
630                 // for some types of storage (parameters, local variables,
631                 // static fields) and single-dimension array access.
632                 //
633                 void EmitCode (EmitContext ec, bool is_expr)
634                 {
635                         ILGenerator ig = ec.ig;
636                         IAssignMethod ia = (IAssignMethod) expr;
637                         Type expr_type = expr.Type;
638                         
639                         if (temp_storage == null)
640                                 temp_storage = new LocalTemporary (ec, expr_type);
641
642                         switch (mode){
643                         case Mode.PreIncrement:
644                         case Mode.PreDecrement:
645                                 if (method == null){
646                                         expr.Emit (ec);
647
648                                         if (expr_type == TypeManager.uint64_type ||
649                                             expr_type == TypeManager.int64_type)
650                                                 ig.Emit (OpCodes.Ldc_I8, 1L);
651                                         else if (expr_type == TypeManager.double_type)
652                                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
653                                         else if (expr_type == TypeManager.float_type)
654                                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
655                                         else
656                                                 ig.Emit (OpCodes.Ldc_I4_1);
657                                 
658                                         if (mode == Mode.PreDecrement)
659                                                 ig.Emit (OpCodes.Sub);
660                                         else
661                                                 ig.Emit (OpCodes.Add);
662                                 } else
663                                         method.Emit (ec);
664                                 
665                                 temp_storage.Store (ec);
666                                 ia.EmitAssign (ec, temp_storage);
667                                 if (is_expr)
668                                         temp_storage.Emit (ec);
669                                 break;
670                                 
671                         case Mode.PostIncrement:
672                         case Mode.PostDecrement:
673                                 if (is_expr)
674                                         expr.Emit (ec);
675                                 
676                                 if (method == null){
677                                         if (!is_expr)
678                                                 expr.Emit (ec);
679                                         else
680                                                 ig.Emit (OpCodes.Dup);
681
682                                         if (expr_type == TypeManager.uint64_type ||
683                                             expr_type == TypeManager.int64_type)
684                                                 ig.Emit (OpCodes.Ldc_I8, 1L);
685                                         else if (expr_type == TypeManager.double_type)
686                                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
687                                         else if (expr_type == TypeManager.float_type)
688                                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
689                                         else
690                                                 ig.Emit (OpCodes.Ldc_I4_1);
691                                 
692                                         if (mode == Mode.PostDecrement)
693                                                 ig.Emit (OpCodes.Sub);
694                                         else
695                                                 ig.Emit (OpCodes.Add);
696                                 } else {
697                                         method.Emit (ec);
698                                 }
699                                 
700                                 temp_storage.Store (ec);
701                                 ia.EmitAssign (ec, temp_storage);
702                                 break;
703                         }
704                 }
705
706                 public override void Emit (EmitContext ec)
707                 {
708                         EmitCode (ec, true);
709                         
710                 }
711                 
712                 public override void EmitStatement (EmitContext ec)
713                 {
714                         EmitCode (ec, false);
715                 }
716
717         }
718
719         /// <summary>
720         ///   Base class for the `Is' and `As' classes. 
721         /// </summary>
722         ///
723         /// <remarks>
724         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
725         ///   size. 
726         /// </remarks>
727         public abstract class Probe : Expression {
728                 public readonly string ProbeType;
729                 protected Expression expr;
730                 protected Type probe_type;
731                 Location loc;
732                 
733                 public Probe (Expression expr, string probe_type, Location l)
734                 {
735                         ProbeType = probe_type;
736                         loc = l;
737                         this.expr = expr;
738                 }
739
740                 public Expression Expr {
741                         get {
742                                 return expr;
743                         }
744                 }
745
746                 public override Expression DoResolve (EmitContext ec)
747                 {
748                         probe_type = RootContext.LookupType (ec.TypeContainer, ProbeType, false, loc);
749
750                         if (probe_type == null)
751                                 return null;
752
753                         expr = expr.Resolve (ec);
754                         
755                         return this;
756                 }
757         }
758
759         /// <summary>
760         ///   Implementation of the `is' operator.
761         /// </summary>
762         public class Is : Probe {
763                 public Is (Expression expr, string probe_type, Location l)
764                         : base (expr, probe_type, l)
765                 {
766                 }
767
768                 public override void Emit (EmitContext ec)
769                 {
770                         ILGenerator ig = ec.ig;
771                         
772                         expr.Emit (ec);
773                         
774                         ig.Emit (OpCodes.Isinst, probe_type);
775                         ig.Emit (OpCodes.Ldnull);
776                         ig.Emit (OpCodes.Cgt_Un);
777                 }
778
779                 public override Expression DoResolve (EmitContext ec)
780                 {
781                         Expression e = base.DoResolve (ec);
782
783                         if (e == null)
784                                 return null;
785
786                         type = TypeManager.bool_type;
787                         eclass = ExprClass.Value;
788
789                         return this;
790                 }                               
791         }
792
793         /// <summary>
794         ///   Implementation of the `as' operator.
795         /// </summary>
796         public class As : Probe {
797                 public As (Expression expr, string probe_type, Location l)
798                         : base (expr, probe_type, l)
799                 {
800                 }
801
802                 public override void Emit (EmitContext ec)
803                 {
804                         ILGenerator ig = ec.ig;
805
806                         expr.Emit (ec);
807                         ig.Emit (OpCodes.Isinst, probe_type);
808                 }
809
810                 public override Expression DoResolve (EmitContext ec)
811                 {
812                         Expression e = base.DoResolve (ec);
813
814                         if (e == null)
815                                 return null;
816
817                         type = probe_type;
818                         eclass = ExprClass.Value;
819
820                         return this;
821                 }                               
822         }
823         
824         /// <summary>
825         ///   This represents a typecast in the source language.
826         ///
827         ///   FIXME: Cast expressions have an unusual set of parsing
828         ///   rules, we need to figure those out.
829         /// </summary>
830         public class Cast : Expression {
831                 Expression target_type;
832                 Expression expr;
833                 Location   loc;
834                         
835                 public Cast (Expression cast_type, Expression expr, Location loc)
836                 {
837                         this.target_type = cast_type;
838                         this.expr = expr;
839                         this.loc = loc;
840                 }
841
842                 public Expression TargetType {
843                         get {
844                                 return target_type;
845                         }
846                 }
847
848                 public Expression Expr {
849                         get {
850                                 return expr;
851                         }
852                         set {
853                                 expr = value;
854                         }
855                 }
856
857                 /// <summary>
858                 ///   Attempts to do a compile-time folding of a constant cast.
859                 /// </summary>
860                 Expression TryReduce (EmitContext ec, Type target_type)
861                 {
862                         if (expr is ByteConstant){
863                                 byte v = ((ByteConstant) expr).Value;
864         
865                                 if (target_type == TypeManager.sbyte_type)
866                                         return new SByteConstant ((sbyte) v);
867                                 if (target_type == TypeManager.short_type)
868                                         return new ShortConstant ((short) v);
869                                 if (target_type == TypeManager.ushort_type)
870                                         return new UShortConstant ((ushort) v);
871                                 if (target_type == TypeManager.int32_type)
872                                         return new IntConstant ((int) v);
873                                 if (target_type == TypeManager.uint32_type)
874                                         return new UIntConstant ((uint) v);
875                                 if (target_type == TypeManager.int64_type)
876                                         return new LongConstant ((long) v);
877                                 if (target_type == TypeManager.uint64_type)
878                                         return new ULongConstant ((ulong) v);
879                                 if (target_type == TypeManager.float_type)
880                                         return new FloatConstant ((float) v);
881                                 if (target_type == TypeManager.double_type)
882                                         return new DoubleConstant ((double) v);
883                         }
884                         if (expr is SByteConstant){
885                                 sbyte v = ((SByteConstant) expr).Value;
886         
887                                 if (target_type == TypeManager.byte_type)
888                                         return new ByteConstant ((byte) v);
889                                 if (target_type == TypeManager.short_type)
890                                         return new ShortConstant ((short) v);
891                                 if (target_type == TypeManager.ushort_type)
892                                         return new UShortConstant ((ushort) v);
893                                 if (target_type == TypeManager.int32_type)
894                                         return new IntConstant ((int) v);
895                                 if (target_type == TypeManager.uint32_type)
896                                         return new UIntConstant ((uint) v);
897                                 if (target_type == TypeManager.int64_type)
898                                         return new LongConstant ((long) v);
899                                 if (target_type == TypeManager.uint64_type)
900                                         return new ULongConstant ((ulong) v);
901                                 if (target_type == TypeManager.float_type)
902                                         return new FloatConstant ((float) v);
903                                 if (target_type == TypeManager.double_type)
904                                         return new DoubleConstant ((double) v);
905                         }
906                         if (expr is ShortConstant){
907                                 short v = ((ShortConstant) expr).Value;
908         
909                                 if (target_type == TypeManager.byte_type)
910                                         return new ByteConstant ((byte) v);
911                                 if (target_type == TypeManager.sbyte_type)
912                                         return new SByteConstant ((sbyte) v);
913                                 if (target_type == TypeManager.ushort_type)
914                                         return new UShortConstant ((ushort) v);
915                                 if (target_type == TypeManager.int32_type)
916                                         return new IntConstant ((int) v);
917                                 if (target_type == TypeManager.uint32_type)
918                                         return new UIntConstant ((uint) v);
919                                 if (target_type == TypeManager.int64_type)
920                                         return new LongConstant ((long) v);
921                                 if (target_type == TypeManager.uint64_type)
922                                         return new ULongConstant ((ulong) v);
923                                 if (target_type == TypeManager.float_type)
924                                         return new FloatConstant ((float) v);
925                                 if (target_type == TypeManager.double_type)
926                                         return new DoubleConstant ((double) v);
927                         }
928                         if (expr is UShortConstant){
929                                 ushort v = ((UShortConstant) expr).Value;
930         
931                                 if (target_type == TypeManager.byte_type)
932                                         return new ByteConstant ((byte) v);
933                                 if (target_type == TypeManager.sbyte_type)
934                                         return new SByteConstant ((sbyte) v);
935                                 if (target_type == TypeManager.short_type)
936                                         return new ShortConstant ((short) v);
937                                 if (target_type == TypeManager.int32_type)
938                                         return new IntConstant ((int) v);
939                                 if (target_type == TypeManager.uint32_type)
940                                         return new UIntConstant ((uint) v);
941                                 if (target_type == TypeManager.int64_type)
942                                         return new LongConstant ((long) v);
943                                 if (target_type == TypeManager.uint64_type)
944                                         return new ULongConstant ((ulong) v);
945                                 if (target_type == TypeManager.float_type)
946                                         return new FloatConstant ((float) v);
947                                 if (target_type == TypeManager.double_type)
948                                         return new DoubleConstant ((double) v);
949                         }
950                         if (expr is IntConstant){
951                                 int v = ((IntConstant) expr).Value;
952         
953                                 if (target_type == TypeManager.byte_type)
954                                         return new ByteConstant ((byte) v);
955                                 if (target_type == TypeManager.sbyte_type)
956                                         return new SByteConstant ((sbyte) v);
957                                 if (target_type == TypeManager.short_type)
958                                         return new ShortConstant ((short) v);
959                                 if (target_type == TypeManager.ushort_type)
960                                         return new UShortConstant ((ushort) v);
961                                 if (target_type == TypeManager.uint32_type)
962                                         return new UIntConstant ((uint) v);
963                                 if (target_type == TypeManager.int64_type)
964                                         return new LongConstant ((long) v);
965                                 if (target_type == TypeManager.uint64_type)
966                                         return new ULongConstant ((ulong) v);
967                                 if (target_type == TypeManager.float_type)
968                                         return new FloatConstant ((float) v);
969                                 if (target_type == TypeManager.double_type)
970                                         return new DoubleConstant ((double) v);
971                         }
972                         if (expr is UIntConstant){
973                                 uint v = ((UIntConstant) expr).Value;
974         
975                                 if (target_type == TypeManager.byte_type)
976                                         return new ByteConstant ((byte) v);
977                                 if (target_type == TypeManager.sbyte_type)
978                                         return new SByteConstant ((sbyte) v);
979                                 if (target_type == TypeManager.short_type)
980                                         return new ShortConstant ((short) v);
981                                 if (target_type == TypeManager.ushort_type)
982                                         return new UShortConstant ((ushort) v);
983                                 if (target_type == TypeManager.int32_type)
984                                         return new IntConstant ((int) v);
985                                 if (target_type == TypeManager.int64_type)
986                                         return new LongConstant ((long) v);
987                                 if (target_type == TypeManager.uint64_type)
988                                         return new ULongConstant ((ulong) v);
989                                 if (target_type == TypeManager.float_type)
990                                         return new FloatConstant ((float) v);
991                                 if (target_type == TypeManager.double_type)
992                                         return new DoubleConstant ((double) v);
993                         }
994                         if (expr is LongConstant){
995                                 long v = ((LongConstant) expr).Value;
996         
997                                 if (target_type == TypeManager.byte_type)
998                                         return new ByteConstant ((byte) v);
999                                 if (target_type == TypeManager.sbyte_type)
1000                                         return new SByteConstant ((sbyte) v);
1001                                 if (target_type == TypeManager.short_type)
1002                                         return new ShortConstant ((short) v);
1003                                 if (target_type == TypeManager.ushort_type)
1004                                         return new UShortConstant ((ushort) v);
1005                                 if (target_type == TypeManager.int32_type)
1006                                         return new IntConstant ((int) v);
1007                                 if (target_type == TypeManager.uint32_type)
1008                                         return new UIntConstant ((uint) v);
1009                                 if (target_type == TypeManager.uint64_type)
1010                                         return new ULongConstant ((ulong) v);
1011                                 if (target_type == TypeManager.float_type)
1012                                         return new FloatConstant ((float) v);
1013                                 if (target_type == TypeManager.double_type)
1014                                         return new DoubleConstant ((double) v);
1015                         }
1016                         if (expr is ULongConstant){
1017                                 ulong v = ((ULongConstant) expr).Value;
1018         
1019                                 if (target_type == TypeManager.byte_type)
1020                                         return new ByteConstant ((byte) v);
1021                                 if (target_type == TypeManager.sbyte_type)
1022                                         return new SByteConstant ((sbyte) v);
1023                                 if (target_type == TypeManager.short_type)
1024                                         return new ShortConstant ((short) v);
1025                                 if (target_type == TypeManager.ushort_type)
1026                                         return new UShortConstant ((ushort) v);
1027                                 if (target_type == TypeManager.int32_type)
1028                                         return new IntConstant ((int) v);
1029                                 if (target_type == TypeManager.uint32_type)
1030                                         return new UIntConstant ((uint) v);
1031                                 if (target_type == TypeManager.int64_type)
1032                                         return new LongConstant ((long) v);
1033                                 if (target_type == TypeManager.float_type)
1034                                         return new FloatConstant ((float) v);
1035                                 if (target_type == TypeManager.double_type)
1036                                         return new DoubleConstant ((double) v);
1037                         }
1038                         if (expr is FloatConstant){
1039                                 float v = ((FloatConstant) expr).Value;
1040         
1041                                 if (target_type == TypeManager.byte_type)
1042                                         return new ByteConstant ((byte) v);
1043                                 if (target_type == TypeManager.sbyte_type)
1044                                         return new SByteConstant ((sbyte) v);
1045                                 if (target_type == TypeManager.short_type)
1046                                         return new ShortConstant ((short) v);
1047                                 if (target_type == TypeManager.ushort_type)
1048                                         return new UShortConstant ((ushort) v);
1049                                 if (target_type == TypeManager.int32_type)
1050                                         return new IntConstant ((int) v);
1051                                 if (target_type == TypeManager.uint32_type)
1052                                         return new UIntConstant ((uint) v);
1053                                 if (target_type == TypeManager.int64_type)
1054                                         return new LongConstant ((long) v);
1055                                 if (target_type == TypeManager.uint64_type)
1056                                         return new ULongConstant ((ulong) v);
1057                                 if (target_type == TypeManager.double_type)
1058                                         return new DoubleConstant ((double) v);
1059                         }
1060                         if (expr is DoubleConstant){
1061                                 double v = ((DoubleConstant) expr).Value;
1062         
1063                                 if (target_type == TypeManager.byte_type)
1064                                         return new ByteConstant ((byte) v);
1065                                 if (target_type == TypeManager.sbyte_type)
1066                                         return new SByteConstant ((sbyte) v);
1067                                 if (target_type == TypeManager.short_type)
1068                                         return new ShortConstant ((short) v);
1069                                 if (target_type == TypeManager.ushort_type)
1070                                         return new UShortConstant ((ushort) v);
1071                                 if (target_type == TypeManager.int32_type)
1072                                         return new IntConstant ((int) v);
1073                                 if (target_type == TypeManager.uint32_type)
1074                                         return new UIntConstant ((uint) v);
1075                                 if (target_type == TypeManager.int64_type)
1076                                         return new LongConstant ((long) v);
1077                                 if (target_type == TypeManager.uint64_type)
1078                                         return new ULongConstant ((ulong) v);
1079                                 if (target_type == TypeManager.float_type)
1080                                         return new FloatConstant ((float) v);
1081                         }
1082
1083                         return null;
1084                 }
1085                 
1086                 public override Expression DoResolve (EmitContext ec)
1087                 {
1088                         expr = expr.Resolve (ec);
1089                         if (expr == null)
1090                                 return null;
1091
1092                         target_type = target_type.Resolve (ec);
1093                         if (target_type == null)
1094                                 return null;
1095
1096                         if (target_type.eclass != ExprClass.Type){
1097                                 report118 (loc, target_type, "class");
1098                                 return null;
1099                         }
1100                         
1101                         type = target_type.Type;
1102                         eclass = ExprClass.Value;
1103                         
1104                         if (type == null)
1105                                 return null;
1106
1107                         if (expr is Constant){
1108                                 Expression e = TryReduce (ec, type);
1109
1110                                 if (e != null)
1111                                         return e;
1112                         }
1113                         
1114                         expr = ConvertExplicit (ec, expr, type, loc);
1115                         return expr;
1116                 }
1117
1118                 public override void Emit (EmitContext ec)
1119                 {
1120                         //
1121                         // This one will never happen
1122                         //
1123                         throw new Exception ("Should not happen");
1124                 }
1125         }
1126
1127         /// <summary>
1128         ///   Binary operators
1129         /// </summary>
1130         public class Binary : Expression {
1131                 public enum Operator : byte {
1132                         Multiply, Division, Modulus,
1133                         Addition, Subtraction,
1134                         LeftShift, RightShift,
1135                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1136                         Equality, Inequality,
1137                         BitwiseAnd,
1138                         ExclusiveOr,
1139                         BitwiseOr,
1140                         LogicalAnd,
1141                         LogicalOr
1142                 }
1143
1144                 Operator oper;
1145                 Expression left, right;
1146                 MethodBase method;
1147                 ArrayList  Arguments;
1148                 Location   loc;
1149
1150                 bool DelegateOperation;
1151
1152                 public Binary (Operator oper, Expression left, Expression right, Location loc)
1153                 {
1154                         this.oper = oper;
1155                         this.left = left;
1156                         this.right = right;
1157                         this.loc = loc;
1158                 }
1159
1160                 public Operator Oper {
1161                         get {
1162                                 return oper;
1163                         }
1164                         set {
1165                                 oper = value;
1166                         }
1167                 }
1168                 
1169                 public Expression Left {
1170                         get {
1171                                 return left;
1172                         }
1173                         set {
1174                                 left = value;
1175                         }
1176                 }
1177
1178                 public Expression Right {
1179                         get {
1180                                 return right;
1181                         }
1182                         set {
1183                                 right = value;
1184                         }
1185                 }
1186
1187
1188                 /// <summary>
1189                 ///   Returns a stringified representation of the Operator
1190                 /// </summary>
1191                 string OperName ()
1192                 {
1193                         switch (oper){
1194                         case Operator.Multiply:
1195                                 return "*";
1196                         case Operator.Division:
1197                                 return "/";
1198                         case Operator.Modulus:
1199                                 return "%";
1200                         case Operator.Addition:
1201                                 return "+";
1202                         case Operator.Subtraction:
1203                                 return "-";
1204                         case Operator.LeftShift:
1205                                 return "<<";
1206                         case Operator.RightShift:
1207                                 return ">>";
1208                         case Operator.LessThan:
1209                                 return "<";
1210                         case Operator.GreaterThan:
1211                                 return ">";
1212                         case Operator.LessThanOrEqual:
1213                                 return "<=";
1214                         case Operator.GreaterThanOrEqual:
1215                                 return ">=";
1216                         case Operator.Equality:
1217                                 return "==";
1218                         case Operator.Inequality:
1219                                 return "!=";
1220                         case Operator.BitwiseAnd:
1221                                 return "&";
1222                         case Operator.BitwiseOr:
1223                                 return "|";
1224                         case Operator.ExclusiveOr:
1225                                 return "^";
1226                         case Operator.LogicalOr:
1227                                 return "||";
1228                         case Operator.LogicalAnd:
1229                                 return "&&";
1230                         }
1231
1232                         return oper.ToString ();
1233                 }
1234
1235                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1236                 {
1237                         if (expr.Type == target_type)
1238                                 return expr;
1239
1240                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
1241                 }
1242                 
1243                 //
1244                 // Note that handling the case l == Decimal || r == Decimal
1245                 // is taken care of by the Step 1 Operator Overload resolution.
1246                 //
1247                 bool DoNumericPromotions (EmitContext ec, Type l, Type r)
1248                 {
1249                         if (l == TypeManager.double_type || r == TypeManager.double_type){
1250                                 //
1251                                 // If either operand is of type double, the other operand is
1252                                 // conveted to type double.
1253                                 //
1254                                 if (r != TypeManager.double_type)
1255                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
1256                                 if (l != TypeManager.double_type)
1257                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
1258                                 
1259                                 type = TypeManager.double_type;
1260                         } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1261                                 //
1262                                 // if either operand is of type float, th eother operand is
1263                                 // converd to type float.
1264                                 //
1265                                 if (r != TypeManager.double_type)
1266                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
1267                                 if (l != TypeManager.double_type)
1268                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
1269                                 type = TypeManager.float_type;
1270                         } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
1271                                 Expression e;
1272                                 Type other;
1273                                 //
1274                                 // If either operand is of type ulong, the other operand is
1275                                 // converted to type ulong.  or an error ocurrs if the other
1276                                 // operand is of type sbyte, short, int or long
1277                                 //
1278                                 if (l == TypeManager.uint64_type){
1279                                         if (r != TypeManager.uint64_type){
1280                                                 if (right is IntConstant){
1281                                                         IntConstant ic = (IntConstant) right;
1282                                                         
1283                                                         e = TryImplicitIntConversion (l, ic);
1284                                                         if (e != null)
1285                                                                 right = e;
1286                                                 } else if (right is LongConstant){
1287                                                         long ll = ((LongConstant) right).Value;
1288
1289                                                         if (ll > 0)
1290                                                                 right = new ULongConstant ((ulong) ll);
1291                                                 } else {
1292                                                         e = ImplicitNumericConversion (ec, right, l, loc);
1293                                                         if (e != null)
1294                                                                 right = e;
1295                                                 }
1296                                         }
1297                                         other = right.Type;
1298                                 } else {
1299                                         if (left is IntConstant){
1300                                                 e = TryImplicitIntConversion (r, (IntConstant) left);
1301                                                 if (e != null)
1302                                                         left = e;
1303                                         } else if (left is LongConstant){
1304                                                 long ll = ((LongConstant) left).Value;
1305                                                 
1306                                                 if (ll > 0)
1307                                                         left = new ULongConstant ((ulong) ll);
1308                                         } else {
1309                                                 e = ImplicitNumericConversion (ec, left, r, loc);
1310                                                 if (e != null)
1311                                                         left = e;
1312                                         }
1313                                         other = left.Type;
1314                                 }
1315
1316                                 if ((other == TypeManager.sbyte_type) ||
1317                                     (other == TypeManager.short_type) ||
1318                                     (other == TypeManager.int32_type) ||
1319                                     (other == TypeManager.int64_type)){
1320                                         string oper = OperName ();
1321                                         
1322                                         Error (34, loc, "Operator `" + OperName ()
1323                                                + "' is ambiguous on operands of type `"
1324                                                + TypeManager.CSharpName (l) + "' "
1325                                                + "and `" + TypeManager.CSharpName (r)
1326                                                + "'");
1327                                 }
1328                                 type = TypeManager.uint64_type;
1329                         } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1330                                 //
1331                                 // If either operand is of type long, the other operand is converted
1332                                 // to type long.
1333                                 //
1334                                 if (l != TypeManager.int64_type)
1335                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
1336                                 if (r != TypeManager.int64_type)
1337                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
1338
1339                                 type = TypeManager.int64_type;
1340                         } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1341                                 //
1342                                 // If either operand is of type uint, and the other
1343                                 // operand is of type sbyte, short or int, othe operands are
1344                                 // converted to type long.
1345                                 //
1346                                 Type other = null;
1347                                 
1348                                 if (l == TypeManager.uint32_type)
1349                                         other = r;
1350                                 else if (r == TypeManager.uint32_type)
1351                                         other = l;
1352
1353                                 if ((other == TypeManager.sbyte_type) ||
1354                                     (other == TypeManager.short_type) ||
1355                                     (other == TypeManager.int32_type)){
1356                                         left = ForceConversion (ec, left, TypeManager.int64_type);
1357                                         right = ForceConversion (ec, right, TypeManager.int64_type);
1358                                         type = TypeManager.int64_type;
1359                                 } else {
1360                                         //
1361                                         // if either operand is of type uint, the other
1362                                         // operand is converd to type uint
1363                                         //
1364                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
1365                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
1366                                         type = TypeManager.uint32_type;
1367                                 } 
1368                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1369                                 if (l != TypeManager.decimal_type)
1370                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
1371                                 if (r != TypeManager.decimal_type)
1372                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
1373
1374                                 type = TypeManager.decimal_type;
1375                         } else {
1376                                 Expression l_tmp, r_tmp;
1377
1378                                 l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
1379                                 if (l_tmp == null)
1380                                         return false;
1381                                 
1382                                 r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
1383                                 if (r_tmp == null)
1384                                         return false;
1385
1386                                 left = l_tmp;
1387                                 right = r_tmp;
1388                                 
1389                                 type = TypeManager.int32_type;
1390                         }
1391
1392                         return true;
1393                 }
1394
1395                 void error19 ()
1396                 {
1397                         Error (19, loc,
1398                                "Operator " + OperName () + " cannot be applied to operands of type `" +
1399                                TypeManager.CSharpName (left.Type) + "' and `" +
1400                                TypeManager.CSharpName (right.Type) + "'");
1401                                                      
1402                 }
1403                 
1404                 Expression CheckShiftArguments (EmitContext ec)
1405                 {
1406                         Expression e;
1407                         Type l = left.Type;
1408                         Type r = right.Type;
1409
1410                         e = ForceConversion (ec, right, TypeManager.int32_type);
1411                         if (e == null){
1412                                 error19 ();
1413                                 return null;
1414                         }
1415                         right = e;
1416
1417                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
1418                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
1419                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
1420                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
1421                                 left = e;
1422                                 type = e.Type;
1423
1424                                 return this;
1425                         }
1426                         error19 ();
1427                         return null;
1428                 }
1429                 
1430                 Expression ResolveOperator (EmitContext ec)
1431                 {
1432                         Type l = left.Type;
1433                         Type r = right.Type;
1434
1435                         //
1436                         // Step 1: Perform Operator Overload location
1437                         //
1438                         Expression left_expr, right_expr;
1439                         
1440                         string op = "op_" + oper;
1441
1442                         left_expr = MemberLookup (ec, l, op, false, loc);
1443                         if (left_expr == null && l.BaseType != null)
1444                                 left_expr = MemberLookup (ec, l.BaseType, op, false, loc);
1445                         
1446                         right_expr = MemberLookup (ec, r, op, false, loc);
1447                         if (right_expr == null && r.BaseType != null)
1448                                 right_expr = MemberLookup (ec, r.BaseType, op, false, loc);
1449                         
1450                         MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
1451                         
1452                         if (union != null) {
1453                                 Arguments = new ArrayList ();
1454                                 Arguments.Add (new Argument (left, Argument.AType.Expression));
1455                                 Arguments.Add (new Argument (right, Argument.AType.Expression));
1456
1457                                 method = Invocation.OverloadResolve (ec, union, Arguments, loc);
1458                                 if (method != null) {
1459                                         MethodInfo mi = (MethodInfo) method;
1460                                         type = mi.ReturnType;
1461                                         return this;
1462                                 } else {
1463                                         error19 ();
1464                                         return null;
1465                                 }
1466                         }       
1467
1468                         //
1469                         // Step 2: Default operations on CLI native types.
1470                         //
1471
1472                         // Only perform numeric promotions on:
1473                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1474                         //
1475                         if (oper == Operator.Addition){
1476                                 //
1477                                 // If any of the arguments is a string, cast to string
1478                                 //
1479                                 if (l == TypeManager.string_type){
1480                                         if (r == TypeManager.string_type){
1481                                                 if (left is Constant && right is Constant){
1482                                                         StringConstant ls = (StringConstant) left;
1483                                                         StringConstant rs = (StringConstant) right;
1484                                                         
1485                                                         return new StringConstant (
1486                                                                 ls.Value + rs.Value);
1487                                                 }
1488                                                 
1489                                                 // string + string
1490                                                 method = TypeManager.string_concat_string_string;
1491                                         } else {
1492                                                 // string + object
1493                                                 method = TypeManager.string_concat_object_object;
1494                                                 right = ConvertImplicit (ec, right,
1495                                                                          TypeManager.object_type, loc);
1496                                         }
1497                                         type = TypeManager.string_type;
1498
1499                                         Arguments = new ArrayList ();
1500                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1501                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1502
1503                                         return this;
1504                                         
1505                                 } else if (r == TypeManager.string_type){
1506                                         // object + string
1507                                         method = TypeManager.string_concat_object_object;
1508                                         Arguments = new ArrayList ();
1509                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1510                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1511
1512                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
1513                                         type = TypeManager.string_type;
1514
1515                                         return this;
1516                                 }
1517                         }
1518
1519                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
1520                                 if (l.IsSubclassOf (TypeManager.delegate_type) &&
1521                                     r.IsSubclassOf (TypeManager.delegate_type)) {
1522                                         
1523                                         Arguments = new ArrayList ();
1524                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1525                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1526                                         
1527                                         if (oper == Operator.Addition)
1528                                                 method = TypeManager.delegate_combine_delegate_delegate;
1529                                         else
1530                                                 method = TypeManager.delegate_remove_delegate_delegate;
1531                                         
1532                                         DelegateOperation = true;
1533                                         type = l;
1534                                         return this;
1535                                 }
1536                         }
1537                         
1538                         //
1539                         // Enumeration operators
1540                         //
1541                         bool lie = TypeManager.IsEnumType (l);
1542                         bool rie = TypeManager.IsEnumType (r);
1543                         if (lie || rie){
1544                                 Expression temp;
1545
1546                                 if (!rie){
1547                                         temp = ConvertImplicit (ec, right, l, loc);
1548                                         if (temp != null)
1549                                                 right = temp;
1550                                 } if (!lie){
1551                                         temp = ConvertImplicit (ec, left, r, loc);
1552                                         if (temp != null){
1553                                                 left = temp;
1554                                                 l = r;
1555                                         }
1556                                 }
1557                                 
1558                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
1559                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
1560                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
1561                                         type = TypeManager.bool_type;
1562                                         return this;
1563                                 }
1564
1565                                 if (oper == Operator.BitwiseAnd ||
1566                                     oper == Operator.BitwiseOr ||
1567                                     oper == Operator.ExclusiveOr){
1568                                         type = l;
1569                                         return this;
1570                                 }
1571                         }
1572                         
1573                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
1574                                 return CheckShiftArguments (ec);
1575
1576                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
1577                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
1578                                         error19 ();
1579                                         return null;
1580                                 }
1581
1582                                 type = TypeManager.bool_type;
1583                                 return this;
1584                         } 
1585
1586                         if (oper == Operator.Equality || oper == Operator.Inequality){
1587                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1588                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1589                                                 error19 ();
1590                                                 return null;
1591                                         }
1592                                         
1593                                         type = TypeManager.bool_type;
1594                                         return this;
1595                                 }
1596
1597                                 //
1598                                 // operator != (object a, object b)
1599                                 // operator == (object a, object b)
1600                                 //
1601                                 // For this to be used, both arguments have to be reference-types.
1602                                 // Read the rationale on the spec (14.9.6)
1603                                 //
1604                                 // Also, if at compile time we know that the classes do not inherit
1605                                 // one from the other, then we catch the error there.
1606                                 //
1607                                 if (!(l.IsValueType || r.IsValueType)){
1608                                         type = TypeManager.bool_type;
1609
1610                                         if (l == r)
1611                                                 return this;
1612                                         
1613                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
1614                                                 return this;
1615
1616                                         //
1617                                         // We are going to have to convert to an object to compare
1618                                         //
1619                                         if (l != TypeManager.object_type)
1620                                                 left = new EmptyCast (left, TypeManager.object_type);
1621                                         if (r != TypeManager.object_type)
1622                                                 right = new EmptyCast (right, TypeManager.object_type);
1623
1624                                         return this;
1625                                 }
1626                         }
1627
1628                         //
1629                         // We are dealing with numbers
1630                         //
1631
1632                         if (!DoNumericPromotions (ec, l, r)){
1633                                 error19 ();
1634                                 return null;
1635                         }
1636
1637                         if (left == null || right == null)
1638                                 return null;
1639
1640                         //
1641                         // reload our cached types if required
1642                         //
1643                         l = left.Type;
1644                         r = right.Type;
1645                         
1646                         if (oper == Operator.BitwiseAnd ||
1647                             oper == Operator.BitwiseOr ||
1648                             oper == Operator.ExclusiveOr){
1649                                 if (l == r){
1650                                         if (!((l == TypeManager.int32_type) ||
1651                                               (l == TypeManager.uint32_type) ||
1652                                               (l == TypeManager.int64_type) ||
1653                                               (l == TypeManager.uint64_type)))
1654                                                 type = l;
1655                                 } else {
1656                                         error19 ();
1657                                         return null;
1658                                 }
1659                         }
1660
1661                         if (oper == Operator.Equality ||
1662                             oper == Operator.Inequality ||
1663                             oper == Operator.LessThanOrEqual ||
1664                             oper == Operator.LessThan ||
1665                             oper == Operator.GreaterThanOrEqual ||
1666                             oper == Operator.GreaterThan){
1667                                 type = TypeManager.bool_type;
1668                         }
1669
1670                         return this;
1671                 }
1672
1673                 /// <summary>
1674                 ///   Constant expression reducer for binary operations
1675                 /// </summary>
1676                 public Expression ConstantFold (EmitContext ec)
1677                 {
1678                         object l = ((Constant) left).GetValue ();
1679                         object r = ((Constant) right).GetValue ();
1680                         
1681                         if (l is string && r is string)
1682                                 return new StringConstant ((string) l + (string) r);
1683
1684                         Type result_type = null;
1685
1686                         //
1687                         // Enumerator folding
1688                         //
1689                         if (left.Type == right.Type && left is EnumConstant)
1690                                 result_type = left.Type;
1691
1692                         switch (oper){
1693                         case Operator.BitwiseOr:
1694                                 if ((l is int) && (r is int)){
1695                                         IntConstant v;
1696                                         int res = (int)l | (int)r;
1697                                         
1698                                         v = new IntConstant (res);
1699                                         if (result_type == null)
1700                                                 return v;
1701                                         else
1702                                                 return new EnumConstant (v, result_type);
1703                                 }
1704                                 break;
1705                                 
1706                         case Operator.BitwiseAnd:
1707                                 if ((l is int) && (r is int)){
1708                                         IntConstant v;
1709                                         int res = (int)l & (int)r;
1710                                         
1711                                         v = new IntConstant (res);
1712                                         if (result_type == null)
1713                                                 return v;
1714                                         else
1715                                                 return new EnumConstant (v, result_type);
1716                                 }
1717                                 break;
1718                         }
1719                                         
1720                         return null;
1721                 }
1722                 
1723                 public override Expression DoResolve (EmitContext ec)
1724                 {
1725                         left = left.Resolve (ec);
1726                         right = right.Resolve (ec);
1727
1728                         if (left == null || right == null)
1729                                 return null;
1730
1731                         if (left.Type == null)
1732                                 throw new Exception (
1733                                         "Resolve returned non null, but did not set the type! (" +
1734                                         left + ") at Line: " + loc.Row);
1735                         if (right.Type == null)
1736                                 throw new Exception (
1737                                         "Resolve returned non null, but did not set the type! (" +
1738                                         right + ") at Line: "+ loc.Row);
1739
1740                         eclass = ExprClass.Value;
1741
1742                         if (left is Constant && right is Constant){
1743                                 //
1744                                 // This is temporary until we do the full folding
1745                                 //
1746                                 Expression e = ConstantFold (ec);
1747                                 if (e != null)
1748                                         return e;
1749                         }
1750
1751                         return ResolveOperator (ec);
1752                 }
1753
1754                 public bool IsBranchable ()
1755                 {
1756                         if (oper == Operator.Equality ||
1757                             oper == Operator.Inequality ||
1758                             oper == Operator.LessThan ||
1759                             oper == Operator.GreaterThan ||
1760                             oper == Operator.LessThanOrEqual ||
1761                             oper == Operator.GreaterThanOrEqual){
1762                                 return true;
1763                         } else
1764                                 return false;
1765                 }
1766
1767                 /// <summary>
1768                 ///   This entry point is used by routines that might want
1769                 ///   to emit a brfalse/brtrue after an expression, and instead
1770                 ///   they could use a more compact notation.
1771                 ///
1772                 ///   Typically the code would generate l.emit/r.emit, followed
1773                 ///   by the comparission and then a brtrue/brfalse.  The comparissions
1774                 ///   are sometimes inneficient (there are not as complete as the branches
1775                 ///   look for the hacks in Emit using double ceqs).
1776                 ///
1777                 ///   So for those cases we provide EmitBranchable that can emit the
1778                 ///   branch with the test
1779                 /// </summary>
1780                 public void EmitBranchable (EmitContext ec, int target)
1781                 {
1782                         OpCode opcode;
1783                         bool close_target = false;
1784                         ILGenerator ig = ec.ig;
1785                                 
1786                         //
1787                         // short-circuit operators
1788                         //
1789                         if (oper == Operator.LogicalAnd){
1790                                 left.Emit (ec);
1791                                 ig.Emit (OpCodes.Brfalse, target);
1792                                 right.Emit (ec);
1793                                 ig.Emit (OpCodes.Brfalse, target);
1794                         } else if (oper == Operator.LogicalOr){
1795                                 left.Emit (ec);
1796                                 ig.Emit (OpCodes.Brtrue, target);
1797                                 right.Emit (ec);
1798                                 ig.Emit (OpCodes.Brfalse, target);
1799                         }
1800                                 
1801                         left.Emit (ec);
1802                         right.Emit (ec);
1803                         
1804                         switch (oper){
1805                         case Operator.Equality:
1806                                 if (close_target)
1807                                         opcode = OpCodes.Beq_S;
1808                                 else
1809                                         opcode = OpCodes.Beq;
1810                                 break;
1811
1812                         case Operator.Inequality:
1813                                 if (close_target)
1814                                         opcode = OpCodes.Bne_Un_S;
1815                                 else
1816                                         opcode = OpCodes.Bne_Un;
1817                                 break;
1818
1819                         case Operator.LessThan:
1820                                 if (close_target)
1821                                         opcode = OpCodes.Blt_S;
1822                                 else
1823                                         opcode = OpCodes.Blt;
1824                                 break;
1825
1826                         case Operator.GreaterThan:
1827                                 if (close_target)
1828                                         opcode = OpCodes.Bgt_S;
1829                                 else
1830                                         opcode = OpCodes.Bgt;
1831                                 break;
1832
1833                         case Operator.LessThanOrEqual:
1834                                 if (close_target)
1835                                         opcode = OpCodes.Ble_S;
1836                                 else
1837                                         opcode = OpCodes.Ble;
1838                                 break;
1839
1840                         case Operator.GreaterThanOrEqual:
1841                                 if (close_target)
1842                                         opcode = OpCodes.Bge_S;
1843                                 else
1844                                         opcode = OpCodes.Ble;
1845                                 break;
1846
1847                         default:
1848                                 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1849                                                      + oper.ToString ());
1850                         }
1851
1852                         ig.Emit (opcode, target);
1853                 }
1854                 
1855                 public override void Emit (EmitContext ec)
1856                 {
1857                         ILGenerator ig = ec.ig;
1858                         Type l = left.Type;
1859                         Type r = right.Type;
1860                         OpCode opcode;
1861
1862                         if (method != null) {
1863
1864                                 // Note that operators are static anyway
1865                                 
1866                                 if (Arguments != null) 
1867                                         Invocation.EmitArguments (ec, method, Arguments);
1868                                 
1869                                 if (method is MethodInfo)
1870                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
1871                                 else
1872                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1873
1874                                 if (DelegateOperation)
1875                                         ig.Emit (OpCodes.Castclass, type);
1876                                         
1877                                 return;
1878                         }
1879
1880                         //
1881                         // Handle short-circuit operators differently
1882                         // than the rest
1883                         //
1884                         if (oper == Operator.LogicalAnd){
1885                                 Label load_zero = ig.DefineLabel ();
1886                                 Label end = ig.DefineLabel ();
1887                                 
1888                                 left.Emit (ec);
1889                                 ig.Emit (OpCodes.Brfalse, load_zero);
1890                                 right.Emit (ec);
1891                                 ig.Emit (OpCodes.Br, end);
1892                                 ig.MarkLabel (load_zero);
1893                                 ig.Emit (OpCodes.Ldc_I4_0);
1894                                 ig.MarkLabel (end);
1895                                 return;
1896                         } else if (oper == Operator.LogicalOr){
1897                                 Label load_one = ig.DefineLabel ();
1898                                 Label end = ig.DefineLabel ();
1899                                 
1900                                 left.Emit (ec);
1901                                 ig.Emit (OpCodes.Brtrue, load_one);
1902                                 right.Emit (ec);
1903                                 ig.Emit (OpCodes.Br, end);
1904                                 ig.MarkLabel (load_one);
1905                                 ig.Emit (OpCodes.Ldc_I4_1);
1906                                 ig.MarkLabel (end);
1907                                 return;
1908                         }
1909                         
1910                         left.Emit (ec);
1911                         right.Emit (ec);
1912
1913                         switch (oper){
1914                         case Operator.Multiply:
1915                                 if (ec.CheckState){
1916                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1917                                                 opcode = OpCodes.Mul_Ovf;
1918                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1919                                                 opcode = OpCodes.Mul_Ovf_Un;
1920                                         else
1921                                                 opcode = OpCodes.Mul;
1922                                 } else
1923                                         opcode = OpCodes.Mul;
1924
1925                                 break;
1926
1927                         case Operator.Division:
1928                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1929                                         opcode = OpCodes.Div_Un;
1930                                 else
1931                                         opcode = OpCodes.Div;
1932                                 break;
1933
1934                         case Operator.Modulus:
1935                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1936                                         opcode = OpCodes.Rem_Un;
1937                                 else
1938                                         opcode = OpCodes.Rem;
1939                                 break;
1940
1941                         case Operator.Addition:
1942                                 if (ec.CheckState){
1943                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1944                                                 opcode = OpCodes.Add_Ovf;
1945                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1946                                                 opcode = OpCodes.Add_Ovf_Un;
1947                                         else
1948                                                 opcode = OpCodes.Mul;
1949                                 } else
1950                                         opcode = OpCodes.Add;
1951                                 break;
1952
1953                         case Operator.Subtraction:
1954                                 if (ec.CheckState){
1955                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1956                                                 opcode = OpCodes.Sub_Ovf;
1957                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1958                                                 opcode = OpCodes.Sub_Ovf_Un;
1959                                         else
1960                                                 opcode = OpCodes.Sub;
1961                                 } else
1962                                         opcode = OpCodes.Sub;
1963                                 break;
1964
1965                         case Operator.RightShift:
1966                                 opcode = OpCodes.Shr;
1967                                 break;
1968                                 
1969                         case Operator.LeftShift:
1970                                 opcode = OpCodes.Shl;
1971                                 break;
1972
1973                         case Operator.Equality:
1974                                 opcode = OpCodes.Ceq;
1975                                 break;
1976
1977                         case Operator.Inequality:
1978                                 ec.ig.Emit (OpCodes.Ceq);
1979                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
1980                                 
1981                                 opcode = OpCodes.Ceq;
1982                                 break;
1983
1984                         case Operator.LessThan:
1985                                 opcode = OpCodes.Clt;
1986                                 break;
1987
1988                         case Operator.GreaterThan:
1989                                 opcode = OpCodes.Cgt;
1990                                 break;
1991
1992                         case Operator.LessThanOrEqual:
1993                                 ec.ig.Emit (OpCodes.Cgt);
1994                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
1995                                 
1996                                 opcode = OpCodes.Ceq;
1997                                 break;
1998
1999                         case Operator.GreaterThanOrEqual:
2000                                 ec.ig.Emit (OpCodes.Clt);
2001                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
2002                                 
2003                                 opcode = OpCodes.Sub;
2004                                 break;
2005
2006                         case Operator.BitwiseOr:
2007                                 opcode = OpCodes.Or;
2008                                 break;
2009
2010                         case Operator.BitwiseAnd:
2011                                 opcode = OpCodes.And;
2012                                 break;
2013
2014                         case Operator.ExclusiveOr:
2015                                 opcode = OpCodes.Xor;
2016                                 break;
2017
2018                         default:
2019                                 throw new Exception ("This should not happen: Operator = "
2020                                                      + oper.ToString ());
2021                         }
2022
2023                         ig.Emit (opcode);
2024                 }
2025         }
2026
2027         /// <summary>
2028         ///   Implements the ternary conditiona operator (?:)
2029         /// </summary>
2030         public class Conditional : Expression {
2031                 Expression expr, trueExpr, falseExpr;
2032                 Location loc;
2033                 
2034                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2035                 {
2036                         this.expr = expr;
2037                         this.trueExpr = trueExpr;
2038                         this.falseExpr = falseExpr;
2039                         this.loc = l;
2040                 }
2041
2042                 public Expression Expr {
2043                         get {
2044                                 return expr;
2045                         }
2046                 }
2047
2048                 public Expression TrueExpr {
2049                         get {
2050                                 return trueExpr;
2051                         }
2052                 }
2053
2054                 public Expression FalseExpr {
2055                         get {
2056                                 return falseExpr;
2057                         }
2058                 }
2059
2060                 public override Expression DoResolve (EmitContext ec)
2061                 {
2062                         expr = expr.Resolve (ec);
2063
2064                         if (expr.Type != TypeManager.bool_type)
2065                                 expr = Expression.ConvertImplicitRequired (
2066                                         ec, expr, TypeManager.bool_type, loc);
2067                         
2068                         trueExpr = trueExpr.Resolve (ec);
2069                         falseExpr = falseExpr.Resolve (ec);
2070
2071                         if (expr == null || trueExpr == null || falseExpr == null)
2072                                 return null;
2073
2074                         if (trueExpr.Type == falseExpr.Type)
2075                                 type = trueExpr.Type;
2076                         else {
2077                                 Expression conv;
2078
2079                                 //
2080                                 // First, if an implicit conversion exists from trueExpr
2081                                 // to falseExpr, then the result type is of type falseExpr.Type
2082                                 //
2083                                 conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc);
2084                                 if (conv != null){
2085                                         type = falseExpr.Type;
2086                                         trueExpr = conv;
2087                                 } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){
2088                                         type = trueExpr.Type;
2089                                         falseExpr = conv;
2090                                 } else {
2091                                         Error (173, loc, "The type of the conditional expression can " +
2092                                                "not be computed because there is no implicit conversion" +
2093                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2094                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2095                                         return null;
2096                                 }
2097                         }
2098
2099                         if (expr is BoolConstant){
2100                                 BoolConstant bc = (BoolConstant) expr;
2101
2102                                 if (bc.Value)
2103                                         return trueExpr;
2104                                 else
2105                                         return falseExpr;
2106                         }
2107
2108                         eclass = ExprClass.Value;
2109                         return this;
2110                 }
2111
2112                 public override void Emit (EmitContext ec)
2113                 {
2114                         ILGenerator ig = ec.ig;
2115                         Label false_target = ig.DefineLabel ();
2116                         Label end_target = ig.DefineLabel ();
2117
2118                         expr.Emit (ec);
2119                         ig.Emit (OpCodes.Brfalse, false_target);
2120                         trueExpr.Emit (ec);
2121                         ig.Emit (OpCodes.Br, end_target);
2122                         ig.MarkLabel (false_target);
2123                         falseExpr.Emit (ec);
2124                         ig.MarkLabel (end_target);
2125                 }
2126
2127         }
2128
2129         /// <summary>
2130         ///   Local variables
2131         /// </summary>
2132         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation {
2133                 public readonly string Name;
2134                 public readonly Block Block;
2135                 Location loc;
2136                 VariableInfo variable_info;
2137                 
2138                 public LocalVariableReference (Block block, string name, Location l)
2139                 {
2140                         Block = block;
2141                         Name = name;
2142                         loc = l;
2143                         eclass = ExprClass.Variable;
2144                 }
2145
2146                 public VariableInfo VariableInfo {
2147                         get {
2148                                 if (variable_info == null)
2149                                         variable_info = Block.GetVariableInfo (Name);
2150                                 return variable_info;
2151                         }
2152                 }
2153                 
2154                 public override Expression DoResolve (EmitContext ec)
2155                 {
2156                         VariableInfo vi = VariableInfo;
2157
2158                         if (Block.IsConstant (Name)) {
2159                                 Expression e = Block.GetConstantExpression (Name);
2160
2161                                 e = e.Resolve (ec);
2162                                 if (e == null)  
2163                                         return null;
2164
2165                                 if (!(e is Constant)) {
2166                                         Report.Error (150, loc, "A constant value is expected");
2167                                         return null;
2168                                 }
2169
2170                                 vi.Used = true;
2171                                 return e;
2172                         }
2173
2174                         type = vi.VariableType;
2175                         return this;
2176                 }
2177
2178                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2179                 {
2180                         Expression e = DoResolve (ec);
2181
2182                         if (e == null)
2183                                 return null;
2184
2185                         VariableInfo vi = VariableInfo;
2186                         
2187                         if (vi.ReadOnly){
2188                                 if (vi.Assigned){
2189                                         Report.Error (
2190                                                 1604, loc,
2191                                                 "cannot assign to `" + Name + "' because it is readonly");
2192                                         return null;
2193                                 }
2194                         }
2195                         
2196                         return this;
2197                 }
2198
2199                 public override void Emit (EmitContext ec)
2200                 {
2201                         VariableInfo vi = VariableInfo;
2202                         ILGenerator ig = ec.ig;
2203                         int idx = vi.Idx;
2204
2205                         vi.Used = true;
2206
2207                         switch (idx){
2208                         case 0:
2209                                 ig.Emit (OpCodes.Ldloc_0);
2210                                 break;
2211                                 
2212                         case 1:
2213                                 ig.Emit (OpCodes.Ldloc_1);
2214                                 break;
2215                                 
2216                         case 2:
2217                                 ig.Emit (OpCodes.Ldloc_2);
2218                                 break;
2219                                 
2220                         case 3:
2221                                 ig.Emit (OpCodes.Ldloc_3);
2222                                 break;
2223                                 
2224                         default:
2225                                 if (idx <= 255)
2226                                         ig.Emit (OpCodes.Ldloc_S, (byte) idx);
2227                                 else
2228                                         ig.Emit (OpCodes.Ldloc, idx);
2229                                 break;
2230                         }
2231                 }
2232                 
2233                 public static void Store (ILGenerator ig, int idx)
2234                 {
2235                         switch (idx){
2236                         case 0:
2237                                 ig.Emit (OpCodes.Stloc_0);
2238                                 break;
2239                                 
2240                         case 1:
2241                                 ig.Emit (OpCodes.Stloc_1);
2242                                 break;
2243                                 
2244                         case 2:
2245                                 ig.Emit (OpCodes.Stloc_2);
2246                                 break;
2247                                 
2248                         case 3:
2249                                 ig.Emit (OpCodes.Stloc_3);
2250                                 break;
2251                                 
2252                         default:
2253                                 if (idx <= 255)
2254                                         ig.Emit (OpCodes.Stloc_S, (byte) idx);
2255                                 else
2256                                         ig.Emit (OpCodes.Stloc, idx);
2257                                 break;
2258                         }
2259                 }
2260
2261                 public void EmitAssign (EmitContext ec, Expression source)
2262                 {
2263                         ILGenerator ig = ec.ig;
2264                         VariableInfo vi = VariableInfo;
2265
2266                         vi.Assigned = true;
2267
2268                         source.Emit (ec);
2269                         
2270                         // Funny seems the code below generates optimal code for us, but
2271                         // seems to take too long to generate what we need.
2272                         // ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2273
2274                         Store (ig, vi.Idx);
2275                 }
2276                 
2277                 public void AddressOf (EmitContext ec)
2278                 {
2279                         VariableInfo vi = VariableInfo;
2280                         int idx = vi.Idx;
2281
2282                         vi.Used = true;
2283                         vi.Assigned = true;
2284                         
2285                         if (idx <= 255)
2286                                 ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx);
2287                         else
2288                                 ec.ig.Emit (OpCodes.Ldloca, idx);
2289                 }
2290         }
2291
2292         /// <summary>
2293         ///   This represents a reference to a parameter in the intermediate
2294         ///   representation.
2295         /// </summary>
2296         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation {
2297                 Parameters pars;
2298                 String name;
2299                 int idx;
2300                 bool is_ref;
2301                 
2302                 public ParameterReference (Parameters pars, int idx, string name)
2303                 {
2304                         this.pars = pars;
2305                         this.idx  = idx;
2306                         this.name = name;
2307                         eclass = ExprClass.Variable;
2308                 }
2309
2310                 //
2311                 // Notice that for ref/out parameters, the type exposed is not the
2312                 // same type exposed externally.
2313                 //
2314                 // for "ref int a":
2315                 //   externally we expose "int&"
2316                 //   here we expose       "int".
2317                 //
2318                 // We record this in "is_ref".  This means that the type system can treat
2319                 // the type as it is expected, but when we generate the code, we generate
2320                 // the alternate kind of code.
2321                 //
2322                 public override Expression DoResolve (EmitContext ec)
2323                 {
2324                         type = pars.GetParameterInfo (ec.TypeContainer, idx, out is_ref);
2325                         eclass = ExprClass.Variable;
2326                         
2327                         return this;
2328                 }
2329
2330                 public override void Emit (EmitContext ec)
2331                 {
2332                         ILGenerator ig = ec.ig;
2333                         int arg_idx = idx;
2334
2335                         if (!ec.IsStatic)
2336                                 arg_idx++;
2337                         
2338                         if (arg_idx <= 255)
2339                                 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2340                         else
2341                                 ig.Emit (OpCodes.Ldarg, arg_idx);
2342
2343                         if (!is_ref)
2344                                 return;
2345
2346                         //
2347                         // If we are a reference, we loaded on the stack a pointer
2348                         // Now lets load the real value
2349                         //
2350
2351                         if (type == TypeManager.int32_type)
2352                                 ig.Emit (OpCodes.Ldind_I4);
2353                         else if (type == TypeManager.uint32_type)
2354                                 ig.Emit (OpCodes.Ldind_U4);
2355                         else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
2356                                 ig.Emit (OpCodes.Ldind_I8);
2357                         else if (type == TypeManager.char_type)
2358                                 ig.Emit (OpCodes.Ldind_U2);
2359                         else if (type == TypeManager.short_type)
2360                                 ig.Emit (OpCodes.Ldind_I2);
2361                         else if (type == TypeManager.ushort_type)
2362                                 ig.Emit (OpCodes.Ldind_U2);
2363                         else if (type == TypeManager.float_type)
2364                                 ig.Emit (OpCodes.Ldind_R4);
2365                         else if (type == TypeManager.double_type)
2366                                 ig.Emit (OpCodes.Ldind_R8);
2367                         else if (type == TypeManager.byte_type)
2368                                 ig.Emit (OpCodes.Ldind_U1);
2369                         else if (type == TypeManager.sbyte_type || type == TypeManager.bool_type)
2370                                 ig.Emit (OpCodes.Ldind_I1);
2371                         else if (type == TypeManager.intptr_type)
2372                                 ig.Emit (OpCodes.Ldind_I);
2373                         else
2374                                 ig.Emit (OpCodes.Ldind_Ref);
2375                 }
2376
2377                 public void EmitAssign (EmitContext ec, Expression source)
2378                 {
2379                         ILGenerator ig = ec.ig;
2380                         int arg_idx = idx;
2381
2382                         if (!ec.IsStatic)
2383                                 arg_idx++;
2384
2385                         if (is_ref){
2386                                 // Load the pointer
2387                                 if (arg_idx <= 255)
2388                                         ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2389                                 else
2390                                         ig.Emit (OpCodes.Ldarg, arg_idx);
2391                         }
2392                         
2393                         source.Emit (ec);
2394
2395                         if (is_ref){
2396                                 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
2397                                         ig.Emit (OpCodes.Stind_I4);
2398                                 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
2399                                         ig.Emit (OpCodes.Stind_I8);
2400                                 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
2401                                         type == TypeManager.ushort_type)
2402                                         ig.Emit (OpCodes.Stind_I2);
2403                                 else if (type == TypeManager.float_type)
2404                                         ig.Emit (OpCodes.Stind_R4);
2405                                 else if (type == TypeManager.double_type)
2406                                         ig.Emit (OpCodes.Stind_R8);
2407                                 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
2408                                         type == TypeManager.bool_type)
2409                                         ig.Emit (OpCodes.Stind_I1);
2410                                 else if (type == TypeManager.intptr_type)
2411                                         ig.Emit (OpCodes.Stind_I);
2412                                 else
2413                                         ig.Emit (OpCodes.Stind_Ref);
2414                         } else {
2415                                 if (arg_idx <= 255)
2416                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
2417                                 else
2418                                         ig.Emit (OpCodes.Starg, arg_idx);
2419                         }
2420                         
2421                 }
2422
2423                 public void AddressOf (EmitContext ec)
2424                 {
2425                         int arg_idx = idx;
2426
2427                         if (!ec.IsStatic)
2428                                 arg_idx++;
2429
2430                         if (arg_idx <= 255)
2431                                 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
2432                         else
2433                                 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
2434                 }
2435         }
2436         
2437         /// <summary>
2438         ///   Used for arguments to New(), Invocation()
2439         /// </summary>
2440         public class Argument {
2441                 public enum AType : byte {
2442                         Expression,
2443                         Ref,
2444                         Out
2445                 };
2446
2447                 public readonly AType ArgType;
2448                 public Expression expr;
2449                 
2450                 public Argument (Expression expr, AType type)
2451                 {
2452                         this.expr = expr;
2453                         this.ArgType = type;
2454                 }
2455
2456                 public Expression Expr {
2457                         get {
2458                                 return expr;
2459                         }
2460
2461                         set {
2462                                 expr = value;
2463                         }
2464                 }
2465
2466                 public Type Type {
2467                         get {
2468                                 return expr.Type;
2469                         }
2470                 }
2471
2472                 public Parameter.Modifier GetParameterModifier ()
2473                 {
2474                         if (ArgType == AType.Ref)
2475                                 return Parameter.Modifier.REF;
2476
2477                         if (ArgType == AType.Out)
2478                                 return Parameter.Modifier.OUT;
2479
2480                         return Parameter.Modifier.NONE;
2481                 }
2482
2483                 public static string FullDesc (Argument a)
2484                 {
2485                         return (a.ArgType == AType.Ref ? "ref " :
2486                                 (a.ArgType == AType.Out ? "out " : "")) +
2487                                 TypeManager.CSharpName (a.Expr.Type);
2488                 }
2489                 
2490                 public bool Resolve (EmitContext ec, Location loc)
2491                 {
2492                         expr = expr.Resolve (ec);
2493
2494                         if (ArgType == AType.Expression)
2495                                 return expr != null;
2496
2497                         if (expr.eclass != ExprClass.Variable){
2498                                 Report.Error (206, loc,
2499                                               "A property or indexer can not be passed as an out or ref " +
2500                                               "parameter");
2501                                 return false;
2502                         }
2503                                 
2504                         return expr != null;
2505                 }
2506
2507                 public void Emit (EmitContext ec)
2508                 {
2509                         if (ArgType == AType.Ref || ArgType == AType.Out)
2510                                 ((IMemoryLocation)expr).AddressOf (ec);
2511                         else
2512                                 expr.Emit (ec);
2513                 }
2514         }
2515
2516         /// <summary>
2517         ///   Invocation of methods or delegates.
2518         /// </summary>
2519         public class Invocation : ExpressionStatement {
2520                 public readonly ArrayList Arguments;
2521                 Location loc;
2522
2523                 Expression expr;
2524                 MethodBase method = null;
2525                         
2526                 static Hashtable method_parameter_cache;
2527
2528                 static Invocation ()
2529                 {
2530                         method_parameter_cache = new PtrHashtable ();
2531                 }
2532                         
2533                 //
2534                 // arguments is an ArrayList, but we do not want to typecast,
2535                 // as it might be null.
2536                 //
2537                 // FIXME: only allow expr to be a method invocation or a
2538                 // delegate invocation (7.5.5)
2539                 //
2540                 public Invocation (Expression expr, ArrayList arguments, Location l)
2541                 {
2542                         this.expr = expr;
2543                         Arguments = arguments;
2544                         loc = l;
2545                 }
2546
2547                 public Expression Expr {
2548                         get {
2549                                 return expr;
2550                         }
2551                 }
2552
2553                 /// <summary>
2554                 ///   Returns the Parameters (a ParameterData interface) for the
2555                 ///   Method `mb'
2556                 /// </summary>
2557                 public static ParameterData GetParameterData (MethodBase mb)
2558                 {
2559                         object pd = method_parameter_cache [mb];
2560                         object ip;
2561                         
2562                         if (pd != null)
2563                                 return (ParameterData) pd;
2564
2565                         
2566                         ip = TypeManager.LookupParametersByBuilder (mb);
2567                         if (ip != null){
2568                                 method_parameter_cache [mb] = ip;
2569
2570                                 return (ParameterData) ip;
2571                         } else {
2572                                 ParameterInfo [] pi = mb.GetParameters ();
2573                                 ReflectionParameters rp = new ReflectionParameters (pi);
2574                                 method_parameter_cache [mb] = rp;
2575
2576                                 return (ParameterData) rp;
2577                         }
2578                 }
2579
2580                 /// <summary>
2581                 ///   Tells whether a user defined conversion from Type `from' to
2582                 ///   Type `to' exists.
2583                 ///
2584                 ///   FIXME: we could implement a cache here. 
2585                 /// </summary>
2586                 static bool ConversionExists (EmitContext ec, Type from, Type to, Location loc)
2587                 {
2588                         // Locate user-defined implicit operators
2589
2590                         Expression mg;
2591                         
2592                         mg = MemberLookup (ec, to, "op_Implicit", false, loc);
2593
2594                         if (mg != null) {
2595                                 MethodGroupExpr me = (MethodGroupExpr) mg;
2596                                 
2597                                 for (int i = me.Methods.Length; i > 0;) {
2598                                         i--;
2599                                         MethodBase mb = me.Methods [i];
2600                                         ParameterData pd = GetParameterData (mb);
2601                                         
2602                                         if (from == pd.ParameterType (0))
2603                                                 return true;
2604                                 }
2605                         }
2606
2607                         mg = MemberLookup (ec, from, "op_Implicit", false, loc);
2608
2609                         if (mg != null) {
2610                                 MethodGroupExpr me = (MethodGroupExpr) mg;
2611
2612                                 for (int i = me.Methods.Length; i > 0;) {
2613                                         i--;
2614                                         MethodBase mb = me.Methods [i];
2615                                         MethodInfo mi = (MethodInfo) mb;
2616                                         
2617                                         if (mi.ReturnType == to)
2618                                                 return true;
2619                                 }
2620                         }
2621                         
2622                         return false;
2623                 }
2624                 
2625                 /// <summary>
2626                 ///  Determines "better conversion" as specified in 7.4.2.3
2627                 ///  Returns : 1 if a->p is better
2628                 ///            0 if a->q or neither is better 
2629                 /// </summary>
2630                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
2631                 {
2632                         Type argument_type = a.Type;
2633                         Expression argument_expr = a.Expr;
2634
2635                         if (argument_type == null)
2636                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
2637
2638                         if (p == q)
2639                                 return 0;
2640                         
2641                         if (argument_type == p)
2642                                 return 1;
2643
2644                         if (argument_type == q)
2645                                 return 0;
2646
2647                         //
2648                         // Now probe whether an implicit constant expression conversion
2649                         // can be used.
2650                         //
2651                         // An implicit constant expression conversion permits the following
2652                         // conversions:
2653                         //
2654                         //    * A constant-expression of type `int' can be converted to type
2655                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
2656                         //      of the expression is withing the range of the destination type.
2657                         //
2658                         //    * A constant-expression of type long can be converted to type
2659                         //      ulong, provided the value of the constant expression is not negative
2660                         //
2661                         // FIXME: Note that this assumes that constant folding has
2662                         // taken place.  We dont do constant folding yet.
2663                         //
2664
2665                         if (argument_expr is IntConstant){
2666                                 IntConstant ei = (IntConstant) argument_expr;
2667                                 int value = ei.Value;
2668                                 
2669                                 if (p == TypeManager.sbyte_type){
2670                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
2671                                                 return 1;
2672                                 } else if (p == TypeManager.byte_type){
2673                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
2674                                                 return 1;
2675                                 } else if (p == TypeManager.short_type){
2676                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
2677                                                 return 1;
2678                                 } else if (p == TypeManager.ushort_type){
2679                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2680                                                 return 1;
2681                                 } else if (p == TypeManager.uint32_type){
2682                                         //
2683                                         // we can optimize this case: a positive int32
2684                                         // always fits on a uint32
2685                                         //
2686                                         if (value >= 0)
2687                                                 return 1;
2688                                 } else if (p == TypeManager.uint64_type){
2689                                         //
2690                                         // we can optimize this case: a positive int32
2691                                         // always fits on a uint64
2692                                         //
2693                                         if (value >= 0)
2694                                                 return 1;
2695                                 }
2696                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
2697                                 LongConstant lc = (LongConstant) argument_expr;
2698                                 
2699                                 if (p == TypeManager.uint64_type){
2700                                         if (lc.Value > 0)
2701                                                 return 1;
2702                                 }
2703                         }
2704
2705                         if (q == null) {
2706
2707                                 Expression tmp;
2708
2709                                 tmp = ConvertImplicitStandard (ec, argument_expr, p, loc);
2710                                 
2711                                 if (tmp != null)
2712                                         return 1;
2713                                 else
2714                                         return 0;
2715
2716                         }
2717
2718                         if (ConversionExists (ec, p, q, loc) == true &&
2719                             ConversionExists (ec, q, p, loc) == false)
2720                                 return 1;
2721
2722                         if (p == TypeManager.sbyte_type)
2723                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
2724                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
2725                                         return 1;
2726
2727                         if (p == TypeManager.short_type)
2728                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
2729                                     q == TypeManager.uint64_type)
2730                                         return 1;
2731
2732                         if (p == TypeManager.int32_type)
2733                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
2734                                         return 1;
2735
2736                         if (p == TypeManager.int64_type)
2737                                 if (q == TypeManager.uint64_type)
2738                                         return 1;
2739
2740                         return 0;
2741                 }
2742                 
2743                 /// <summary>
2744                 ///  Determines "Better function"
2745                 /// </summary>
2746                 /// <remarks>
2747                 ///    and returns an integer indicating :
2748                 ///    0 if candidate ain't better
2749                 ///    1 if candidate is better than the current best match
2750                 /// </remarks>
2751                 static int BetterFunction (EmitContext ec, ArrayList args,
2752                                            MethodBase candidate, MethodBase best,
2753                                            bool expanded_form, Location loc)
2754                 {
2755                         ParameterData candidate_pd = GetParameterData (candidate);
2756                         ParameterData best_pd;
2757                         int argument_count;
2758                 
2759
2760                         if (args == null)
2761                                 argument_count = 0;
2762                         else
2763                                 argument_count = args.Count;
2764
2765                         if (candidate_pd.Count == 0 && argument_count == 0)
2766                                 return 1;
2767
2768                         if (candidate_pd.ParameterModifier (candidate_pd.Count - 1) != Parameter.Modifier.PARAMS)
2769                                 if (candidate_pd.Count != argument_count)
2770                                         return 0;
2771                         
2772                         if (best == null) {
2773                                 int x = 0;
2774                                 for (int j = argument_count; j > 0;) {
2775                                         j--;
2776                                         
2777                                         Argument a = (Argument) args [j];
2778                                         Type t = candidate_pd.ParameterType (j);
2779
2780                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
2781                                                 if (expanded_form)
2782                                                         t = t.GetElementType ();
2783                                         
2784                                         x = BetterConversion (ec, a, t, null, loc);
2785                                         
2786                                         if (x <= 0)
2787                                                 break;
2788                                 }
2789                                 
2790                                 if (x > 0)
2791                                         return 1;
2792                                 else
2793                                         return 0;
2794                         }
2795
2796                         best_pd = GetParameterData (best);
2797
2798                         int rating1 = 0, rating2 = 0;
2799                         
2800                         for (int j = 0; j < argument_count; ++j) {
2801                                 int x, y;
2802                                 
2803                                 Argument a = (Argument) args [j];
2804
2805                                 Type ct = candidate_pd.ParameterType (j);
2806                                 Type bt = best_pd.ParameterType (j);
2807
2808                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
2809                                         if (expanded_form)
2810                                                 ct = ct.GetElementType ();
2811
2812                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
2813                                         if (expanded_form)
2814                                                 bt = bt.GetElementType ();
2815                                 
2816                                 x = BetterConversion (ec, a, ct, bt, loc);
2817                                 y = BetterConversion (ec, a, bt, ct, loc);
2818                                                       
2819                                 if (x < y)
2820                                         break;
2821                                 
2822                                 rating1 += x;
2823                                 rating2 += y;
2824                         }
2825
2826                         if (rating1 > rating2)
2827                                 return 1;
2828                         else
2829                                 return 0;
2830                 }
2831
2832                 public static string FullMethodDesc (MethodBase mb)
2833                 {
2834                         StringBuilder sb = new StringBuilder (mb.Name);
2835                         ParameterData pd = GetParameterData (mb);
2836
2837                         int count = pd.Count;
2838                         sb.Append (" (");
2839                         
2840                         for (int i = count; i > 0; ) {
2841                                 i--;
2842
2843                                 sb.Append (pd.ParameterDesc (count - i - 1));
2844                                 if (i != 0)
2845                                         sb.Append (", ");
2846                         }
2847                         
2848                         sb.Append (")");
2849                         return sb.ToString ();
2850                 }
2851
2852                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
2853                 {
2854                         MemberInfo [] miset;
2855                         MethodGroupExpr union;
2856                         
2857                         if (mg1 != null && mg2 != null) {
2858                                 
2859                                 MethodGroupExpr left_set = null, right_set = null;
2860                                 int length1 = 0, length2 = 0;
2861                                 
2862                                 left_set = (MethodGroupExpr) mg1;
2863                                 length1 = left_set.Methods.Length;
2864                                 
2865                                 right_set = (MethodGroupExpr) mg2;
2866                                 length2 = right_set.Methods.Length;
2867
2868                                 ArrayList common = new ArrayList ();
2869                                 
2870                                 for (int i = 0; i < left_set.Methods.Length; i++) {
2871                                         for (int j = 0; j < right_set.Methods.Length; j++) {
2872                                                 if (left_set.Methods [i] == right_set.Methods [j]) 
2873                                                         common.Add (left_set.Methods [i]);
2874                                         }
2875                                 }
2876                                 
2877                                 miset = new MemberInfo [length1 + length2 - common.Count];
2878
2879                                 left_set.Methods.CopyTo (miset, 0);
2880
2881                                 int k = 0;
2882                                 
2883                                 for (int j = 0; j < right_set.Methods.Length; j++)
2884                                         if (!common.Contains (right_set.Methods [j]))
2885                                                 miset [length1 + k++] = right_set.Methods [j];
2886                                 
2887                                 union = new MethodGroupExpr (miset);
2888
2889                                 return union;
2890
2891                         } else if (mg1 == null && mg2 != null) {
2892                                 
2893                                 MethodGroupExpr me = (MethodGroupExpr) mg2; 
2894                                 
2895                                 miset = new MemberInfo [me.Methods.Length];
2896                                 me.Methods.CopyTo (miset, 0);
2897
2898                                 union = new MethodGroupExpr (miset);
2899                                 
2900                                 return union;
2901
2902                         } else if (mg2 == null && mg1 != null) {
2903                                 
2904                                 MethodGroupExpr me = (MethodGroupExpr) mg1; 
2905                                 
2906                                 miset = new MemberInfo [me.Methods.Length];
2907                                 me.Methods.CopyTo (miset, 0);
2908
2909                                 union = new MethodGroupExpr (miset);
2910                                 
2911                                 return union;
2912                         }
2913                         
2914                         return null;
2915                 }
2916
2917                 /// <summary>
2918                 ///  Determines is the candidate method, if a params method, is applicable
2919                 ///  in its expanded form to the given set of arguments
2920                 /// </summary>
2921                 static bool IsParamsMethodApplicable (ArrayList arguments, MethodBase candidate)
2922                 {
2923                         int arg_count;
2924                         
2925                         if (arguments == null)
2926                                 arg_count = 0;
2927                         else
2928                                 arg_count = arguments.Count;
2929                         
2930                         ParameterData pd = GetParameterData (candidate);
2931                         
2932                         int pd_count = pd.Count;
2933
2934                         if (pd_count == 0)
2935                                 return false;
2936                         
2937                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
2938                                 return false;
2939                         
2940                         if (pd_count - 1 > arg_count)
2941                                 return false;
2942
2943                         //
2944                         // If we have come this far, the case which remains is when the number of parameters
2945                         // is less than or equal to the argument count. So, we now check if the element type
2946                         // of the params array is compatible with each argument type
2947                         //
2948
2949                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
2950
2951                         for (int i = pd_count - 1; i < arg_count - 1; i++) {
2952                                 Argument a = (Argument) arguments [i];
2953                                 
2954                                 if (!StandardConversionExists (a.Type, element_type))
2955                                         return false;
2956                         }
2957                         
2958                         return true;
2959                 }
2960
2961                 /// <summary>
2962                 ///  Determines if the candidate method is applicable (section 14.4.2.1)
2963                 ///  to the given set of arguments
2964                 /// </summary>
2965                 static bool IsApplicable (ArrayList arguments, MethodBase candidate)
2966                 {
2967                         int arg_count;
2968
2969                         if (arguments == null)
2970                                 arg_count = 0;
2971                         else
2972                                 arg_count = arguments.Count;
2973
2974                         ParameterData pd = GetParameterData (candidate);
2975
2976                         int pd_count = pd.Count;
2977
2978                         if (arg_count != pd.Count)
2979                                 return false;
2980
2981                         for (int i = arg_count; i > 0; ) {
2982                                 i--;
2983
2984                                 Argument a = (Argument) arguments [i];
2985
2986                                 Parameter.Modifier a_mod = a.GetParameterModifier ();
2987                                 Parameter.Modifier p_mod = pd.ParameterModifier (i);
2988
2989                                 if (a_mod == p_mod) {
2990                                         
2991                                         if (a_mod == Parameter.Modifier.NONE)
2992                                                 if (!StandardConversionExists (a.Type, pd.ParameterType (i)))
2993                                                         return false;
2994                                         
2995                                         if (a_mod == Parameter.Modifier.REF ||
2996                                             a_mod == Parameter.Modifier.OUT)
2997                                                 if (pd.ParameterType (i) != a.Type)
2998                                                         return false;
2999                                 } else
3000                                         return false;
3001                         }
3002
3003                         return true;
3004                 }
3005                 
3006                 
3007
3008                 /// <summary>
3009                 ///   Find the Applicable Function Members (7.4.2.1)
3010                 ///
3011                 ///   me: Method Group expression with the members to select.
3012                 ///       it might contain constructors or methods (or anything
3013                 ///       that maps to a method).
3014                 ///
3015                 ///   Arguments: ArrayList containing resolved Argument objects.
3016                 ///
3017                 ///   loc: The location if we want an error to be reported, or a Null
3018                 ///        location for "probing" purposes.
3019                 ///
3020                 ///   use_standard: controls whether OverloadResolve should use the 
3021                 ///   ConvertImplicit or ConvertImplicitStandard during overload resolution.
3022                 ///
3023                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3024                 ///            that is the best match of me on Arguments.
3025                 ///
3026                 /// </summary>
3027                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3028                                                           ArrayList Arguments, Location loc)
3029                 {
3030                         ArrayList afm = new ArrayList ();
3031                         int best_match_idx = -1;
3032                         MethodBase method = null;
3033                         int argument_count;
3034                         ArrayList candidates = new ArrayList ();
3035                         
3036                         for (int i = me.Methods.Length; i > 0; ){
3037                                 i--;
3038                                 MethodBase candidate  = me.Methods [i];
3039                                 int x;
3040
3041                                 // Check if candidate is applicable (section 14.4.2.1)
3042                                 if (!IsApplicable (Arguments, candidate))
3043                                         continue;
3044
3045                                 candidates.Add (candidate);
3046                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
3047                                 
3048                                 if (x == 0)
3049                                         continue;
3050                                 else {
3051                                         best_match_idx = i;
3052                                         method = me.Methods [best_match_idx];
3053                                 }
3054                         }
3055
3056                         if (Arguments == null)
3057                                 argument_count = 0;
3058                         else
3059                                 argument_count = Arguments.Count;
3060                         
3061                         //
3062                         // Now we see if we can find params functions, applicable in their expanded form
3063                         // since if they were applicable in their normal form, they would have been selected
3064                         // above anyways
3065                         //
3066                         bool chose_params_expanded = false;
3067                         
3068                         if (best_match_idx == -1) {
3069
3070                                 candidates = new ArrayList ();
3071                                 for (int i = me.Methods.Length; i > 0; ) {
3072                                         i--;
3073                                         MethodBase candidate = me.Methods [i];
3074
3075                                         if (!IsParamsMethodApplicable (Arguments, candidate))
3076                                                 continue;
3077
3078                                         candidates.Add (candidate);
3079
3080                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
3081
3082                                         if (x == 0)
3083                                                 continue;
3084                                         else {
3085                                                 best_match_idx = i;
3086                                                 method = me.Methods [best_match_idx];
3087                                                 chose_params_expanded = true;
3088                                         }
3089                                 }
3090                         }
3091
3092                         //
3093                         // Now we see if we can at least find a method with the same number of arguments
3094                         //
3095                         ParameterData pd;
3096                         int method_count = 0;
3097
3098                         if (best_match_idx == -1) {
3099                                 
3100                                 for (int i = me.Methods.Length; i > 0;) {
3101                                         i--;
3102                                         MethodBase mb = me.Methods [i];
3103                                         pd = GetParameterData (mb);
3104                                         
3105                                         if (pd.Count == argument_count) {
3106                                                 best_match_idx = i;
3107                                                 method = me.Methods [best_match_idx];
3108                                                 method_count++;
3109                                         } else
3110                                                 continue;
3111                                 }
3112                         }
3113
3114                         if (method == null)
3115                                 return null;
3116
3117
3118                         //
3119                         // Now check that there are no ambiguities i.e the selected method
3120                         // should be better than all the others
3121                         //
3122
3123                         for (int i = 0; i < candidates.Count; ++i) {
3124                                 MethodBase candidate = (MethodBase) candidates [i];
3125                                 
3126                                 if (candidate == method)
3127                                         continue;
3128
3129                                 int x = BetterFunction (ec, Arguments, method, candidate,
3130                                                         chose_params_expanded, loc);
3131
3132                                 if (x != 1) {
3133                                         Console.WriteLine (candidate + "  " + method);
3134                                         Report.Error (
3135                                                 121, loc,
3136                                                 "Ambiguous call when selecting function due to implicit casts");
3137                                         return null;
3138                                 }
3139                         }
3140                         
3141                         // And now convert implicitly, each argument to the required type
3142                         
3143                         pd = GetParameterData (method);
3144                         int pd_count = pd.Count;
3145
3146                         for (int j = 0; j < argument_count; j++) {
3147                                 Argument a = (Argument) Arguments [j];
3148                                 Expression a_expr = a.Expr;
3149                                 Type parameter_type = pd.ParameterType (j);
3150
3151                                 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS && chose_params_expanded)
3152                                         parameter_type = parameter_type.GetElementType ();
3153
3154                                 if (a.Type != parameter_type){
3155                                         Expression conv;
3156                                         
3157                                         conv = ConvertImplicitStandard (ec, a_expr, parameter_type, Location.Null);
3158
3159                                         if (conv == null) {
3160                                                 if (!Location.IsNull (loc)) {
3161                                                         Error (1502, loc,
3162                                                                "The best overloaded match for method '" +
3163                                                                FullMethodDesc (method) +
3164                                                                "' has some invalid arguments");
3165                                                         Error (1503, loc,
3166                                                          "Argument " + (j+1) +
3167                                                          ": Cannot convert from '" + Argument.FullDesc (a) 
3168                                                          + "' to '" + pd.ParameterDesc (j) + "'");
3169                                                 }
3170                                                 return null;
3171                                         }
3172                                         
3173                                         //
3174                                         // Update the argument with the implicit conversion
3175                                         //
3176                                         if (a_expr != conv)
3177                                                 a.Expr = conv;
3178
3179                                         // FIXME : For the case of params methods, we need to actually instantiate
3180                                         // an array and initialize it with the argument values etc etc.
3181
3182                                 }
3183                                 
3184                                 if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
3185                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
3186                                         if (!Location.IsNull (loc)) {
3187                                                 Error (1502, loc,
3188                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
3189                                                        "' has some invalid arguments");
3190                                                 Error (1503, loc,
3191                                                        "Argument " + (j+1) +
3192                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
3193                                                        + "' to '" + pd.ParameterDesc (j) + "'");
3194                                         }
3195                                         return null;
3196                                 }
3197                         }
3198                         
3199                         return method;
3200                 }
3201                 
3202                 public override Expression DoResolve (EmitContext ec)
3203                 {
3204                         //
3205                         // First, resolve the expression that is used to
3206                         // trigger the invocation
3207                         //
3208                         expr = expr.Resolve (ec);
3209                         if (expr == null)
3210                                 return null;
3211
3212                         if (!(expr is MethodGroupExpr)) {
3213                                 Type expr_type = expr.Type;
3214
3215                                 if (expr_type != null){
3216                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
3217                                         if (IsDelegate)
3218                                                 return (new DelegateInvocation (
3219                                                         this.expr, Arguments, loc)).Resolve (ec);
3220                                 }
3221                         }
3222
3223                         if (!(expr is MethodGroupExpr)){
3224                                 report118 (loc, this.expr, "method group");
3225                                 return null;
3226                         }
3227
3228                         //
3229                         // Next, evaluate all the expressions in the argument list
3230                         //
3231                         if (Arguments != null){
3232                                 for (int i = Arguments.Count; i > 0;){
3233                                         --i;
3234                                         Argument a = (Argument) Arguments [i];
3235
3236                                         if (!a.Resolve (ec, loc))
3237                                                 return null;
3238                                 }
3239                         }
3240
3241                         method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);
3242
3243                         if (method == null){
3244                                 Error (-6, loc,
3245                                        "Could not find any applicable function for this argument list");
3246                                 return null;
3247                         }
3248
3249                         if (method is MethodInfo)
3250                                 type = ((MethodInfo)method).ReturnType;
3251
3252                         eclass = ExprClass.Value;
3253                         return this;
3254                 }
3255
3256                 // <summary>
3257                 //   Emits the list of arguments as an array
3258                 // </summary>
3259                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
3260                 {
3261                         ILGenerator ig = ec.ig;
3262                         int count = arguments.Count - idx;
3263                         Argument a = (Argument) arguments [idx];
3264                         Type t = a.expr.Type;
3265                         string array_type = t.FullName + "[]";
3266                         LocalBuilder array;
3267                         
3268                         array = ig.DeclareLocal (Type.GetType (array_type));
3269                         IntConstant.EmitInt (ig, count);
3270                         ig.Emit (OpCodes.Newarr, t);
3271                         ig.Emit (OpCodes.Stloc, array);
3272
3273                         int top = arguments.Count;
3274                         for (int j = idx; j < top; j++){
3275                                 a = (Argument) arguments [j];
3276                                 
3277                                 ig.Emit (OpCodes.Ldloc, array);
3278                                 IntConstant.EmitInt (ig, j - idx);
3279                                 a.Emit (ec);
3280                                 
3281                                 ArrayAccess.EmitStoreOpcode (ig, t);
3282                         }
3283                         ig.Emit (OpCodes.Ldloc, array);
3284                 }
3285                 
3286                 /// <summary>
3287                 ///   Emits a list of resolved Arguments that are in the arguments
3288                 ///   ArrayList.
3289                 /// 
3290                 ///   The MethodBase argument might be null if the
3291                 ///   emission of the arguments is known not to contain
3292                 ///   a `params' field (for example in constructors or other routines
3293                 ///   that keep their arguments in this structure
3294                 /// </summary>
3295                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
3296                 {
3297                         ParameterData pd = null;
3298                         int top;
3299
3300                         if (arguments != null)
3301                                 top = arguments.Count;
3302                         else
3303                                 top = 0;
3304
3305                         if (mb != null)
3306                                  pd = GetParameterData (mb);
3307
3308                         for (int i = 0; i < top; i++){
3309                                 Argument a = (Argument) arguments [i];
3310
3311                                 if (pd != null){
3312                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
3313                                                 EmitParams (ec, i, arguments);
3314                                                 return;
3315                                         }
3316                                 }
3317                                             
3318                                 a.Emit (ec);
3319                         }
3320                 }
3321
3322                 public static void EmitCall (EmitContext ec,
3323                                              bool is_static, Expression instance_expr,
3324                                              MethodBase method, ArrayList Arguments)
3325                 {
3326                         ILGenerator ig = ec.ig;
3327                         bool struct_call = false;
3328                                 
3329                         if (!is_static){
3330                                 
3331                                 if (method.DeclaringType.IsValueType)
3332                                         struct_call = true;
3333                                 //
3334                                 // If this is ourselves, push "this"
3335                                 //
3336                                 if (instance_expr == null){
3337                                         ig.Emit (OpCodes.Ldarg_0);
3338                                 } else {
3339                                         //
3340                                         // Push the instance expression
3341                                         //
3342                                         if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
3343                                                 //
3344                                                 // Special case: calls to a function declared in a 
3345                                                 // reference-type with a value-type argument need
3346                                                 // to have their value boxed.  
3347
3348                                                 struct_call = true;
3349                                                 if (method.DeclaringType.IsValueType){
3350                                                         //
3351                                                         // If the expression implements IMemoryLocation, then
3352                                                         // we can optimize and use AddressOf on the
3353                                                         // return.
3354                                                         //
3355                                                         // If not we have to use some temporary storage for
3356                                                         // it.
3357                                                         if (instance_expr is IMemoryLocation){
3358                                                                 ((IMemoryLocation)instance_expr).
3359                                                                         AddressOf (ec);
3360                                                         }
3361                                                         else {
3362                                                                 Type t = instance_expr.Type;
3363                                                                 
3364                                                                 instance_expr.Emit (ec);
3365                                                                 LocalBuilder temp = ig.DeclareLocal (t);
3366                                                                 ig.Emit (OpCodes.Stloc, temp);
3367                                                                 ig.Emit (OpCodes.Ldloca, temp);
3368                                                         }
3369                                                 } else {
3370                                                         instance_expr.Emit (ec);
3371                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
3372                                                 } 
3373                                         } else
3374                                                 instance_expr.Emit (ec);
3375                                 }
3376                         }
3377
3378                         if (Arguments != null)
3379                                 EmitArguments (ec, method, Arguments);
3380
3381                         if (method is MethodInfo){
3382                                 MethodInfo mi = (MethodInfo) method;
3383
3384                                 if (!mi.IsVirtual)
3385                                         is_static = true;
3386                         }
3387                         
3388                         if (is_static || struct_call){
3389                                 if (method is MethodInfo)
3390                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3391                                 else
3392                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3393                         } else {
3394                                 if (method is MethodInfo)
3395                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3396                                 else
3397                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3398                         }
3399                 }
3400                 
3401                 public override void Emit (EmitContext ec)
3402                 {
3403                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3404
3405                         EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments);
3406                 }
3407                 
3408                 public override void EmitStatement (EmitContext ec)
3409                 {
3410                         Emit (ec);
3411
3412                         // 
3413                         // Pop the return value if there is one
3414                         //
3415                         if (method is MethodInfo){
3416                                 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3417                                         ec.ig.Emit (OpCodes.Pop);
3418                         }
3419                 }
3420         }
3421
3422         /// <summary>
3423         ///    Implements the new expression 
3424         /// </summary>
3425         public class New : ExpressionStatement {
3426                 public readonly ArrayList Arguments;
3427                 public readonly string    RequestedType;
3428
3429                 Location loc;
3430                 MethodBase method = null;
3431
3432                 //
3433                 // If set, the new expression is for a value_target, and
3434                 // we will not leave anything on the stack.
3435                 //
3436                 Expression value_target;
3437                 
3438                 public New (string requested_type, ArrayList arguments, Location l)
3439                 {
3440                         RequestedType = requested_type;
3441                         Arguments = arguments;
3442                         loc = l;
3443                 }
3444
3445                 public Expression ValueTypeVariable {
3446                         get {
3447                                 return value_target;
3448                         }
3449
3450                         set {
3451                                 value_target = value;
3452                         }
3453                 }
3454
3455                 public override Expression DoResolve (EmitContext ec)
3456                 {
3457                         type = RootContext.LookupType (ec.TypeContainer, RequestedType, false, loc);
3458                         
3459                         if (type == null)
3460                                 return null;
3461                         
3462                         bool IsDelegate = TypeManager.IsDelegateType (type);
3463                         
3464                         if (IsDelegate)
3465                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
3466                         
3467                         bool is_struct = false;
3468                         is_struct = type.IsSubclassOf (TypeManager.value_type);
3469                         eclass = ExprClass.Value;
3470
3471                         //
3472                         // SRE returns a match for .ctor () on structs (the object constructor), 
3473                         // so we have to manually ignore it.
3474                         //
3475                         if (is_struct && Arguments == null)
3476                                 return this;
3477                         
3478                         Expression ml;
3479                         ml = MemberLookup (ec, type, ".ctor", false,
3480                                            MemberTypes.Constructor, AllBindingFlags, loc);
3481                         
3482                         if (! (ml is MethodGroupExpr)){
3483                                 if (!is_struct){
3484                                         report118 (loc, ml, "method group");
3485                                         return null;
3486                                 }
3487                         }
3488                         
3489                         if (ml != null) {
3490                                 if (Arguments != null){
3491                                         for (int i = Arguments.Count; i > 0;){
3492                                                 --i;
3493                                                 Argument a = (Argument) Arguments [i];
3494                                                 
3495                                                 if (!a.Resolve (ec, loc))
3496                                                         return null;
3497                                         }
3498                                 }
3499
3500                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
3501                                                                      Arguments, loc);
3502                                 
3503                         }
3504                         
3505                         if (method == null && !is_struct) {
3506                                 Error (-6, loc,
3507                                        "New invocation: Can not find a constructor for " +
3508                                        "this argument list");
3509                                 return null;
3510                         }
3511                         return this;
3512                 }
3513
3514                 //
3515                 // This DoEmit can be invoked in two contexts:
3516                 //    * As a mechanism that will leave a value on the stack (new object)
3517                 //    * As one that wont (init struct)
3518                 //
3519                 // You can control whether a value is required on the stack by passing
3520                 // need_value_on_stack.  The code *might* leave a value on the stack
3521                 // so it must be popped manually
3522                 //
3523                 // If we are dealing with a ValueType, we have a few
3524                 // situations to deal with:
3525                 //
3526                 //    * The target is a ValueType, and we have been provided
3527                 //      the instance (this is easy, we are being assigned).
3528                 //
3529                 //    * The target of New is being passed as an argument,
3530                 //      to a boxing operation or a function that takes a
3531                 //      ValueType.
3532                 //
3533                 //      In this case, we need to create a temporary variable
3534                 //      that is the argument of New.
3535                 //
3536                 // Returns whether a value is left on the stack
3537                 //
3538                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
3539                 {
3540                         if (method == null){
3541                                 IMemoryLocation ml;
3542
3543                                 if (value_target == null)
3544                                         value_target = new LocalTemporary (ec, type);
3545                                                 
3546                                 ml = (IMemoryLocation) value_target;
3547                                 ml.AddressOf (ec);
3548                         } else {
3549                                 Invocation.EmitArguments (ec, method, Arguments);
3550                                 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
3551                                 return true;
3552                         }
3553
3554                         //
3555                         // It must be a value type, sanity check
3556                         //
3557                         if (value_target != null){
3558                                 ec.ig.Emit (OpCodes.Initobj, type);
3559
3560                                 if (need_value_on_stack){
3561                                         value_target.Emit (ec);
3562                                         return true;
3563                                 }
3564                                 return false;
3565                         }
3566
3567                         throw new Exception ("No method and no value type");
3568                 }
3569
3570                 public override void Emit (EmitContext ec)
3571                 {
3572                         DoEmit (ec, true);
3573                 }
3574                 
3575                 public override void EmitStatement (EmitContext ec)
3576                 {
3577                         if (DoEmit (ec, false))
3578                                 ec.ig.Emit (OpCodes.Pop);
3579                 }
3580         }
3581
3582         /// <summary>
3583         ///   Represents an array creation expression.
3584         /// </summary>
3585         ///
3586         /// <remarks>
3587         ///   There are two possible scenarios here: one is an array creation
3588         ///   expression that specifies the dimensions and optionally the
3589         ///   initialization data and the other which does not need dimensions
3590         ///   specified but where initialization data is mandatory.
3591         /// </remarks>
3592         public class ArrayCreation : ExpressionStatement {
3593                 string RequestedType;
3594                 string Rank;
3595                 ArrayList Initializers;
3596                 Location  loc;
3597                 ArrayList Arguments;
3598                 
3599                 MethodBase method = null;
3600                 Type array_element_type;
3601                 bool IsOneDimensional = false;
3602                 bool IsBuiltinType = false;
3603                 bool ExpectInitializers = false;
3604
3605                 int dimensions = 0;
3606                 Type underlying_type;
3607
3608                 ArrayList ArrayData;
3609
3610                 Hashtable Bounds;
3611
3612                 public ArrayCreation (string requested_type, ArrayList exprs,
3613                                       string rank, ArrayList initializers, Location l)
3614                 {
3615                         RequestedType = requested_type;
3616                         Rank          = rank;
3617                         Initializers  = initializers;
3618                         loc = l;
3619
3620                         Arguments = new ArrayList ();
3621
3622                         foreach (Expression e in exprs)
3623                                 Arguments.Add (new Argument (e, Argument.AType.Expression));
3624
3625                 }
3626
3627                 public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)
3628                 {
3629                         RequestedType = requested_type;
3630                         Initializers = initializers;
3631                         loc = l;
3632
3633                         Rank = rank.Substring (0, rank.LastIndexOf ("["));
3634
3635                         string tmp = rank.Substring (rank.LastIndexOf ("["));
3636
3637                         dimensions = tmp.Length - 1;
3638                         ExpectInitializers = true;
3639                 }
3640
3641                 public static string FormArrayType (string base_type, int idx_count, string rank)
3642                 {
3643                         StringBuilder sb = new StringBuilder (base_type);
3644
3645                         sb.Append (rank);
3646                         
3647                         sb.Append ("[");
3648                         for (int i = 1; i < idx_count; i++)
3649                                 sb.Append (",");
3650                         
3651                         sb.Append ("]");
3652
3653                         return sb.ToString ();
3654                 }
3655
3656                 public static string FormElementType (string base_type, int idx_count, string rank)
3657                 {
3658                         StringBuilder sb = new StringBuilder (base_type);
3659                         
3660                         sb.Append ("[");
3661                         for (int i = 1; i < idx_count; i++)
3662                                 sb.Append (",");
3663                         
3664                         sb.Append ("]");
3665                         
3666                         sb.Append (rank);
3667
3668                         string val = sb.ToString ();
3669
3670                         return val.Substring (0, val.LastIndexOf ("["));
3671                 }
3672
3673                 void error178 ()
3674                 {
3675                         Report.Error (178, loc, "Incorrectly structured array initializer");
3676                 }
3677                 
3678                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
3679                 {
3680                         if (specified_dims) { 
3681                                 Argument a = (Argument) Arguments [idx];
3682                                 
3683                                 if (!a.Resolve (ec, loc))
3684                                         return false;
3685                                 
3686                                 if (!(a.Expr is Constant)) {
3687                                         Report.Error (150, loc, "A constant value is expected");
3688                                         return false;
3689                                 }
3690                                 
3691                                 int value = (int) ((Constant) a.Expr).GetValue ();
3692                                 
3693                                 if (value != probe.Count) {
3694                                         error178 ();
3695                                         return false;
3696                                 }
3697                                 
3698                                 Bounds [idx] = value;
3699                         }
3700                         
3701                         foreach (object o in probe) {
3702                                 if (o is ArrayList) {
3703                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
3704                                         if (!ret)
3705                                                 return false;
3706                                 } else {
3707                                         Expression tmp = (Expression) o;
3708                                         tmp = tmp.Resolve (ec);
3709                                         if (tmp == null)
3710                                                 continue;
3711                                         
3712                                         // Handle initialization from vars, fields etc.
3713
3714                                         Expression conv = ConvertImplicitRequired (
3715                                                 ec, tmp, underlying_type, loc);
3716                                         
3717                                         if (conv == null) 
3718                                                 return false;
3719
3720                                         if (conv is StringConstant)
3721                                                 ArrayData.Add (conv);
3722                                         else if (conv is Constant)
3723                                                 ArrayData.Add (((Constant) conv).GetValue ());
3724                                         else
3725                                                 ArrayData.Add (conv);
3726                                 }
3727                         }
3728
3729                         return true;
3730                 }
3731                 
3732                 public void UpdateIndices (EmitContext ec)
3733                 {
3734                         int i = 0;
3735                         for (ArrayList probe = Initializers; probe != null;) {
3736                                 if (probe.Count > 0 && probe [0] is ArrayList) {
3737                                         Expression e = new IntConstant (probe.Count);
3738                                         Arguments.Add (new Argument (e, Argument.AType.Expression));
3739
3740                                         Bounds [i++] =  probe.Count;
3741                                         
3742                                         probe = (ArrayList) probe [0];
3743                                         
3744                                 } else {
3745                                         Expression e = new IntConstant (probe.Count);
3746                                         Arguments.Add (new Argument (e, Argument.AType.Expression));
3747
3748                                         Bounds [i++] = probe.Count;
3749                                         probe = null;
3750                                 }
3751                         }
3752
3753                 }
3754                 
3755                 public bool ValidateInitializers (EmitContext ec)
3756                 {
3757                         if (Initializers == null) {
3758                                 if (ExpectInitializers)
3759                                         return false;
3760                                 else
3761                                         return true;
3762                         }
3763                         
3764                         underlying_type = RootContext.LookupType (
3765                                 ec.TypeContainer, RequestedType, false, loc);
3766                         
3767                         //
3768                         // We use this to store all the date values in the order in which we
3769                         // will need to store them in the byte blob later
3770                         //
3771                         ArrayData = new ArrayList ();
3772                         Bounds = new Hashtable ();
3773                         
3774                         bool ret;
3775
3776                         if (Arguments != null) {
3777                                 ret = CheckIndices (ec, Initializers, 0, true);
3778                                 return ret;
3779                                 
3780                         } else {
3781                                 Arguments = new ArrayList ();
3782
3783                                 ret = CheckIndices (ec, Initializers, 0, false);
3784                                 
3785                                 if (!ret)
3786                                         return false;
3787                                 
3788                                 UpdateIndices (ec);
3789                                 
3790                                 if (Arguments.Count != dimensions) {
3791                                         error178 ();
3792                                         return false;
3793                                 }
3794
3795                                 return ret;
3796                         }
3797                 }
3798                 
3799                 public override Expression DoResolve (EmitContext ec)
3800                 {
3801                         int arg_count;
3802
3803                         if (!ValidateInitializers (ec))
3804                                 return null;
3805
3806                         if (Arguments == null)
3807                                 arg_count = 0;
3808                         else {
3809                                 arg_count = Arguments.Count;
3810                                 for (int i = arg_count; i > 0;){
3811                                         --i;
3812                                         Argument a = (Argument) Arguments [i];
3813                                         
3814                                         if (!a.Resolve (ec, loc))
3815                                                 return null;
3816                                 }
3817                         }
3818                         
3819                         string array_type = FormArrayType (RequestedType, arg_count, Rank);
3820                         string element_type = FormElementType (RequestedType, arg_count, Rank);
3821
3822                         type = RootContext.LookupType (ec.TypeContainer, array_type, false, loc);
3823                         
3824                         array_element_type = RootContext.LookupType (
3825                                 ec.TypeContainer, element_type, false, loc);
3826                         
3827                         if (type == null)
3828                                 return null;
3829                         
3830                         if (arg_count == 1) {
3831                                 IsOneDimensional = true;
3832                                 eclass = ExprClass.Value;
3833                                 return this;
3834                         }
3835
3836                         IsBuiltinType = TypeManager.IsBuiltinType (type);
3837                         
3838                         if (IsBuiltinType) {
3839                                 
3840                                 Expression ml;
3841                                 
3842                                 ml = MemberLookup (ec, type, ".ctor", false, MemberTypes.Constructor,
3843                                                    AllBindingFlags, loc);
3844                                 
3845                                 if (!(ml is MethodGroupExpr)){
3846                                         report118 (loc, ml, "method group");
3847                                         return null;
3848                                 }
3849                                 
3850                                 if (ml == null) {
3851                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
3852                                                       "this argument list");
3853                                         return null;
3854                                 }
3855                                 
3856                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
3857                                 
3858                                 if (method == null) {
3859                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
3860                                                       "this argument list");
3861                                         return null;
3862                                 }
3863                                 
3864                                 eclass = ExprClass.Value;
3865                                 return this;
3866                                 
3867                         } else {
3868                                 ModuleBuilder mb = RootContext.ModuleBuilder;
3869
3870                                 ArrayList args = new ArrayList ();
3871                                 if (Arguments != null){
3872                                         for (int i = arg_count; i > 0;){
3873                                                 --i;
3874                                                 Argument a = (Argument) Arguments [i];
3875                                                 
3876                                                 args.Add (a.Type);
3877                                         }
3878                                 }
3879                                 
3880                                 Type [] arg_types = null;
3881                                 
3882                                 if (args.Count > 0)
3883                                         arg_types = new Type [args.Count];
3884                                 
3885                                 args.CopyTo (arg_types, 0);
3886                                 
3887                                 method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
3888                                                             arg_types);
3889                                 
3890                                 if (method == null) {
3891                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
3892                                                       "this argument list");
3893                                         return null;
3894                                 }
3895                                 
3896                                 eclass = ExprClass.Value;
3897                                 return this;
3898                                 
3899                         }
3900                 }
3901
3902                 public static byte [] MakeByteBlob (ArrayList ArrayData, Type underlying_type, Location loc)
3903                 {
3904                         int factor;
3905                         byte [] data;
3906
3907                         int count = ArrayData.Count;
3908
3909                         if (underlying_type == TypeManager.int32_type ||
3910                             underlying_type == TypeManager.uint32_type ||
3911                             underlying_type == TypeManager.float_type)
3912                                 factor = 4;
3913                         else if (underlying_type == TypeManager.int64_type ||
3914                                  underlying_type == TypeManager.uint64_type ||
3915                                  underlying_type == TypeManager.double_type)
3916                                 factor = 8;
3917                         else if (underlying_type == TypeManager.byte_type ||
3918                                  underlying_type == TypeManager.sbyte_type ||
3919                                  underlying_type == TypeManager.bool_type)      
3920                                 factor = 1;
3921                         else if (underlying_type == TypeManager.short_type ||
3922                                  underlying_type == TypeManager.char_type ||
3923                                  underlying_type == TypeManager.ushort_type)
3924                                 factor = 2;
3925                         else
3926                                 return null;
3927
3928                         data = new byte [count * factor];
3929                         int idx = 0;
3930                         
3931                         for (int i = 0; i < count; ++i) {
3932                                 object v = ArrayData [i];
3933
3934                                 if (v is EnumConstant)
3935                                         v = ((EnumConstant) v).Child;
3936
3937                                 if (underlying_type == TypeManager.int64_type){
3938                                         long val = 0;
3939                                         if (!(v is Expression))
3940                                                 val = (long) v;
3941
3942                                         for (int j = 0; j < factor; ++j) {
3943                                                 data [idx + j] = (byte) (val & 0xFF);
3944                                                 val = (val >> 8);
3945                                         }
3946                                 } else if (underlying_type == TypeManager.uint64_type){
3947                                         ulong val = 0;
3948                                         if (!(v is Expression))
3949                                                 val = (ulong) v;
3950
3951                                         for (int j = 0; j < factor; ++j) {
3952                                                 data [idx + j] = (byte) (val & 0xFF);
3953                                                 val = (val >> 8);
3954                                         }
3955                                 } else if (underlying_type == TypeManager.float_type) {
3956 #if __MonoCS__
3957 #else
3958                                         unsafe {
3959                                                 float val = 0;
3960
3961                                                 if (!(v is Expression))
3962                                                         val = (float) v;
3963
3964                                                 byte *ptr = (byte *) &val;
3965                                                 
3966                                                 for (int j = 0; j < factor; ++j)
3967                                                         data [idx + j] = (byte) ptr [j];
3968                                         }
3969 #endif
3970                                 } else if (underlying_type == TypeManager.double_type) {
3971 #if __MonoCS__
3972 #else
3973                                         unsafe {
3974                                                 double val = 0;
3975
3976                                                 if (!(v is Expression))
3977                                                         val = (double) v;
3978
3979                                                 byte *ptr = (byte *) &val;
3980                                                 
3981                                                 for (int j = 0; j < factor; ++j)
3982                                                         data [idx + j] = (byte) ptr [j];
3983                                         }
3984 #endif
3985                                 } else if (underlying_type == TypeManager.char_type){
3986                                         int val = 0;
3987
3988                                         if (!(v is Expression))
3989                                                 val = (int) ((char) v);
3990
3991                                         data [idx] = (byte) (val & 0xff);
3992                                         data [idx+1] = (byte) (val >> 8);
3993                                 } else if (underlying_type == TypeManager.short_type){
3994                                         int val = (int) 0;
3995
3996                                         if (!(v is Expression))
3997                                                 val = (int) ((short) v);
3998                                         
3999                                         data [idx] = (byte) (val & 0xff);
4000                                         data [idx+1] = (byte) (val >> 8);
4001
4002                                 } else if (underlying_type == TypeManager.ushort_type){
4003                                         int val = (int) 0;
4004
4005                                         if (!(v is Expression))
4006                                                 val = (int) ((ushort) v);
4007                                         
4008                                         data [idx] = (byte) (val & 0xff);
4009                                         data [idx+1] = (byte) (val >> 8);
4010
4011                                 } else if (underlying_type == TypeManager.int32_type) {
4012                                         int val = 0;
4013                                         
4014                                         if (!(v is Expression))
4015                                                 val = (int) v;
4016                                         
4017                                         data [idx]   = (byte) (val & 0xff);
4018                                         data [idx+1] = (byte) ((val >> 8) & 0xff);
4019                                         data [idx+2] = (byte) ((val >> 16) & 0xff);
4020                                         data [idx+3] = (byte) (val >> 24);
4021                                 } else if (underlying_type == TypeManager.uint32_type) {
4022                                         uint val = 0;
4023                                         
4024                                         if (!(v is Expression))
4025                                                 val = (uint) v;
4026                                         
4027                                         data [idx]   = (byte) (val & 0xff);
4028                                         data [idx+1] = (byte) ((val >> 8) & 0xff);
4029                                         data [idx+2] = (byte) ((val >> 16) & 0xff);
4030                                         data [idx+3] = (byte) (val >> 24);
4031                                 } else if (underlying_type == TypeManager.sbyte_type) {
4032                                         sbyte val = 0;
4033                                         
4034                                         if (!(v is Expression))
4035                                                 val = (sbyte) v;
4036                                         
4037                                         data [idx] = (byte) val;
4038                                 } else if (underlying_type == TypeManager.byte_type) {
4039                                         byte val = 0;
4040                                         
4041                                         if (!(v is Expression))
4042                                                 val = (byte) v;
4043                                         
4044                                         data [idx] = (byte) val;
4045                                 } else
4046                                         throw new Exception ("Unrecognized type in MakeByteBlob");
4047
4048                                 idx += factor;
4049                         }
4050
4051                         return data;
4052                 }
4053
4054                 //
4055                 // Emits the initializers for the array
4056                 //
4057                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
4058                 {
4059                         //
4060                         // First, the static data
4061                         //
4062                         FieldBuilder fb;
4063                         ILGenerator ig = ec.ig;
4064                         
4065                         byte [] data = MakeByteBlob (ArrayData, underlying_type, loc);
4066                         
4067                         if (data != null) {
4068                                 fb = RootContext.MakeStaticData (data);
4069                                 
4070                                 if (is_expression)
4071                                         ig.Emit (OpCodes.Dup);
4072                                 ig.Emit (OpCodes.Ldtoken, fb);
4073                                 ig.Emit (OpCodes.Call,
4074                                          TypeManager.void_initializearray_array_fieldhandle);
4075                         }
4076                 }
4077                 
4078                 //
4079                 // Emits pieces of the array that can not be computed at compile
4080                 // time (variables and string locations).
4081                 //
4082                 // This always expect the top value on the stack to be the array
4083                 //
4084                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
4085                 {
4086                         ILGenerator ig = ec.ig;
4087                         int dims = Bounds.Count;
4088                         int [] current_pos = new int [dims];
4089                         int top = ArrayData.Count;
4090                         LocalBuilder temp = ig.DeclareLocal (type);
4091
4092                         ig.Emit (OpCodes.Stloc, temp);
4093
4094                         MethodInfo set = null;
4095
4096                         if (dims != 1){
4097                                 Type [] args;
4098                                 ModuleBuilder mb = null;
4099                                 mb = RootContext.ModuleBuilder;
4100                                 args = new Type [dims + 1];
4101
4102                                 int j;
4103                                 for (j = 0; j < dims; j++)
4104                                         args [j] = TypeManager.int32_type;
4105
4106                                 args [j] = array_element_type;
4107                                 
4108                                 set = mb.GetArrayMethod (
4109                                         type, "Set",
4110                                         CallingConventions.HasThis | CallingConventions.Standard,
4111                                         TypeManager.void_type, args);
4112                         }
4113                         
4114                         for (int i = 0; i < top; i++){
4115
4116                                 Expression e = null;
4117
4118                                 if (ArrayData [i] is Expression)
4119                                         e = (Expression) ArrayData [i];
4120
4121                                 if (e != null) {
4122                                         //
4123                                         // Basically we do this for string literals and
4124                                         // other non-literal expressions
4125                                         //
4126                                         if (e is StringConstant || !(e is Constant)) {
4127
4128                                                 ig.Emit (OpCodes.Ldloc, temp);
4129
4130                                                 for (int idx = dims; idx > 0; ) {
4131                                                         idx--;
4132                                                         IntConstant.EmitInt (ig, current_pos [idx]);
4133                                                 }
4134
4135                                                 e.Emit (ec);
4136                                                 
4137                                                 if (dims == 1)
4138                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
4139                                                 else 
4140                                                         ig.Emit (OpCodes.Call, set);
4141                                                 
4142                                         }
4143                                 }
4144                                 
4145                                 //
4146                                 // Advance counter
4147                                 //
4148                                 for (int j = 0; j < dims; j++){
4149                                         current_pos [j]++;
4150                                         if (current_pos [j] < (int) Bounds [j])
4151                                                 break;
4152                                         current_pos [j] = 0;
4153                                 }
4154                         }
4155
4156                         if (is_expression)
4157                                 ig.Emit (OpCodes.Ldloc, temp);
4158                 }
4159
4160                 void DoEmit (EmitContext ec, bool is_statement)
4161                 {
4162                         ILGenerator ig = ec.ig;
4163                         
4164                         if (IsOneDimensional) {
4165                                 Invocation.EmitArguments (ec, null, Arguments);
4166                                 ig.Emit (OpCodes.Newarr, array_element_type);
4167                                 
4168                         } else {
4169                                 Invocation.EmitArguments (ec, null, Arguments);
4170
4171                                 if (IsBuiltinType)
4172                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4173                                 else
4174                                         ig.Emit (OpCodes.Newobj, (MethodInfo) method);
4175                         }
4176
4177                         if (Initializers != null){
4178                                 //
4179                                 // FIXME: Set this variable correctly.
4180                                 // 
4181                                 bool dynamic_initializers = true;
4182
4183                                 if (underlying_type != TypeManager.string_type &&
4184                                     underlying_type != TypeManager.object_type)
4185                                         EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
4186                                 
4187                                 if (dynamic_initializers)
4188                                         EmitDynamicInitializers (ec, !is_statement);
4189                         }
4190                 }
4191                 
4192                 public override void Emit (EmitContext ec)
4193                 {
4194                         DoEmit (ec, false);
4195                 }
4196
4197                 public override void EmitStatement (EmitContext ec)
4198                 {
4199                         DoEmit (ec, true);
4200                 }
4201                 
4202         }
4203         
4204         /// <summary>
4205         ///   Represents the `this' construct
4206         /// </summary>
4207         public class This : Expression, IAssignMethod, IMemoryLocation {
4208                 Location loc;
4209                 
4210                 public This (Location loc)
4211                 {
4212                         this.loc = loc;
4213                 }
4214
4215                 public override Expression DoResolve (EmitContext ec)
4216                 {
4217                         eclass = ExprClass.Variable;
4218                         type = ec.TypeContainer.TypeBuilder;
4219
4220                         if (ec.IsStatic){
4221                                 Report.Error (26, loc,
4222                                               "Keyword this not valid in static code");
4223                                 return null;
4224                         }
4225                         
4226                         return this;
4227                 }
4228
4229                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4230                 {
4231                         DoResolve (ec);
4232                         
4233                         if (ec.TypeContainer is Class){
4234                                 Report.Error (1604, loc, "Cannot assign to `this'");
4235                                 return null;
4236                         }
4237
4238                         return this;
4239                 }
4240
4241                 public override void Emit (EmitContext ec)
4242                 {
4243                         ec.ig.Emit (OpCodes.Ldarg_0);
4244                 }
4245
4246                 public void EmitAssign (EmitContext ec, Expression source)
4247                 {
4248                         source.Emit (ec);
4249                         ec.ig.Emit (OpCodes.Starg, 0);
4250                 }
4251
4252                 public void AddressOf (EmitContext ec)
4253                 {
4254                         ec.ig.Emit (OpCodes.Ldarg_0);
4255
4256                         // FIMXE
4257                         // FIGURE OUT WHY LDARG_S does not work
4258                         //
4259                         // consider: struct X { int val; int P { set { val = value; }}}
4260                         //
4261                         // Yes, this looks very bad. Look at `NOTAS' for
4262                         // an explanation.
4263                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4264                 }
4265         }
4266
4267         /// <summary>
4268         ///   Implements the typeof operator
4269         /// </summary>
4270         public class TypeOf : Expression {
4271                 public readonly string QueriedType;
4272                 Type typearg;
4273                 Location loc;
4274                 
4275                 public TypeOf (string queried_type, Location l)
4276                 {
4277                         QueriedType = queried_type;
4278                         loc = l;
4279                 }
4280
4281                 public override Expression DoResolve (EmitContext ec)
4282                 {
4283                         typearg = RootContext.LookupType (
4284                                 ec.TypeContainer, QueriedType, false, loc);
4285
4286                         if (typearg == null)
4287                                 return null;
4288
4289                         type = TypeManager.type_type;
4290                         eclass = ExprClass.Type;
4291                         return this;
4292                 }
4293
4294                 public override void Emit (EmitContext ec)
4295                 {
4296                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
4297                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4298                 }
4299         }
4300
4301         /// <summary>
4302         ///   Implements the sizeof expression
4303         /// </summary>
4304         public class SizeOf : Expression {
4305                 public readonly string QueriedType;
4306                 
4307                 public SizeOf (string queried_type)
4308                 {
4309                         this.QueriedType = queried_type;
4310                 }
4311
4312                 public override Expression DoResolve (EmitContext ec)
4313                 {
4314                         // FIXME: Implement;
4315                         throw new Exception ("Unimplemented");
4316                         // return this;
4317                 }
4318
4319                 public override void Emit (EmitContext ec)
4320                 {
4321                         throw new Exception ("Implement me");
4322                 }
4323         }
4324
4325         /// <summary>
4326         ///   Implements the member access expression
4327         /// </summary>
4328         public class MemberAccess : Expression {
4329                 public readonly string Identifier;
4330                 Expression expr;
4331                 Expression member_lookup;
4332                 Location loc;
4333                 
4334                 public MemberAccess (Expression expr, string id, Location l)
4335                 {
4336                         this.expr = expr;
4337                         Identifier = id;
4338                         loc = l;
4339                 }
4340
4341                 public Expression Expr {
4342                         get {
4343                                 return expr;
4344                         }
4345                 }
4346
4347                 static void error176 (Location loc, string name)
4348                 {
4349                         Report.Error (176, loc, "Static member `" +
4350                                       name + "' cannot be accessed " +
4351                                       "with an instance reference, qualify with a " +
4352                                       "type name instead");
4353                 }
4354
4355 #if USE_OLD
4356                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
4357                 {
4358                         if (left_original == null)
4359                                 return false;
4360
4361                         if (!(left_original is SimpleName))
4362                                 return false;
4363
4364                         SimpleName sn = (SimpleName) left_original;
4365
4366                         Type t = RootContext.LookupType (ec.TypeContainer, sn.Name, true, loc);
4367                         if (t != null)
4368                                 return true;
4369
4370                         return false;
4371                 }
4372                 
4373                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
4374                                                               Expression left, Location loc,
4375                                                               Expression left_original)
4376                 {
4377                         //
4378                         // Method Groups
4379                         //
4380                         if (member_lookup is MethodGroupExpr){
4381                                 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
4382
4383                                 //
4384                                 // Type.MethodGroup
4385                                 //
4386                                 if (left is TypeExpr){
4387                                         if (!mg.RemoveInstanceMethods ()){
4388                                                 SimpleName.Error120 (loc, mg.Methods [0].Name); 
4389                                                 return null;
4390                                         }
4391
4392                                         return member_lookup;
4393                                 }
4394
4395                                 //
4396                                 // Instance.MethodGroup
4397                                 //
4398                                 if (!mg.RemoveStaticMethods ()){
4399                                         if (IdenticalNameAndTypeName (ec, left_original, loc)){
4400                                                 if (!mg.RemoveInstanceMethods ()){
4401                                                         SimpleName.Error120 (loc, mg.Methods [0].Name);
4402                                                         return null;
4403                                                 }
4404                                                 return member_lookup;
4405                                         }
4406                                         
4407                                         error176 (loc, mg.Methods [0].Name);
4408                                         return null;
4409                                 }
4410                                 
4411                                 mg.InstanceExpression = left;
4412                                         
4413                                 return member_lookup;
4414                         }
4415
4416                         if (member_lookup is FieldExpr){
4417                                 FieldExpr fe = (FieldExpr) member_lookup;
4418                                 FieldInfo fi = fe.FieldInfo;
4419
4420                                 if (fi is FieldBuilder) {
4421                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
4422                                         
4423                                         if (c != null) {
4424                                                 object o = c.LookupConstantValue (ec);
4425                                                 object real_value = ((Constant) c.Expr).GetValue ();
4426                                                 return Constantify (real_value, fi.FieldType);
4427                                         }
4428                                 }
4429
4430                                 if (fi.IsLiteral) {
4431                                         Type t = fi.FieldType;
4432                                         Type decl_type = fi.DeclaringType;
4433                                         object o;
4434
4435                                         if (fi is FieldBuilder)
4436                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
4437                                         else
4438                                                 o = fi.GetValue (fi);
4439                                         
4440                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
4441                                                 Expression enum_member = MemberLookup (
4442                                                         ec, decl_type, "value__", false, loc); 
4443
4444                                                 Enum en = TypeManager.LookupEnum (decl_type);
4445
4446                                                 Constant c;
4447                                                 if (en != null)
4448                                                         c = Constantify (o, en.UnderlyingType);
4449                                                 else 
4450                                                         c = Constantify (o, enum_member.Type);
4451                                                 
4452                                                 return new EnumConstant (c, decl_type);
4453                                         }
4454                                         
4455                                         Expression exp = Constantify (o, t);
4456
4457                                         if (!(left is TypeExpr)) {
4458                                                 error176 (loc, fe.FieldInfo.Name);
4459                                                 return null;
4460                                         }
4461                                         
4462                                         return exp;
4463                                 }
4464                                 
4465                                 if (left is TypeExpr){
4466                                         // and refers to a type name or an 
4467                                         if (!fe.FieldInfo.IsStatic){
4468                                                 error176 (loc, fe.FieldInfo.Name);
4469                                                 return null;
4470                                         }
4471                                         return member_lookup;
4472                                 } else {
4473                                         if (fe.FieldInfo.IsStatic){
4474                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
4475                                                         return member_lookup;
4476
4477                                                 error176 (loc, fe.FieldInfo.Name);
4478                                                 return null;
4479                                         }
4480                                         fe.InstanceExpression = left;
4481
4482                                         return fe;
4483                                 }
4484                         }
4485
4486                         if (member_lookup is PropertyExpr){
4487                                 PropertyExpr pe = (PropertyExpr) member_lookup;
4488
4489                                 if (left is TypeExpr){
4490                                         if (!pe.IsStatic){
4491                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
4492                                                 return null;
4493                                         }
4494                                         return pe;
4495                                 } else {
4496                                         if (pe.IsStatic){
4497                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
4498                                                         return member_lookup;
4499                                                 error176 (loc, pe.PropertyInfo.Name);
4500                                                 return null;
4501                                         }
4502                                         pe.InstanceExpression = left;
4503                                         
4504                                         return pe;
4505                                 }
4506                         }
4507
4508                         if (member_lookup is EventExpr) {
4509
4510                                 EventExpr ee = (EventExpr) member_lookup;
4511                                 
4512                                 //
4513                                 // If the event is local to this class, we transform ourselves into
4514                                 // a FieldExpr
4515                                 //
4516
4517                                 Expression ml = MemberLookup (ec, ec.TypeContainer.TypeBuilder, ee.EventInfo.Name,
4518                                                               true, MemberTypes.Event, AllBindingFlags, loc);
4519
4520                                 if (ml != null) {
4521                                         MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
4522
4523                                         if (mi == null) {
4524                                                 //
4525                                                 // If this happens, then we have an event with its own
4526                                                 // accessors and private field etc so there's no need
4527                                                 // to transform ourselves : we should instead flag an error
4528                                                 //
4529                                                 Assign.error70 (ee.EventInfo, loc);
4530                                                 return null;
4531                                         }
4532
4533                                         ml = ExprClassFromMemberInfo (ec, mi, loc);
4534                                         
4535                                         if (ml == null) {
4536                                                 Report.Error (-200, loc, "Internal error!!");
4537                                                 return null;
4538                                         }
4539                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
4540                                 }
4541
4542                                 if (left is TypeExpr) {
4543                                         if (!ee.IsStatic) {
4544                                                 SimpleName.Error120 (loc, ee.EventInfo.Name);
4545                                                 return null;
4546                                         }
4547
4548                                         return ee;
4549
4550                                 } else {
4551                                         if (ee.IsStatic) {
4552                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
4553                                                         return ee;
4554                                                     
4555                                                 error176 (loc, ee.EventInfo.Name);
4556                                                 return null;
4557                                         }
4558
4559                                         ee.InstanceExpression = left;
4560
4561                                         return ee;
4562                                 }
4563                         }
4564
4565                         if (member_lookup is TypeExpr){
4566                                 member_lookup.Resolve (ec);
4567                                 return member_lookup;
4568                         }
4569                         
4570                         Console.WriteLine ("Left is: " + left);
4571                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
4572                         Environment.Exit (0);
4573                         return null;
4574                 }
4575                 
4576                 public override Expression DoResolve (EmitContext ec)
4577                 {
4578                         //
4579                         // We are the sole users of ResolveWithSimpleName (ie, the only
4580                         // ones that can cope with it
4581                         //
4582                         Expression original = expr;
4583                         expr = expr.ResolveWithSimpleName (ec);
4584
4585                         if (expr == null)
4586                                 return null;
4587
4588                         if (expr is SimpleName){
4589                                 SimpleName child_expr = (SimpleName) expr;
4590                                 
4591                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
4592
4593                                 return expr.ResolveWithSimpleName (ec);
4594                         }
4595                                         
4596                         //
4597                         // Handle enums here when they are in transit.
4598                         // Note that we cannot afford to hit MemberLookup in this case because
4599                         // it will fail to find any members at all
4600                         //
4601
4602                         Type expr_type = expr.Type;
4603                         if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
4604                                 
4605                                 Enum en = TypeManager.LookupEnum (expr_type);
4606                                 
4607                                 if (en != null) {
4608                                         object value = en.LookupEnumValue (ec, Identifier, loc);
4609
4610                                         if (value != null){
4611                                                 Constant c = Constantify (value, en.UnderlyingType);
4612                                                 return new EnumConstant (c, expr_type);
4613                                         }
4614                                 }
4615                         }
4616
4617                         member_lookup = MemberLookup (ec, expr_type, Identifier, false, loc);
4618
4619                         if (member_lookup == null)
4620                                 return null;
4621
4622                         return ResolveMemberAccess (ec, member_lookup, expr, loc, original);
4623                 }
4624
4625 #else
4626
4627                 bla bla bla
4628                 //
4629                 // This code is more conformant to the spec (it follows it step by step),
4630                 // but it has not been tested yet, and there is nothing here that is not
4631                 // caught by the above code.  But it might be a better foundation to improve
4632                 // on in the future
4633                 //
4634                 public ResolveTypeMemberAccess (EmitContext ec, Expression member_lookup,
4635                                                 Expression left, Location loc)
4636                 {
4637                         if (member_lookup is TypeExpr){
4638                                 member_lookup.Resolve (ec);
4639                                 return member_lookup;
4640                         }
4641                         
4642                         if (member_lookup is MethodGroupExpr){
4643                                 if (!mg.RemoveStaticMethods ()){
4644                                         SimpleName.Error120 (loc, mg.Methods [0].Name); 
4645                                         return null;
4646                                 }
4647                                 
4648                                 return member_lookup;
4649                         }
4650                         
4651                         if (member_lookup is PropertyExpr){
4652                                 PropertyExpr pe = (PropertyExpr) member_lookup;
4653                                         
4654                                         if (!pe.IsStatic){
4655                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
4656                                                 return null;
4657                                         }
4658                                         return pe;
4659                         }
4660                         
4661                         if (member_lookup is FieldExpr){
4662                                 FieldExpr fe = (FieldExpr) member_lookup;
4663                                 FieldInfo fi = fe.FieldInfo;
4664                                 
4665                                 if (fi is FieldBuilder) {
4666                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
4667                                         
4668                                         if (c != null) {
4669                                                 object o = c.LookupConstantValue (ec);
4670                                                 return Constantify (o, fi.FieldType);
4671                                         }
4672                                 }
4673                                 
4674                                 if (fi.IsLiteral) {
4675                                         Type t = fi.FieldType;
4676                                         Type decl_type = fi.DeclaringType;
4677                                         object o;
4678                                         
4679                                         if (fi is FieldBuilder)
4680                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
4681                                         else
4682                                                 o = fi.GetValue (fi);
4683                                         
4684                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
4685                                                 Expression enum_member = MemberLookup (
4686                                                         ec, decl_type, "value__",
4687                                                         false, loc); 
4688                                                 
4689                                                 Enum en = TypeManager.LookupEnum (decl_type);
4690                                                 
4691                                                 Constant c;
4692                                                 if (en != null)
4693                                                         c = Constantify (o, en.UnderlyingType);
4694                                                 else 
4695                                                         c = Constantify (o, enum_member.Type);
4696                                                 
4697                                                 return new EnumConstant (c, decl_type);
4698                                         }
4699                                         
4700                                         Expression exp = Constantify (o, t);
4701                                         
4702                                         return exp;
4703                                 }
4704
4705                                 if (!fe.FieldInfo.IsStatic){
4706                                         error176 (loc, fe.FieldInfo.Name);
4707                                         return null;
4708                                 }
4709                                 return member_lookup;
4710                         }
4711
4712                         if (member_lookup is EventExpr){
4713
4714                                 EventExpr ee = (EventExpr) member_lookup;
4715                                 
4716                                 //
4717                                 // If the event is local to this class, we transform ourselves into
4718                                 // a FieldExpr
4719                                 //
4720
4721                                 Expression ml = MemberLookup (
4722                                         ec, ec.TypeContainer.TypeBuilder, ee.EventInfo.Name,
4723                                         true, MemberTypes.Event, AllBindingFlags, loc);
4724
4725                                 if (ml != null) {
4726                                         MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
4727
4728                                         ml = ExprClassFromMemberInfo (ec, mi, loc);
4729                                         
4730                                         if (ml == null) {
4731                                                 Report.Error (-200, loc, "Internal error!!");
4732                                                 return null;
4733                                         }
4734
4735                                         return ResolveMemberAccess (ec, ml, left, loc);
4736                                 }
4737
4738                                 if (!ee.IsStatic) {
4739                                         SimpleName.Error120 (loc, ee.EventInfo.Name);
4740                                         return null;
4741                                 }
4742                                 
4743                                 return ee;
4744                         }
4745
4746                         Console.WriteLine ("Left is: " + left);
4747                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
4748                         Environment.Exit (0);
4749
4750                         return null;
4751                 }
4752                 
4753                 public ResolveInstanceMemberAccess (EmitContext ec, Expression member_lookup,
4754                                                     Expression left, Location loc)
4755                 {
4756                         if (member_lookup is MethodGroupExpr){
4757                                 //
4758                                 // Instance.MethodGroup
4759                                 //
4760                                 if (!mg.RemoveStaticMethods ()){
4761                                         error176 (loc, mg.Methods [0].Name);
4762                                         return null;
4763                                 }
4764                                 
4765                                 mg.InstanceExpression = left;
4766                                         
4767                                 return member_lookup;
4768                         }
4769
4770                         if (member_lookup is PropertyExpr){
4771                                 PropertyExpr pe = (PropertyExpr) member_lookup;
4772
4773                                 if (pe.IsStatic){
4774                                         error176 (loc, pe.PropertyInfo.Name);
4775                                         return null;
4776                                 }
4777                                 pe.InstanceExpression = left;
4778                                 
4779                                 return pe;
4780                         }
4781
4782                         Type left_type = left.type;
4783
4784                         if (left_type.IsValueType){
4785                         } else {
4786                                 
4787                         }
4788                 }
4789                 
4790                 public override Expression DoResolve (EmitContext ec)
4791                 {
4792                         //
4793                         // We are the sole users of ResolveWithSimpleName (ie, the only
4794                         // ones that can cope with it
4795                         //
4796                         expr = expr.ResolveWithSimpleName (ec);
4797
4798                         if (expr == null)
4799                                 return null;
4800
4801                         if (expr is SimpleName){
4802                                 SimpleName child_expr = (SimpleName) expr;
4803                                 
4804                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
4805
4806                                 return expr.ResolveWithSimpleName (ec);
4807                         }
4808
4809                         //
4810                         // Handle enums here when they are in transit.
4811                         // Note that we cannot afford to hit MemberLookup in this case because
4812                         // it will fail to find any members at all (Why?)
4813                         //
4814
4815                         Type expr_type = expr.Type;
4816                         if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
4817                                 
4818                                 Enum en = TypeManager.LookupEnum (expr_type);
4819                                 
4820                                 if (en != null) {
4821                                         object value = en.LookupEnumValue (ec, Identifier, loc);
4822
4823                                         if (value == null)
4824                                                 return null;
4825                                         
4826                                         Constant c = Constantify (value, en.UnderlyingType);
4827                                         return new EnumConstant (c, expr_type);
4828                                 }
4829                         }
4830
4831                         member_lookup = MemberLookup (ec, expr.Type, Identifier, false, loc);
4832
4833                         if (member_lookup == null)
4834                                 return null;
4835
4836                         if (expr is TypeExpr)
4837                                 return ResolveTypeMemberAccess (ec, member_lookup, expr, loc);
4838                         else
4839                                 return ResolveInstanceMemberAccess (ec, member_lookup, expr, loc);
4840                 }
4841 #endif
4842                 public override void Emit (EmitContext ec)
4843                 {
4844                         throw new Exception ("Should not happen");
4845                 }
4846         }
4847
4848         /// <summary>
4849         ///   Implements checked expressions
4850         /// </summary>
4851         public class CheckedExpr : Expression {
4852
4853                 public Expression Expr;
4854
4855                 public CheckedExpr (Expression e)
4856                 {
4857                         Expr = e;
4858                 }
4859
4860                 public override Expression DoResolve (EmitContext ec)
4861                 {
4862                         Expr = Expr.Resolve (ec);
4863
4864                         if (Expr == null)
4865                                 return null;
4866
4867                         eclass = Expr.eclass;
4868                         type = Expr.Type;
4869                         return this;
4870                 }
4871
4872                 public override void Emit (EmitContext ec)
4873                 {
4874                         bool last_check = ec.CheckState;
4875                         
4876                         ec.CheckState = true;
4877                         Expr.Emit (ec);
4878                         ec.CheckState = last_check;
4879                 }
4880                 
4881         }
4882
4883         /// <summary>
4884         ///   Implements the unchecked expression
4885         /// </summary>
4886         public class UnCheckedExpr : Expression {
4887
4888                 public Expression Expr;
4889
4890                 public UnCheckedExpr (Expression e)
4891                 {
4892                         Expr = e;
4893                 }
4894
4895                 public override Expression DoResolve (EmitContext ec)
4896                 {
4897                         Expr = Expr.Resolve (ec);
4898
4899                         if (Expr == null)
4900                                 return null;
4901
4902                         eclass = Expr.eclass;
4903                         type = Expr.Type;
4904                         return this;
4905                 }
4906
4907                 public override void Emit (EmitContext ec)
4908                 {
4909                         bool last_check = ec.CheckState;
4910                         
4911                         ec.CheckState = false;
4912                         Expr.Emit (ec);
4913                         ec.CheckState = last_check;
4914                 }
4915                 
4916         }
4917
4918         /// <summary>
4919         ///   An Element Access expression.
4920         ///
4921         ///   During semantic analysis these are transformed into 
4922         ///   IndexerAccess or ArrayAccess 
4923         /// </summary>
4924         public class ElementAccess : Expression {
4925                 public ArrayList  Arguments;
4926                 public Expression Expr;
4927                 public Location   loc;
4928                 
4929                 public ElementAccess (Expression e, ArrayList e_list, Location l)
4930                 {
4931                         Expr = e;
4932
4933                         loc  = l;
4934                         
4935                         if (e_list == null)
4936                                 return;
4937                         
4938                         Arguments = new ArrayList ();
4939                         foreach (Expression tmp in e_list)
4940                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
4941                         
4942                 }
4943
4944                 bool CommonResolve (EmitContext ec)
4945                 {
4946                         Expr = Expr.Resolve (ec);
4947
4948                         if (Expr == null) 
4949                                 return false;
4950
4951                         if (Arguments == null)
4952                                 return false;
4953
4954                         for (int i = Arguments.Count; i > 0;){
4955                                 --i;
4956                                 Argument a = (Argument) Arguments [i];
4957                                 
4958                                 if (!a.Resolve (ec, loc))
4959                                         return false;
4960                         }
4961
4962                         return true;
4963                 }
4964                                 
4965                 public override Expression DoResolve (EmitContext ec)
4966                 {
4967                         if (!CommonResolve (ec))
4968                                 return null;
4969
4970                         //
4971                         // We perform some simple tests, and then to "split" the emit and store
4972                         // code we create an instance of a different class, and return that.
4973                         //
4974                         // I am experimenting with this pattern.
4975                         //
4976                         if (Expr.Type.IsSubclassOf (TypeManager.array_type))
4977                                 return (new ArrayAccess (this)).Resolve (ec);
4978                         else
4979                                 return (new IndexerAccess (this)).Resolve (ec);
4980                 }
4981
4982                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4983                 {
4984                         if (!CommonResolve (ec))
4985                                 return null;
4986
4987                         if (Expr.Type.IsSubclassOf (TypeManager.array_type))
4988                                 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
4989                         else
4990                                 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
4991                 }
4992                 
4993                 public override void Emit (EmitContext ec)
4994                 {
4995                         throw new Exception ("Should never be reached");
4996                 }
4997         }
4998
4999         /// <summary>
5000         ///   Implements array access 
5001         /// </summary>
5002         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
5003                 //
5004                 // Points to our "data" repository
5005                 //
5006                 ElementAccess ea;
5007                 
5008                 public ArrayAccess (ElementAccess ea_data)
5009                 {
5010                         ea = ea_data;
5011                         eclass = ExprClass.Variable;
5012                 }
5013
5014                 public override Expression DoResolve (EmitContext ec)
5015                 {
5016                         if (ea.Expr.eclass != ExprClass.Variable) {
5017                                 report118 (ea.loc, ea.Expr, "variable");
5018                                 return null;
5019                         }
5020
5021                         Type t = ea.Expr.Type;
5022
5023                         if (t.GetArrayRank () != ea.Arguments.Count){
5024                                 Report.Error (22, ea.loc,
5025                                               "Incorrect number of indexes for array " +
5026                                               " expected: " + t.GetArrayRank () + " got: " +
5027                                               ea.Arguments.Count);
5028                                 return null;
5029                         }
5030                         type = t.GetElementType ();
5031                         eclass = ExprClass.Variable;
5032
5033                         return this;
5034                 }
5035
5036                 /// <summary>
5037                 ///    Emits the right opcode to load an object of Type `t'
5038                 ///    from an array of T
5039                 /// </summary>
5040                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
5041                 {
5042                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
5043                                 ig.Emit (OpCodes.Ldelem_I1);
5044                         else if (type == TypeManager.sbyte_type)
5045                                 ig.Emit (OpCodes.Ldelem_U1);
5046                         else if (type == TypeManager.short_type)
5047                                 ig.Emit (OpCodes.Ldelem_I2);
5048                         else if (type == TypeManager.ushort_type)
5049                                 ig.Emit (OpCodes.Ldelem_U2);
5050                         else if (type == TypeManager.int32_type)
5051                                 ig.Emit (OpCodes.Ldelem_I4);
5052                         else if (type == TypeManager.uint32_type)
5053                                 ig.Emit (OpCodes.Ldelem_U4);
5054                         else if (type == TypeManager.uint64_type)
5055                                 ig.Emit (OpCodes.Ldelem_I8);
5056                         else if (type == TypeManager.int64_type)
5057                                 ig.Emit (OpCodes.Ldelem_I8);
5058                         else if (type == TypeManager.float_type)
5059                                 ig.Emit (OpCodes.Ldelem_R4);
5060                         else if (type == TypeManager.double_type)
5061                                 ig.Emit (OpCodes.Ldelem_R8);
5062                         else if (type == TypeManager.intptr_type)
5063                                 ig.Emit (OpCodes.Ldelem_I);
5064                         else if (type.IsValueType){
5065                                 ig.Emit (OpCodes.Ldelema, type);
5066                                 ig.Emit (OpCodes.Ldobj, type);
5067                         } else 
5068                                 ig.Emit (OpCodes.Ldelem_Ref);
5069                 }
5070
5071                 /// <summary>
5072                 ///    Emits the right opcode to store an object of Type `t'
5073                 ///    from an array of T.  
5074                 /// </summary>
5075                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
5076                 {
5077                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
5078                             t == TypeManager.bool_type)
5079                                 ig.Emit (OpCodes.Stelem_I1);
5080                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type)
5081                                 ig.Emit (OpCodes.Stelem_I2);
5082                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
5083                                 ig.Emit (OpCodes.Stelem_I4);
5084                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
5085                                 ig.Emit (OpCodes.Stelem_I8);
5086                         else if (t == TypeManager.float_type)
5087                                 ig.Emit (OpCodes.Stelem_R4);
5088                         else if (t == TypeManager.double_type)
5089                                 ig.Emit (OpCodes.Stelem_R8);
5090                         else if (t == TypeManager.intptr_type)
5091                                 ig.Emit (OpCodes.Stelem_I);
5092                         else if (t.IsValueType)
5093                                 ig.Emit (OpCodes.Stobj, t);
5094                         else
5095                                 ig.Emit (OpCodes.Stelem_Ref);
5096                 }
5097
5098                 MethodInfo FetchGetMethod ()
5099                 {
5100                         ModuleBuilder mb = RootContext.ModuleBuilder;
5101                         Type [] args = new Type [ea.Arguments.Count];
5102                         MethodInfo get;
5103                         
5104                         int i = 0;
5105                                 
5106                         foreach (Argument a in ea.Arguments)
5107                                 args [i++] = a.Type;
5108                         
5109                         get = mb.GetArrayMethod (
5110                                 ea.Expr.Type, "Get",
5111                                 CallingConventions.HasThis |
5112                                 CallingConventions.Standard,
5113                                 type, args);
5114                         return get;
5115                 }
5116                                 
5117
5118                 MethodInfo FetchAddressMethod ()
5119                 {
5120                         ModuleBuilder mb = RootContext.ModuleBuilder;
5121                         Type [] args = new Type [ea.Arguments.Count];
5122                         MethodInfo address;
5123                         string ptr_type_name;
5124                         Type ret_type;
5125                         int i = 0;
5126                         
5127                         ptr_type_name = type.FullName + "&";
5128                         ret_type = Type.GetType (ptr_type_name);
5129                         
5130                         //
5131                         // It is a type defined by the source code we are compiling
5132                         //
5133                         if (ret_type == null){
5134                                 ret_type = mb.GetType (ptr_type_name);
5135                         }
5136                         
5137                         foreach (Argument a in ea.Arguments)
5138                                 args [i++] = a.Type;
5139                         
5140                         address = mb.GetArrayMethod (
5141                                 ea.Expr.Type, "Address",
5142                                 CallingConventions.HasThis |
5143                                 CallingConventions.Standard,
5144                                 ret_type, args);
5145
5146                         return address;
5147                 }
5148                 
5149                 public override void Emit (EmitContext ec)
5150                 {
5151                         int rank = ea.Expr.Type.GetArrayRank ();
5152                         ILGenerator ig = ec.ig;
5153
5154                         ea.Expr.Emit (ec);
5155
5156                         foreach (Argument a in ea.Arguments)
5157                                 a.Expr.Emit (ec);
5158
5159                         if (rank == 1)
5160                                 EmitLoadOpcode (ig, type);
5161                         else {
5162                                 MethodInfo method;
5163                                 
5164                                 method = FetchGetMethod ();
5165                                 ig.Emit (OpCodes.Call, method);
5166                         }
5167                 }
5168
5169                 public void EmitAssign (EmitContext ec, Expression source)
5170                 {
5171                         int rank = ea.Expr.Type.GetArrayRank ();
5172                         ILGenerator ig = ec.ig;
5173
5174                         ea.Expr.Emit (ec);
5175
5176                         foreach (Argument a in ea.Arguments)
5177                                 a.Expr.Emit (ec);
5178
5179                         Type t = source.Type;
5180
5181                         //
5182                         // The stobj opcode used by value types will need
5183                         // an address on the stack, not really an array/array
5184                         // pair
5185                         //
5186                         if (rank == 1){
5187                                 if (t.IsValueType && !TypeManager.IsBuiltinType (t))
5188                                         ig.Emit (OpCodes.Ldelema, t);
5189                         }
5190                         
5191                         source.Emit (ec);
5192
5193                         if (rank == 1)
5194                                 EmitStoreOpcode (ig, t);
5195                         else {
5196                                 ModuleBuilder mb = RootContext.ModuleBuilder;
5197                                 Type [] args = new Type [ea.Arguments.Count + 1];
5198                                 MethodInfo set;
5199                                 
5200                                 int i = 0;
5201                                 
5202                                 foreach (Argument a in ea.Arguments)
5203                                         args [i++] = a.Type;
5204
5205                                 args [i] = type;
5206                                 
5207                                 set = mb.GetArrayMethod (
5208                                         ea.Expr.Type, "Set",
5209                                         CallingConventions.HasThis |
5210                                         CallingConventions.Standard,
5211                                         TypeManager.void_type, args);
5212                                 
5213                                 ig.Emit (OpCodes.Call, set);
5214                         }
5215                 }
5216
5217                 public void AddressOf (EmitContext ec)
5218                 {
5219                         int rank = ea.Expr.Type.GetArrayRank ();
5220                         ILGenerator ig = ec.ig;
5221                         
5222                         ea.Expr.Emit (ec);
5223
5224                         foreach (Argument a in ea.Arguments)
5225                                 a.Expr.Emit (ec);
5226
5227                         if (rank == 1){
5228                                 ig.Emit (OpCodes.Ldelema, type);
5229                         } else {
5230                                 MethodInfo address = FetchAddressMethod ();
5231                                 ig.Emit (OpCodes.Call, address);
5232                         }
5233                 }
5234         }
5235
5236         
5237         class Indexers {
5238                 public ArrayList getters, setters;
5239                 static Hashtable map;
5240
5241                 static Indexers ()
5242                 {
5243                         map = new Hashtable ();
5244                 }
5245
5246                 Indexers (MemberInfo [] mi)
5247                 {
5248                         foreach (PropertyInfo property in mi){
5249                                 MethodInfo get, set;
5250                                 
5251                                 get = property.GetGetMethod (true);
5252                                 if (get != null){
5253                                         if (getters == null)
5254                                                 getters = new ArrayList ();
5255
5256                                         getters.Add (get);
5257                                 }
5258                                 
5259                                 set = property.GetSetMethod (true);
5260                                 if (set != null){
5261                                         if (setters == null)
5262                                                 setters = new ArrayList ();
5263                                         setters.Add (set);
5264                                 }
5265                         }
5266                 }
5267                 
5268                 static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) 
5269                 {
5270                         Indexers ix = (Indexers) map [t];
5271                         string p_name = TypeManager.IndexerPropertyName (t);
5272                         
5273                         if (ix != null)
5274                                 return ix;
5275
5276                         MemberInfo [] mi = tm.FindMembers (
5277                                 t, MemberTypes.Property,
5278                                 BindingFlags.Public | BindingFlags.Instance,
5279                                 Type.FilterName, p_name);
5280
5281                         if (mi == null || mi.Length == 0){
5282                                 Report.Error (21, loc,
5283                                               "Type `" + TypeManager.CSharpName (t) + "' does not have " +
5284                                               "any indexers defined");
5285                                 return null;
5286                         }
5287                         
5288                         ix = new Indexers (mi);
5289                         map [t] = ix;
5290
5291                         return ix;
5292                 }
5293         }
5294
5295         /// <summary>
5296         ///   Expressions that represent an indexer call.
5297         /// </summary>
5298         public class IndexerAccess : Expression, IAssignMethod {
5299                 //
5300                 // Points to our "data" repository
5301                 //
5302                 ElementAccess ea;
5303                 MethodInfo get, set;
5304                 Indexers ilist;
5305                 ArrayList set_arguments;
5306                 
5307                 public IndexerAccess (ElementAccess ea_data)
5308                 {
5309                         ea = ea_data;
5310                         eclass = ExprClass.Value;
5311                 }
5312
5313                 public override Expression DoResolve (EmitContext ec)
5314                 {
5315                         Type indexer_type = ea.Expr.Type;
5316                         
5317                         //
5318                         // Step 1: Query for all `Item' *properties*.  Notice
5319                         // that the actual methods are pointed from here.
5320                         //
5321                         // This is a group of properties, piles of them.  
5322
5323                         if (ilist == null)
5324                                 ilist = Indexers.GetIndexersForType (
5325                                         indexer_type, RootContext.TypeManager, ea.loc);
5326
5327
5328                         //
5329                         // Step 2: find the proper match
5330                         //
5331                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
5332                                 get = (MethodInfo) Invocation.OverloadResolve (
5333                                         ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc);
5334
5335                         if (get == null){
5336                                 Report.Error (154, ea.loc,
5337                                               "indexer can not be used in this context, because " +
5338                                               "it lacks a `get' accessor");
5339                                 return null;
5340                         }
5341
5342                         type = get.ReturnType;
5343                         eclass = ExprClass.IndexerAccess;
5344                         return this;
5345                 }
5346
5347                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5348                 {
5349                         Type indexer_type = ea.Expr.Type;
5350                         Type right_type = right_side.Type;
5351
5352                         if (ilist == null)
5353                                 ilist = Indexers.GetIndexersForType (
5354                                         indexer_type, RootContext.TypeManager, ea.loc);
5355
5356                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
5357                                 set_arguments = (ArrayList) ea.Arguments.Clone ();
5358                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
5359
5360                                 set = (MethodInfo) Invocation.OverloadResolve (
5361                                         ec, new MethodGroupExpr (ilist.setters), set_arguments, ea.loc);
5362                         }
5363                         
5364                         if (set == null){
5365                                 Report.Error (200, ea.loc,
5366                                               "indexer X.this [" + TypeManager.CSharpName (right_type) +
5367                                               "] lacks a `set' accessor");
5368                                         return null;
5369                         }
5370
5371                         type = TypeManager.void_type;
5372                         eclass = ExprClass.IndexerAccess;
5373                         return this;
5374                 }
5375                 
5376                 public override void Emit (EmitContext ec)
5377                 {
5378                         Invocation.EmitCall (ec, false, ea.Expr, get, ea.Arguments);
5379                 }
5380
5381                 //
5382                 // source is ignored, because we already have a copy of it from the
5383                 // LValue resolution and we have already constructed a pre-cached
5384                 // version of the arguments (ea.set_arguments);
5385                 //
5386                 public void EmitAssign (EmitContext ec, Expression source)
5387                 {
5388                         Invocation.EmitCall (ec, false, ea.Expr, set, set_arguments);
5389                 }
5390         }
5391
5392         /// <summary>
5393         ///   The base operator for method names
5394         /// </summary>
5395         public class BaseAccess : Expression {
5396                 string member;
5397                 Location loc;
5398                 
5399                 public BaseAccess (string member, Location l)
5400                 {
5401                         this.member = member;
5402                         loc = l;
5403                 }
5404
5405                 public override Expression DoResolve (EmitContext ec)
5406                 {
5407                         Expression member_lookup;
5408                         Type current_type = ec.TypeContainer.TypeBuilder;
5409                         Type base_type = current_type.BaseType;
5410                         
5411                         member_lookup = MemberLookup (ec, base_type, member, false, loc);
5412                         if (member_lookup == null)
5413                                 return null;
5414
5415                         Expression left;
5416                         
5417                         if (ec.IsStatic)
5418                                 left = new TypeExpr (base_type);
5419                         else
5420                                 left = ec.This;
5421                         
5422                         return MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
5423                 }
5424
5425                 public override void Emit (EmitContext ec)
5426                 {
5427                         throw new Exception ("Should never be called"); 
5428                 }
5429         }
5430
5431         /// <summary>
5432         ///   The base indexer operator
5433         /// </summary>
5434         public class BaseIndexerAccess : Expression {
5435                 ArrayList Arguments;
5436
5437                 public BaseIndexerAccess (ArrayList args)
5438                 {
5439                         Arguments = args;
5440                 }
5441
5442                 public override Expression DoResolve (EmitContext ec)
5443                 {
5444                         // FIXME: Implement;
5445                         throw new Exception ("Unimplemented");
5446                         // return this;
5447                 }
5448
5449                 public override void Emit (EmitContext ec)
5450                 {
5451                         throw new Exception ("Unimplemented");
5452                 }
5453         }
5454         
5455         /// <summary>
5456         ///   This class exists solely to pass the Type around and to be a dummy
5457         ///   that can be passed to the conversion functions (this is used by
5458         ///   foreach implementation to typecast the object return value from
5459         ///   get_Current into the proper type.  All code has been generated and
5460         ///   we only care about the side effect conversions to be performed
5461         /// </summary>
5462         public class EmptyExpression : Expression {
5463                 public EmptyExpression ()
5464                 {
5465                         type = TypeManager.object_type;
5466                         eclass = ExprClass.Value;
5467                 }
5468
5469                 public EmptyExpression (Type t)
5470                 {
5471                         type = t;
5472                         eclass = ExprClass.Value;
5473                 }
5474                 
5475                 public override Expression DoResolve (EmitContext ec)
5476                 {
5477                         return this;
5478                 }
5479
5480                 public override void Emit (EmitContext ec)
5481                 {
5482                         // nothing, as we only exist to not do anything.
5483                 }
5484
5485                 //
5486                 // This is just because we might want to reuse this bad boy
5487                 // instead of creating gazillions of EmptyExpressions.
5488                 // (CanConvertImplicit uses it)
5489                 //
5490                 public void SetType (Type t)
5491                 {
5492                         type = t;
5493                 }
5494         }
5495
5496         public class UserCast : Expression {
5497                 MethodBase method;
5498                 Expression source;
5499                 
5500                 public UserCast (MethodInfo method, Expression source)
5501                 {
5502                         this.method = method;
5503                         this.source = source;
5504                         type = method.ReturnType;
5505                         eclass = ExprClass.Value;
5506                 }
5507
5508                 public override Expression DoResolve (EmitContext ec)
5509                 {
5510                         //
5511                         // We are born fully resolved
5512                         //
5513                         return this;
5514                 }
5515
5516                 public override void Emit (EmitContext ec)
5517                 {
5518                         ILGenerator ig = ec.ig;
5519
5520                         source.Emit (ec);
5521                         
5522                         if (method is MethodInfo)
5523                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
5524                         else
5525                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5526
5527                 }
5528
5529         }
5530
5531         // <summary>
5532         //   This class is used to "construct" the type during a typecast
5533         //   operation.  Since the Type.GetType class in .NET can parse
5534         //   the type specification, we just use this to construct the type
5535         //   one bit at a time.
5536         // </summary>
5537         public class ComposedCast : Expression {
5538                 Expression left;
5539                 string dim;
5540                 Location loc;
5541                 
5542                 public ComposedCast (Expression left, string dim, Location l)
5543                 {
5544                         this.left = left;
5545                         this.dim = dim;
5546                         loc = l;
5547                 }
5548
5549                 public override Expression DoResolve (EmitContext ec)
5550                 {
5551                         left = left.Resolve (ec);
5552                         if (left == null)
5553                                 return null;
5554
5555                         if (left.eclass != ExprClass.Type){
5556                                 report118 (loc, left, "type");
5557                                 return null;
5558                         }
5559                         
5560                         type = RootContext.LookupType (
5561                                 ec.TypeContainer, left.Type.FullName + dim, false, loc);
5562                         if (type == null)
5563                                 return null;
5564
5565                         eclass = ExprClass.Type;
5566                         return this;
5567                 }
5568
5569                 public override void Emit (EmitContext ec)
5570                 {
5571                         throw new Exception ("This should never be called");
5572                 }
5573         }
5574 }