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