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