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