2001-11-05 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 //
10
11 namespace CIR {
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         //   Unary expressions.  
21         // </summary>
22         //
23         // <remarks>
24         //   Unary implements unary expressions.   It derives from
25         //   ExpressionStatement becuase the pre/post increment/decrement
26         //   operators can be used in a statement context.
27         // </remarks>
28         public class Unary : ExpressionStatement {
29                 public enum Operator {
30                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
31                         Indirection, AddressOf, PreIncrement,
32                         PreDecrement, PostIncrement, PostDecrement 
33                 }
34
35                 Operator   oper;
36                 Expression expr;
37                 ArrayList  Arguments;
38                 MethodBase method;
39                 Location   loc;
40                 
41                 public Unary (Operator op, Expression expr, Location loc)
42                 {
43                         this.oper = op;
44                         this.expr = expr;
45                         this.loc = loc;
46                 }
47
48                 public Expression Expr {
49                         get {
50                                 return expr;
51                         }
52
53                         set {
54                                 expr = value;
55                         }
56                 }
57
58                 public Operator Oper {
59                         get {
60                                 return oper;
61                         }
62
63                         set {
64                                 oper = value;
65                         }
66                 }
67
68                 // <summary>
69                 //   Returns a stringified representation of the Operator
70                 // </summary>
71                 string OperName ()
72                 {
73                         switch (oper){
74                         case Operator.UnaryPlus:
75                                 return "+";
76                         case Operator.UnaryNegation:
77                                 return "-";
78                         case Operator.LogicalNot:
79                                 return "!";
80                         case Operator.OnesComplement:
81                                 return "~";
82                         case Operator.AddressOf:
83                                 return "&";
84                         case Operator.Indirection:
85                                 return "*";
86                         case Operator.PreIncrement : case Operator.PostIncrement :
87                                 return "++";
88                         case Operator.PreDecrement : case Operator.PostDecrement :
89                                 return "--";
90                         }
91
92                         return oper.ToString ();
93                 }
94
95                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
96                 {
97                         if (expr.Type == target_type)
98                                 return expr;
99
100                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
101                 }
102
103                 void error23 (Type t)
104                 {
105                         Report.Error (
106                                 23, loc, "Operator " + OperName () +
107                                 " cannot be applied to operand of type `" +
108                                 TypeManager.CSharpName (t) + "'");
109                 }
110
111                 // <summary>
112                 //   Returns whether an object of type `t' can be incremented
113                 //   or decremented with add/sub (ie, basically whether we can
114                 //   use pre-post incr-decr operations on it, but it is not a
115                 //   System.Decimal, which we test elsewhere)
116                 // </summary>
117                 static bool IsIncrementableNumber (Type t)
118                 {
119                         return (t == TypeManager.sbyte_type) ||
120                                 (t == TypeManager.byte_type) ||
121                                 (t == TypeManager.short_type) ||
122                                 (t == TypeManager.ushort_type) ||
123                                 (t == TypeManager.int32_type) ||
124                                 (t == TypeManager.uint32_type) ||
125                                 (t == TypeManager.int64_type) ||
126                                 (t == TypeManager.uint64_type) ||
127                                 (t == TypeManager.char_type) ||
128                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
129                                 (t == TypeManager.float_type) ||
130                                 (t == TypeManager.double_type);
131                 }
132
133                 static Expression TryReduceNegative (Expression expr)
134                 {
135                         Expression e = null;
136                         
137                         if (expr is IntLiteral)
138                                 e = new IntLiteral (-((IntLiteral) expr).Value);
139                         else if (expr is UIntLiteral)
140                                 e = new LongLiteral (-((UIntLiteral) expr).Value);
141                         else if (expr is LongLiteral)
142                                 e = new LongLiteral (-((LongLiteral) expr).Value);
143                         else if (expr is FloatLiteral)
144                                 e = new FloatLiteral (-((FloatLiteral) expr).Value);
145                         else if (expr is DoubleLiteral)
146                                 e = new DoubleLiteral (-((DoubleLiteral) expr).Value);
147                         else if (expr is DecimalLiteral)
148                                 e = new DecimalLiteral (-((DecimalLiteral) expr).Value);
149
150                         return e;
151                 }
152                 
153                 Expression ResolveOperator (EmitContext ec)
154                 {
155                         Type expr_type = expr.Type;
156
157                         //
158                         // Step 1: Perform Operator Overload location
159                         //
160                         Expression mg;
161                         string op_name;
162                         
163                         if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
164                                 op_name = "op_Increment";
165                         else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
166                                 op_name = "op_Decrement";
167                         else
168                                 op_name = "op_" + oper;
169
170                         mg = MemberLookup (ec, expr_type, op_name, false, loc);
171                         
172                         if (mg == null && expr_type.BaseType != null)
173                                 mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc);
174                         
175                         if (mg != null) {
176                                 Arguments = new ArrayList ();
177                                 Arguments.Add (new Argument (expr, Argument.AType.Expression));
178                                 
179                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg,
180                                                                      Arguments, loc);
181                                 if (method != null) {
182                                         MethodInfo mi = (MethodInfo) method;
183                                         type = mi.ReturnType;
184                                         return this;
185                                 } else {
186                                         error23 (expr_type);
187                                         return null;
188                                 }
189                                         
190                         }
191
192                         //
193                         // Step 2: Default operations on CLI native types.
194                         //
195
196                         // Only perform numeric promotions on:
197                         // +, -, ++, --
198
199                         if (expr_type == null)
200                                 return null;
201                         
202                         if (oper == Operator.LogicalNot){
203                                 if (expr_type != TypeManager.bool_type) {
204                                         error23 (expr.Type);
205                                         return null;
206                                 }
207                                 
208                                 type = TypeManager.bool_type;
209                                 return this;
210                         }
211
212                         if (oper == Operator.OnesComplement) {
213                                 if (!((expr_type == TypeManager.int32_type) ||
214                                       (expr_type == TypeManager.uint32_type) ||
215                                       (expr_type == TypeManager.int64_type) ||
216                                       (expr_type == TypeManager.uint64_type) ||
217                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
218                                         error23 (expr.Type);
219                                         return null;
220                                 }
221                                 type = expr_type;
222                                 return this;
223                         }
224
225                         if (oper == Operator.UnaryPlus) {
226                                 //
227                                 // A plus in front of something is just a no-op, so return the child.
228                                 //
229                                 return expr;
230                         }
231
232                         //
233                         // Deals with -literals
234                         // int     operator- (int x)
235                         // long    operator- (long x)
236                         // float   operator- (float f)
237                         // double  operator- (double d)
238                         // decimal operator- (decimal d)
239                         //
240                         if (oper == Operator.UnaryNegation){
241                                 //
242                                 // Fold a "- Constant" into a negative constant
243                                 //
244                         
245                                 Expression e = null;
246
247                                 //
248                                 // Is this a constant? 
249                                 //
250                                 e = TryReduceNegative (expr);
251                                 
252                                 if (e != null){
253                                         e = e.Resolve (ec);
254                                         return e;
255                                 }
256
257                                 //
258                                 // Not a constant we can optimize, perform numeric 
259                                 // promotions to int, long, double.
260                                 //
261                                 //
262                                 // The following is inneficient, because we call
263                                 // ConvertImplicit too many times.
264                                 //
265                                 // It is also not clear if we should convert to Float
266                                 // or Double initially.
267                                 //
268                                 if (expr_type == TypeManager.uint32_type){
269                                         //
270                                         // FIXME: handle exception to this rule that
271                                         // permits the int value -2147483648 (-2^31) to
272                                         // bt written as a decimal interger literal
273                                         //
274                                         type = TypeManager.int64_type;
275                                         expr = ConvertImplicit (ec, expr, type, loc);
276                                         return this;
277                                 }
278
279                                 if (expr_type == TypeManager.uint64_type){
280                                         //
281                                         // FIXME: Handle exception of `long value'
282                                         // -92233720368547758087 (-2^63) to be written as
283                                         // decimal integer literal.
284                                         //
285                                         error23 (expr_type);
286                                         return null;
287                                 }
288
289                                 e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc);
290                                 if (e != null){
291                                         expr = e;
292                                         type = e.Type;
293                                         return this;
294                                 } 
295
296                                 e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc);
297                                 if (e != null){
298                                         expr = e;
299                                         type = e.Type;
300                                         return this;
301                                 }
302
303                                 e = ConvertImplicit (ec, expr, TypeManager.double_type, loc);
304                                 if (e != null){
305                                         expr = e;
306                                         type = e.Type;
307                                         return this;
308                                 }
309
310                                 error23 (expr_type);
311                                 return null;
312                         }
313
314                         //
315                         // The operand of the prefix/postfix increment decrement operators
316                         // should be an expression that is classified as a variable,
317                         // a property access or an indexer access
318                         //
319                         if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
320                             oper == Operator.PostDecrement || oper == Operator.PostIncrement){
321                                 if (expr.ExprClass == ExprClass.Variable){
322                                         if (IsIncrementableNumber (expr_type) ||
323                                             expr_type == TypeManager.decimal_type){
324                                                 type = expr_type;
325                                                 return this;
326                                         }
327                                 } else if (expr.ExprClass == ExprClass.IndexerAccess){
328                                         //
329                                         // FIXME: Verify that we have both get and set methods
330                                         //
331                                         throw new Exception ("Implement me");
332                                 } else if (expr.ExprClass == ExprClass.PropertyAccess){
333                                         PropertyExpr pe = (PropertyExpr) expr;
334                                         
335                                         if (pe.VerifyAssignable ())
336                                                 return this;
337                                         return null;
338                                 } else {
339                                         report118 (loc, expr, "variable, indexer or property access");
340                                 }
341                         }
342
343                         if (oper == Operator.AddressOf){
344                                 if (expr.ExprClass != ExprClass.Variable){
345                                         Error (211, "Cannot take the address of non-variables");
346                                         return null;
347                                 }
348                                 type = Type.GetType (expr.Type.ToString () + "*");
349                         }
350                         
351                         Error (187, "No such operator '" + OperName () + "' defined for type '" +
352                                TypeManager.CSharpName (expr_type) + "'");
353                         return null;
354
355                 }
356
357                 public override Expression DoResolve (EmitContext ec)
358                 {
359                         expr = expr.Resolve (ec);
360                         
361                         if (expr == null)
362                                 return null;
363
364                         eclass = ExprClass.Value;
365                         return ResolveOperator (ec);
366                 }
367
368                 public override void Emit (EmitContext ec)
369                 {
370                         ILGenerator ig = ec.ig;
371                         Type expr_type = expr.Type;
372                         ExprClass eclass;
373                         
374                         if (method != null) {
375
376                                 // Note that operators are static anyway
377                                 
378                                 if (Arguments != null) 
379                                         Invocation.EmitArguments (ec, Arguments);
380
381                                 //
382                                 // Post increment/decrement operations need a copy at this
383                                 // point.
384                                 //
385                                 if (oper == Operator.PostDecrement || oper == Operator.PostIncrement)
386                                         ig.Emit (OpCodes.Dup);
387                                 
388
389                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
390
391                                 //
392                                 // Pre Increment and Decrement operators
393                                 //
394                                 if (oper == Operator.PreIncrement || oper == Operator.PreDecrement){
395                                         ig.Emit (OpCodes.Dup);
396                                 }
397                                 
398                                 //
399                                 // Increment and Decrement should store the result
400                                 //
401                                 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
402                                     oper == Operator.PostDecrement || oper == Operator.PostIncrement){
403                                         ((IStackStore) expr).Store (ec);
404                                 }
405                                 return;
406                         }
407                         
408                         switch (oper) {
409                         case Operator.UnaryPlus:
410                                 throw new Exception ("This should be caught by Resolve");
411                                 
412                         case Operator.UnaryNegation:
413                                 expr.Emit (ec);
414                                 ig.Emit (OpCodes.Neg);
415                                 break;
416                                 
417                         case Operator.LogicalNot:
418                                 expr.Emit (ec);
419                                 ig.Emit (OpCodes.Ldc_I4_0);
420                                 ig.Emit (OpCodes.Ceq);
421                                 break;
422                                 
423                         case Operator.OnesComplement:
424                                 expr.Emit (ec);
425                                 ig.Emit (OpCodes.Not);
426                                 break;
427                                 
428                         case Operator.AddressOf:
429                                 ((IMemoryLocation)expr).AddressOf (ec);
430                                 break;
431                                 
432                         case Operator.Indirection:
433                                 throw new Exception ("Not implemented yet");
434                                 
435                         case Operator.PreIncrement:
436                         case Operator.PreDecrement:
437                                 if (expr.ExprClass == ExprClass.Variable){
438                                         //
439                                         // Resolve already verified that it is an "incrementable"
440                                         // 
441                                         expr.Emit (ec);
442                                         ig.Emit (OpCodes.Ldc_I4_1);
443                                         
444                                         if (oper == Operator.PreDecrement)
445                                                 ig.Emit (OpCodes.Sub);
446                                         else
447                                                 ig.Emit (OpCodes.Add);
448                                         ig.Emit (OpCodes.Dup);
449                                         ((IStackStore) expr).Store (ec);
450                                 } else {
451                                         throw new Exception ("Handle Indexers and Properties here");
452                                 }
453                                 break;
454                                 
455                         case Operator.PostIncrement:
456                         case Operator.PostDecrement:
457                                 eclass = expr.ExprClass;
458                                 if (eclass == ExprClass.Variable){
459                                         //
460                                         // Resolve already verified that it is an "incrementable"
461                                         // 
462                                         expr.Emit (ec);
463                                         ig.Emit (OpCodes.Dup);
464                                         ig.Emit (OpCodes.Ldc_I4_1);
465                                         
466                                         if (oper == Operator.PostDecrement)
467                                                 ig.Emit (OpCodes.Sub);
468                                         else
469                                                 ig.Emit (OpCodes.Add);
470                                         ((IStackStore) expr).Store (ec);
471                                 } else if (eclass == ExprClass.PropertyAccess){
472                                         throw new Exception ("Handle Properties here");
473                                 } else if (eclass == ExprClass.IndexerAccess) {
474                                         throw new Exception ("Handle Indexers here");
475                                 } else {
476                                         Console.WriteLine ("Unknown exprclass: " + eclass);
477                                 }
478                                 break;
479                                 
480                         default:
481                                 throw new Exception ("This should not happen: Operator = "
482                                                      + oper.ToString ());
483                         }
484                 }
485
486                 // <summary>
487                 //   This will emit the child expression for `ec' avoiding the logical
488                 //   not.  The parent will take care of changing brfalse/brtrue
489                 // </summary>
490                 public void EmitLogicalNot (EmitContext ec)
491                 {
492                         if (oper != Operator.LogicalNot)
493                                 throw new Exception ("EmitLogicalNot can only be called with !expr");
494
495                         expr.Emit (ec);
496                 }
497                 
498                 public override void EmitStatement (EmitContext ec)
499                 {
500                         //
501                         // FIXME: we should rewrite this code to generate
502                         // better code for ++ and -- as we know we wont need
503                         // the values on the stack
504                         //
505                         Emit (ec);
506                         ec.ig.Emit (OpCodes.Pop);
507                 }
508
509                 public override Expression Reduce (EmitContext ec)
510                 {
511                         Expression e;
512                         
513                         //
514                         // We can not reduce expressions that invoke operator overloaded functions.
515                         //
516                         if (method != null)
517                                 return this;
518
519                         //
520                         // First, reduce our child.  Note that although we handle 
521                         //
522                         expr = expr.Reduce (ec);
523                         if (!(expr is Literal))
524                                 return expr;
525                         
526                         switch (oper){
527                         case Operator.UnaryPlus:
528                                 return expr;
529                                 
530                         case Operator.UnaryNegation:
531                                 e = TryReduceNegative (expr);
532                                 if (e == null)
533                                         break;
534                                 return e;
535                                 
536                         case Operator.LogicalNot:
537                                 BoolLiteral b = (BoolLiteral) expr;
538
539                                 return new BoolLiteral (!(b.Value));
540                                 
541                         case Operator.OnesComplement:
542                                 Type et = expr.Type;
543                                 
544                                 if (et == TypeManager.int32_type)
545                                         return new IntLiteral (~ ((IntLiteral) expr).Value);
546                                 if (et == TypeManager.uint32_type)
547                                         return new UIntLiteral (~ ((UIntLiteral) expr).Value);
548                                 if (et == TypeManager.int64_type)
549                                         return new LongLiteral (~ ((LongLiteral) expr).Value);
550                                 if (et == TypeManager.uint64_type)
551                                         return new ULongLiteral (~ ((ULongLiteral) expr).Value);
552                                 break;
553                         }
554                         return this;
555                 }
556         }
557         
558         public class Probe : Expression {
559                 public readonly string ProbeType;
560                 public readonly Operator Oper;
561                 Expression expr;
562                 Type probe_type;
563                 
564                 public enum Operator {
565                         Is, As
566                 }
567                 
568                 public Probe (Operator oper, Expression expr, string probe_type)
569                 {
570                         Oper = oper;
571                         ProbeType = probe_type;
572                         this.expr = expr;
573                 }
574
575                 public Expression Expr {
576                         get {
577                                 return expr;
578                         }
579                 }
580                 
581                 public override Expression DoResolve (EmitContext ec)
582                 {
583                         probe_type = ec.TypeContainer.LookupType (ProbeType, false);
584
585                         if (probe_type == null)
586                                 return null;
587
588                         expr = expr.Resolve (ec);
589                         
590                         type = TypeManager.bool_type;
591                         eclass = ExprClass.Value;
592
593                         return this;
594                 }
595
596                 public override void Emit (EmitContext ec)
597                 {
598                         ILGenerator ig = ec.ig;
599                         
600                         expr.Emit (ec);
601                         
602                         if (Oper == Operator.Is){
603                                 ig.Emit (OpCodes.Isinst, probe_type);
604                                 ig.Emit (OpCodes.Ldnull);
605                                 ig.Emit (OpCodes.Cgt_Un);
606                         } else {
607                                 ig.Emit (OpCodes.Isinst, probe_type);
608                         }
609                 }
610         }
611
612         // <summary>
613         //   This represents a typecast in the source language.
614         //
615         //   FIXME: Cast expressions have an unusual set of parsing
616         //   rules, we need to figure those out.
617         // </summary>
618         public class Cast : Expression {
619                 string target_type;
620                 Expression expr;
621                 Location   loc;
622                         
623                 public Cast (string cast_type, Expression expr, Location loc)
624                 {
625                         this.target_type = cast_type;
626                         this.expr = expr;
627                         this.loc = loc;
628                 }
629
630                 public string TargetType {
631                         get {
632                                 return target_type;
633                         }
634                 }
635
636                 public Expression Expr {
637                         get {
638                                 return expr;
639                         }
640                         set {
641                                 expr = value;
642                         }
643                 }
644                 
645                 public override Expression DoResolve (EmitContext ec)
646                 {
647                         expr = expr.Resolve (ec);
648                         if (expr == null)
649                                 return null;
650                         
651                         type = ec.TypeContainer.LookupType (target_type, false);
652                         eclass = ExprClass.Value;
653                         
654                         if (type == null)
655                                 return null;
656
657                         expr = ConvertExplicit (ec, expr, type, loc);
658
659                         return expr;
660                 }
661
662                 public override void Emit (EmitContext ec)
663                 {
664                         //
665                         // This one will never happen
666                         //
667                         throw new Exception ("Should not happen");
668                 }
669         }
670
671         public class Binary : Expression {
672                 public enum Operator {
673                         Multiply, Division, Modulus,
674                         Addition, Subtraction,
675                         LeftShift, RightShift,
676                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
677                         Equality, Inequality,
678                         BitwiseAnd,
679                         ExclusiveOr,
680                         BitwiseOr,
681                         LogicalAnd,
682                         LogicalOr
683                 }
684
685                 Operator oper;
686                 Expression left, right;
687                 MethodBase method;
688                 ArrayList  Arguments;
689                 Location   loc;
690                 
691
692                 public Binary (Operator oper, Expression left, Expression right, Location loc)
693                 {
694                         this.oper = oper;
695                         this.left = left;
696                         this.right = right;
697                         this.loc = loc;
698                 }
699
700                 public Operator Oper {
701                         get {
702                                 return oper;
703                         }
704                         set {
705                                 oper = value;
706                         }
707                 }
708                 
709                 public Expression Left {
710                         get {
711                                 return left;
712                         }
713                         set {
714                                 left = value;
715                         }
716                 }
717
718                 public Expression Right {
719                         get {
720                                 return right;
721                         }
722                         set {
723                                 right = value;
724                         }
725                 }
726
727
728                 // <summary>
729                 //   Returns a stringified representation of the Operator
730                 // </summary>
731                 string OperName ()
732                 {
733                         switch (oper){
734                         case Operator.Multiply:
735                                 return "*";
736                         case Operator.Division:
737                                 return "/";
738                         case Operator.Modulus:
739                                 return "%";
740                         case Operator.Addition:
741                                 return "+";
742                         case Operator.Subtraction:
743                                 return "-";
744                         case Operator.LeftShift:
745                                 return "<<";
746                         case Operator.RightShift:
747                                 return ">>";
748                         case Operator.LessThan:
749                                 return "<";
750                         case Operator.GreaterThan:
751                                 return ">";
752                         case Operator.LessThanOrEqual:
753                                 return "<=";
754                         case Operator.GreaterThanOrEqual:
755                                 return ">=";
756                         case Operator.Equality:
757                                 return "==";
758                         case Operator.Inequality:
759                                 return "!=";
760                         case Operator.BitwiseAnd:
761                                 return "&";
762                         case Operator.BitwiseOr:
763                                 return "|";
764                         case Operator.ExclusiveOr:
765                                 return "^";
766                         case Operator.LogicalOr:
767                                 return "||";
768                         case Operator.LogicalAnd:
769                                 return "&&";
770                         }
771
772                         return oper.ToString ();
773                 }
774
775                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
776                 {
777                         if (expr.Type == target_type)
778                                 return expr;
779
780                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
781                 }
782                 
783                 //
784                 // Note that handling the case l == Decimal || r == Decimal
785                 // is taken care of by the Step 1 Operator Overload resolution.
786                 //
787                 void DoNumericPromotions (EmitContext ec, Type l, Type r)
788                 {
789                         if (l == TypeManager.double_type || r == TypeManager.double_type){
790                                 //
791                                 // If either operand is of type double, the other operand is
792                                 // conveted to type double.
793                                 //
794                                 if (r != TypeManager.double_type)
795                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
796                                 if (l != TypeManager.double_type)
797                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
798                                 
799                                 type = TypeManager.double_type;
800                         } else if (l == TypeManager.float_type || r == TypeManager.float_type){
801                                 //
802                                 // if either operand is of type float, th eother operand is
803                                 // converd to type float.
804                                 //
805                                 if (r != TypeManager.double_type)
806                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
807                                 if (l != TypeManager.double_type)
808                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
809                                 type = TypeManager.float_type;
810                         } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
811                                 Expression e;
812                                 Type other;
813                                 //
814                                 // If either operand is of type ulong, the other operand is
815                                 // converted to type ulong.  or an error ocurrs if the other
816                                 // operand is of type sbyte, short, int or long
817                                 //
818                                 
819                                 if (l == TypeManager.uint64_type){
820                                         if (r != TypeManager.uint64_type && right is IntLiteral){
821                                                 e = TryImplicitIntConversion (l, (IntLiteral) right);
822                                                 if (e != null)
823                                                         right = e;
824                                         }
825                                         other = right.Type;
826                                 } else {
827                                         if (left is IntLiteral){
828                                                 e = TryImplicitIntConversion (r, (IntLiteral) left);
829                                                 if (e != null)
830                                                         left = e;
831                                         }
832                                         other = left.Type;
833                                 }
834
835                                 if ((other == TypeManager.sbyte_type) ||
836                                     (other == TypeManager.short_type) ||
837                                     (other == TypeManager.int32_type) ||
838                                     (other == TypeManager.int64_type)){
839                                         string oper = OperName ();
840                                         
841                                         Error (34, loc, "Operator `" + OperName ()
842                                                + "' is ambiguous on operands of type `"
843                                                + TypeManager.CSharpName (l) + "' "
844                                                + "and `" + TypeManager.CSharpName (r)
845                                                + "'");
846                                 }
847                                 type = TypeManager.uint64_type;
848                         } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
849                                 //
850                                 // If either operand is of type long, the other operand is converted
851                                 // to type long.
852                                 //
853                                 if (l != TypeManager.int64_type)
854                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
855                                 if (r != TypeManager.int64_type)
856                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
857
858                                 type = TypeManager.int64_type;
859                         } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
860                                 //
861                                 // If either operand is of type uint, and the other
862                                 // operand is of type sbyte, short or int, othe operands are
863                                 // converted to type long.
864                                 //
865                                 Type other = null;
866                                 
867                                 if (l == TypeManager.uint32_type)
868                                         other = r;
869                                 else if (r == TypeManager.uint32_type)
870                                         other = l;
871
872                                 if ((other == TypeManager.sbyte_type) ||
873                                     (other == TypeManager.short_type) ||
874                                     (other == TypeManager.int32_type)){
875                                         left = ForceConversion (ec, left, TypeManager.int64_type);
876                                         right = ForceConversion (ec, right, TypeManager.int64_type);
877                                         type = TypeManager.int64_type;
878                                 } else {
879                                         //
880                                         // if either operand is of type uint, the other
881                                         // operand is converd to type uint
882                                         //
883                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
884                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
885                                         type = TypeManager.uint32_type;
886                                 } 
887                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
888                                 if (l != TypeManager.decimal_type)
889                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
890                                 if (r != TypeManager.decimal_type)
891                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
892
893                                 type = TypeManager.decimal_type;
894                         } else {
895                                 Expression l_tmp, r_tmp;
896
897                                 l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
898                                 if (l_tmp == null) {
899                                         error19 ();
900                                         left = l_tmp;
901                                         return;
902                                 }
903                                 
904                                 r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
905                                 if (r_tmp == null) {
906                                         error19 ();
907                                         right = r_tmp;
908                                         return;
909                                 }
910                                 
911                                 type = TypeManager.int32_type;
912                         }
913                 }
914
915                 void error19 ()
916                 {
917                         Error (19, loc,
918                                "Operator " + OperName () + " cannot be applied to operands of type `" +
919                                TypeManager.CSharpName (left.Type) + "' and `" +
920                                TypeManager.CSharpName (right.Type) + "'");
921                                                      
922                 }
923                 
924                 Expression CheckShiftArguments (EmitContext ec)
925                 {
926                         Expression e;
927                         Type l = left.Type;
928                         Type r = right.Type;
929
930                         e = ForceConversion (ec, right, TypeManager.int32_type);
931                         if (e == null){
932                                 error19 ();
933                                 return null;
934                         }
935                         right = e;
936
937                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
938                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
939                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
940                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
941                                 left = e;
942                                 type = e.Type;
943
944                                 return this;
945                         }
946                         error19 ();
947                         return null;
948                 }
949                 
950                 Expression ResolveOperator (EmitContext ec)
951                 {
952                         Type l = left.Type;
953                         Type r = right.Type;
954
955                         //
956                         // Step 1: Perform Operator Overload location
957                         //
958                         Expression left_expr, right_expr;
959                         
960                         string op = "op_" + oper;
961
962                         left_expr = MemberLookup (ec, l, op, false, loc);
963                         if (left_expr == null && l.BaseType != null)
964                                 left_expr = MemberLookup (ec, l.BaseType, op, false, loc);
965                         
966                         right_expr = MemberLookup (ec, r, op, false, loc);
967                         if (right_expr == null && r.BaseType != null)
968                                 right_expr = MemberLookup (ec, r.BaseType, op, false, loc);
969                         
970                         MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
971                         
972                         if (union != null) {
973                                 Arguments = new ArrayList ();
974                                 Arguments.Add (new Argument (left, Argument.AType.Expression));
975                                 Arguments.Add (new Argument (right, Argument.AType.Expression));
976                                 
977                                 method = Invocation.OverloadResolve (ec, union, Arguments, loc);
978                                 if (method != null) {
979                                         MethodInfo mi = (MethodInfo) method;
980                                         type = mi.ReturnType;
981                                         return this;
982                                 } else {
983                                         error19 ();
984                                         return null;
985                                 }
986                         }       
987
988                         //
989                         // Step 2: Default operations on CLI native types.
990                         //
991                         
992                         // Only perform numeric promotions on:
993                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
994                         //
995                         if (oper == Operator.Addition){
996                                 //
997                                 // If any of the arguments is a string, cast to string
998                                 //
999                                 if (l == TypeManager.string_type){
1000                                         if (r == TypeManager.string_type){
1001                                                 if (left is Literal && right is Literal){
1002                                                         StringLiteral ls = (StringLiteral) left;
1003                                                         StringLiteral rs = (StringLiteral) right;
1004                                                         
1005                                                         return new StringLiteral (ls.Value + rs.Value);
1006                                                 }
1007                                                 
1008                                                 // string + string
1009                                                 method = TypeManager.string_concat_string_string;
1010                                         } else {
1011                                                 // string + object
1012                                                 method = TypeManager.string_concat_object_object;
1013                                                 right = ConvertImplicit (ec, right,
1014                                                                          TypeManager.object_type, loc);
1015                                         }
1016                                         type = TypeManager.string_type;
1017
1018                                         Arguments = new ArrayList ();
1019                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1020                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1021
1022                                         return this;
1023                                         
1024                                 } else if (r == TypeManager.string_type){
1025                                         // object + string
1026                                         method = TypeManager.string_concat_object_object;
1027                                         Arguments = new ArrayList ();
1028                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1029                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1030
1031                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
1032                                         type = TypeManager.string_type;
1033
1034                                         return this;
1035                                 }
1036
1037                                 //
1038                                 // FIXME: is Delegate operator + (D x, D y) handled?
1039                                 //
1040                         }
1041                         
1042                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
1043                                 return CheckShiftArguments (ec);
1044
1045                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
1046                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
1047                                         error19 ();
1048                                         return null;
1049                                 }
1050
1051                                 type = TypeManager.bool_type;
1052                                 return this;
1053                         } 
1054
1055                         if (oper == Operator.Equality || oper == Operator.Inequality){
1056                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1057                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1058                                                 error19 ();
1059                                                 return null;
1060                                         }
1061                                         
1062                                         type = TypeManager.bool_type;
1063                                         return this;
1064                                 }
1065                                 //
1066                                 // fall here.
1067                                 //
1068                         }
1069
1070                         //
1071                         // We are dealing with numbers
1072                         //
1073
1074                         DoNumericPromotions (ec, l, r);
1075
1076                         if (left == null || right == null)
1077                                 return null;
1078
1079                         
1080                         if (oper == Operator.BitwiseAnd ||
1081                             oper == Operator.BitwiseOr ||
1082                             oper == Operator.ExclusiveOr){
1083                                 if (!((l == TypeManager.int32_type) ||
1084                                       (l == TypeManager.uint32_type) ||
1085                                       (l == TypeManager.int64_type) ||
1086                                       (l == TypeManager.uint64_type))){
1087                                         error19 ();
1088                                         return null;
1089                                 }
1090                                 type = l;
1091                         }
1092
1093                         if (oper == Operator.Equality ||
1094                             oper == Operator.Inequality ||
1095                             oper == Operator.LessThanOrEqual ||
1096                             oper == Operator.LessThan ||
1097                             oper == Operator.GreaterThanOrEqual ||
1098                             oper == Operator.GreaterThan){
1099                                 type = TypeManager.bool_type;
1100                         }
1101
1102                         return this;
1103                 }
1104                 
1105                 public override Expression DoResolve (EmitContext ec)
1106                 {
1107                         left = left.Resolve (ec);
1108                         right = right.Resolve (ec);
1109
1110                         if (left == null || right == null)
1111                                 return null;
1112
1113                         if (left.Type == null)
1114                                 throw new Exception (
1115                                         "Resolve returned non null, but did not set the type! (" +
1116                                         left + ") at Line: " + loc.Row);
1117                         if (right.Type == null)
1118                                 throw new Exception (
1119                                         "Resolve returned non null, but did not set the type! (" +
1120                                         right + ") at Line: "+ loc.Row);
1121
1122                         eclass = ExprClass.Value;
1123
1124                         return ResolveOperator (ec);
1125                 }
1126
1127                 public bool IsBranchable ()
1128                 {
1129                         if (oper == Operator.Equality ||
1130                             oper == Operator.Inequality ||
1131                             oper == Operator.LessThan ||
1132                             oper == Operator.GreaterThan ||
1133                             oper == Operator.LessThanOrEqual ||
1134                             oper == Operator.GreaterThanOrEqual){
1135                                 return true;
1136                         } else
1137                                 return false;
1138                 }
1139
1140                 // <summary>
1141                 //   This entry point is used by routines that might want
1142                 //   to emit a brfalse/brtrue after an expression, and instead
1143                 //   they could use a more compact notation.
1144                 //
1145                 //   Typically the code would generate l.emit/r.emit, followed
1146                 //   by the comparission and then a brtrue/brfalse.  The comparissions
1147                 //   are sometimes inneficient (there are not as complete as the branches
1148                 //   look for the hacks in Emit using double ceqs).
1149                 //
1150                 //   So for those cases we provide EmitBranchable that can emit the
1151                 //   branch with the test
1152                 // </summary>
1153                 public void EmitBranchable (EmitContext ec, int target)
1154                 {
1155                         OpCode opcode;
1156                         bool close_target = false;
1157                         
1158                         left.Emit (ec);
1159                         right.Emit (ec);
1160                         
1161                         switch (oper){
1162                         case Operator.Equality:
1163                                 if (close_target)
1164                                         opcode = OpCodes.Beq_S;
1165                                 else
1166                                         opcode = OpCodes.Beq;
1167                                 break;
1168
1169                         case Operator.Inequality:
1170                                 if (close_target)
1171                                         opcode = OpCodes.Bne_Un_S;
1172                                 else
1173                                         opcode = OpCodes.Bne_Un;
1174                                 break;
1175
1176                         case Operator.LessThan:
1177                                 if (close_target)
1178                                         opcode = OpCodes.Blt_S;
1179                                 else
1180                                         opcode = OpCodes.Blt;
1181                                 break;
1182
1183                         case Operator.GreaterThan:
1184                                 if (close_target)
1185                                         opcode = OpCodes.Bgt_S;
1186                                 else
1187                                         opcode = OpCodes.Bgt;
1188                                 break;
1189
1190                         case Operator.LessThanOrEqual:
1191                                 if (close_target)
1192                                         opcode = OpCodes.Ble_S;
1193                                 else
1194                                         opcode = OpCodes.Ble;
1195                                 break;
1196
1197                         case Operator.GreaterThanOrEqual:
1198                                 if (close_target)
1199                                         opcode = OpCodes.Bge_S;
1200                                 else
1201                                         opcode = OpCodes.Ble;
1202                                 break;
1203
1204                         default:
1205                                 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1206                                                      + oper.ToString ());
1207                         }
1208
1209                         ec.ig.Emit (opcode, target);
1210                 }
1211                 
1212                 public override void Emit (EmitContext ec)
1213                 {
1214                         ILGenerator ig = ec.ig;
1215                         Type l = left.Type;
1216                         Type r = right.Type;
1217                         OpCode opcode;
1218
1219                         if (method != null) {
1220
1221                                 // Note that operators are static anyway
1222                                 
1223                                 if (Arguments != null) 
1224                                         Invocation.EmitArguments (ec, Arguments);
1225                                 
1226                                 if (method is MethodInfo)
1227                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
1228                                 else
1229                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1230
1231                                 return;
1232                         }
1233                         
1234                         left.Emit (ec);
1235                         right.Emit (ec);
1236
1237                         switch (oper){
1238                         case Operator.Multiply:
1239                                 if (ec.CheckState){
1240                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1241                                                 opcode = OpCodes.Mul_Ovf;
1242                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1243                                                 opcode = OpCodes.Mul_Ovf_Un;
1244                                         else
1245                                                 opcode = OpCodes.Mul;
1246                                 } else
1247                                         opcode = OpCodes.Mul;
1248
1249                                 break;
1250
1251                         case Operator.Division:
1252                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1253                                         opcode = OpCodes.Div_Un;
1254                                 else
1255                                         opcode = OpCodes.Div;
1256                                 break;
1257
1258                         case Operator.Modulus:
1259                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1260                                         opcode = OpCodes.Rem_Un;
1261                                 else
1262                                         opcode = OpCodes.Rem;
1263                                 break;
1264
1265                         case Operator.Addition:
1266                                 if (ec.CheckState){
1267                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1268                                                 opcode = OpCodes.Add_Ovf;
1269                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1270                                                 opcode = OpCodes.Add_Ovf_Un;
1271                                         else
1272                                                 opcode = OpCodes.Mul;
1273                                 } else
1274                                         opcode = OpCodes.Add;
1275                                 break;
1276
1277                         case Operator.Subtraction:
1278                                 if (ec.CheckState){
1279                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1280                                                 opcode = OpCodes.Sub_Ovf;
1281                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1282                                                 opcode = OpCodes.Sub_Ovf_Un;
1283                                         else
1284                                                 opcode = OpCodes.Sub;
1285                                 } else
1286                                         opcode = OpCodes.Sub;
1287                                 break;
1288
1289                         case Operator.RightShift:
1290                                 opcode = OpCodes.Shr;
1291                                 break;
1292                                 
1293                         case Operator.LeftShift:
1294                                 opcode = OpCodes.Shl;
1295                                 break;
1296
1297                         case Operator.Equality:
1298                                 opcode = OpCodes.Ceq;
1299                                 break;
1300
1301                         case Operator.Inequality:
1302                                 ec.ig.Emit (OpCodes.Ceq);
1303                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
1304                                 
1305                                 opcode = OpCodes.Ceq;
1306                                 break;
1307
1308                         case Operator.LessThan:
1309                                 opcode = OpCodes.Clt;
1310                                 break;
1311
1312                         case Operator.GreaterThan:
1313                                 opcode = OpCodes.Cgt;
1314                                 break;
1315
1316                         case Operator.LessThanOrEqual:
1317                                 ec.ig.Emit (OpCodes.Cgt);
1318                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
1319                                 
1320                                 opcode = OpCodes.Ceq;
1321                                 break;
1322
1323                         case Operator.GreaterThanOrEqual:
1324                                 ec.ig.Emit (OpCodes.Clt);
1325                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
1326                                 
1327                                 opcode = OpCodes.Sub;
1328                                 break;
1329
1330                         case Operator.LogicalOr:
1331                         case Operator.BitwiseOr:
1332                                 opcode = OpCodes.Or;
1333                                 break;
1334
1335                         case Operator.LogicalAnd:
1336                         case Operator.BitwiseAnd:
1337                                 opcode = OpCodes.And;
1338                                 break;
1339
1340                         case Operator.ExclusiveOr:
1341                                 opcode = OpCodes.Xor;
1342                                 break;
1343
1344                         default:
1345                                 throw new Exception ("This should not happen: Operator = "
1346                                                      + oper.ToString ());
1347                         }
1348
1349                         ig.Emit (opcode);
1350                 }
1351
1352                 // <summary>
1353                 //   Constant expression reducer for binary operations
1354                 // </summary>
1355                 public override Expression Reduce (EmitContext ec)
1356                 {
1357                         Console.WriteLine ("Reduce called");
1358                         
1359                         left = left.Reduce (ec);
1360                         right = right.Reduce (ec);
1361
1362                         if (!(left is Literal && right is Literal))
1363                                 return this;
1364
1365                         if (method == TypeManager.string_concat_string_string){
1366                                 StringLiteral ls = (StringLiteral) left;
1367                                 StringLiteral rs = (StringLiteral) right;
1368                                 
1369                                 return new StringLiteral (ls.Value + rs.Value);
1370                         }
1371
1372                         // FINISH ME.
1373                         
1374                         return this;
1375                 }
1376         }
1377
1378         public class Conditional : Expression {
1379                 Expression expr, trueExpr, falseExpr;
1380                 Location loc;
1381                 
1382                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
1383                 {
1384                         this.expr = expr;
1385                         this.trueExpr = trueExpr;
1386                         this.falseExpr = falseExpr;
1387                         this.loc = l;
1388                 }
1389
1390                 public Expression Expr {
1391                         get {
1392                                 return expr;
1393                         }
1394                 }
1395
1396                 public Expression TrueExpr {
1397                         get {
1398                                 return trueExpr;
1399                         }
1400                 }
1401
1402                 public Expression FalseExpr {
1403                         get {
1404                                 return falseExpr;
1405                         }
1406                 }
1407
1408                 public override Expression DoResolve (EmitContext ec)
1409                 {
1410                         expr = expr.Resolve (ec);
1411
1412                         if (expr.Type != TypeManager.bool_type)
1413                                 expr = Expression.ConvertImplicitRequired (
1414                                         ec, expr, TypeManager.bool_type, loc);
1415                         
1416                         trueExpr = trueExpr.Resolve (ec);
1417                         falseExpr = falseExpr.Resolve (ec);
1418
1419                         if (expr == null || trueExpr == null || falseExpr == null)
1420                                 return null;
1421
1422                         if (trueExpr.Type == falseExpr.Type)
1423                                 type = trueExpr.Type;
1424                         else {
1425                                 Expression conv;
1426
1427                                 //
1428                                 // First, if an implicit conversion exists from trueExpr
1429                                 // to falseExpr, then the result type is of type falseExpr.Type
1430                                 //
1431                                 conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc);
1432                                 if (conv != null){
1433                                         type = falseExpr.Type;
1434                                         trueExpr = conv;
1435                                 } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){
1436                                         type = trueExpr.Type;
1437                                         falseExpr = conv;
1438                                 } else {
1439                                         Error (173, loc, "The type of the conditional expression can " +
1440                                                "not be computed because there is no implicit conversion" +
1441                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
1442                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
1443                                         return null;
1444                                 }
1445                         }
1446
1447                         if (expr is BoolLiteral){
1448                                 BoolLiteral bl = (BoolLiteral) expr;
1449
1450                                 if (bl.Value)
1451                                         return trueExpr;
1452                                 else
1453                                         return falseExpr;
1454                         }
1455                         
1456                         eclass = ExprClass.Value;
1457                         return this;
1458                 }
1459
1460                 public override void Emit (EmitContext ec)
1461                 {
1462                         ILGenerator ig = ec.ig;
1463                         Label false_target = ig.DefineLabel ();
1464                         Label end_target = ig.DefineLabel ();
1465
1466                         expr.Emit (ec);
1467                         ig.Emit (OpCodes.Brfalse, false_target);
1468                         trueExpr.Emit (ec);
1469                         ig.Emit (OpCodes.Br, end_target);
1470                         ig.MarkLabel (false_target);
1471                         falseExpr.Emit (ec);
1472                         ig.MarkLabel (end_target);
1473                 }
1474
1475                 public override Expression Reduce (EmitContext ec)
1476                 {
1477                         expr = expr.Reduce (ec);
1478                         trueExpr = trueExpr.Reduce (ec);
1479                         falseExpr = falseExpr.Reduce (ec);
1480
1481                         if (!(expr is Literal && trueExpr is Literal && falseExpr is Literal))
1482                                 return this;
1483
1484                         BoolLiteral bl = (BoolLiteral) expr;
1485
1486                         if (bl.Value)
1487                                 return trueExpr;
1488                         else
1489                                 return falseExpr;
1490                 }
1491         }
1492
1493         public class LocalVariableReference : Expression, IStackStore, IMemoryLocation {
1494                 public readonly string Name;
1495                 public readonly Block Block;
1496
1497                 VariableInfo variable_info;
1498                 
1499                 public LocalVariableReference (Block block, string name)
1500                 {
1501                         Block = block;
1502                         Name = name;
1503                         eclass = ExprClass.Variable;
1504                 }
1505
1506                 public VariableInfo VariableInfo {
1507                         get {
1508                                 if (variable_info == null)
1509                                         variable_info = Block.GetVariableInfo (Name);
1510                                 return variable_info;
1511                         }
1512                 }
1513                 
1514                 public override Expression DoResolve (EmitContext ec)
1515                 {
1516                         VariableInfo vi = VariableInfo;
1517
1518                         type = vi.VariableType;
1519                         return this;
1520                 }
1521
1522                 public override void Emit (EmitContext ec)
1523                 {
1524                         VariableInfo vi = VariableInfo;
1525                         ILGenerator ig = ec.ig;
1526                         int idx = vi.Idx;
1527
1528                         vi.Used = true;
1529
1530                         switch (idx){
1531                         case 0:
1532                                 ig.Emit (OpCodes.Ldloc_0);
1533                                 break;
1534                                 
1535                         case 1:
1536                                 ig.Emit (OpCodes.Ldloc_1);
1537                                 break;
1538                                 
1539                         case 2:
1540                                 ig.Emit (OpCodes.Ldloc_2);
1541                                 break;
1542                                 
1543                         case 3:
1544                                 ig.Emit (OpCodes.Ldloc_3);
1545                                 break;
1546                                 
1547                         default:
1548                                 if (idx <= 255)
1549                                         ig.Emit (OpCodes.Ldloc_S, (byte) idx);
1550                                 else
1551                                         ig.Emit (OpCodes.Ldloc, idx);
1552                                 break;
1553                         }
1554                 }
1555                 
1556                 public static void Store (ILGenerator ig, int idx)
1557                 {
1558                         switch (idx){
1559                         case 0:
1560                                 ig.Emit (OpCodes.Stloc_0);
1561                                 break;
1562                                 
1563                         case 1:
1564                                 ig.Emit (OpCodes.Stloc_1);
1565                                 break;
1566                                 
1567                         case 2:
1568                                 ig.Emit (OpCodes.Stloc_2);
1569                                 break;
1570                                 
1571                         case 3:
1572                                 ig.Emit (OpCodes.Stloc_3);
1573                                 break;
1574                                 
1575                         default:
1576                                 if (idx <= 255)
1577                                         ig.Emit (OpCodes.Stloc_S, (byte) idx);
1578                                 else
1579                                         ig.Emit (OpCodes.Stloc, idx);
1580                                 break;
1581                         }
1582                 }
1583                 
1584                 public void Store (EmitContext ec)
1585                 {
1586                         ILGenerator ig = ec.ig;
1587                         VariableInfo vi = VariableInfo;
1588
1589                         vi.Assigned = true;
1590
1591                         // Funny seems the above generates optimal code for us, but
1592                         // seems to take too long to generate what we need.
1593                         // ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1594
1595                         Store (ig, vi.Idx);
1596                 }
1597
1598                 public void AddressOf (EmitContext ec)
1599                 {
1600                         VariableInfo vi = VariableInfo;
1601                         int idx = vi.Idx;
1602
1603                         vi.Used = true;
1604                         vi.Assigned = true;
1605                         
1606                         if (idx <= 255)
1607                                 ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx);
1608                         else
1609                                 ec.ig.Emit (OpCodes.Ldloca, idx);
1610                 }
1611         }
1612
1613         public class ParameterReference : Expression, IStackStore, IMemoryLocation {
1614                 public readonly Parameters Pars;
1615                 public readonly String Name;
1616                 public readonly int Idx;
1617                 int arg_idx;
1618                 
1619                 public ParameterReference (Parameters pars, int idx, string name)
1620                 {
1621                         Pars = pars;
1622                         Idx  = idx;
1623                         Name = name;
1624                         eclass = ExprClass.Variable;
1625                 }
1626
1627                 public override Expression DoResolve (EmitContext ec)
1628                 {
1629                         Type [] types = Pars.GetParameterInfo (ec.TypeContainer);
1630
1631                         type = types [Idx];
1632
1633                         arg_idx = Idx;
1634                         if (!ec.IsStatic)
1635                                 arg_idx++;
1636                         
1637                         return this;
1638                 }
1639
1640                 public override void Emit (EmitContext ec)
1641                 {
1642                         if (arg_idx <= 255)
1643                                 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
1644                         else
1645                                 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
1646                 }
1647
1648                 public void Store (EmitContext ec)
1649                 {
1650                         if (arg_idx <= 255)
1651                                 ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
1652                         else
1653                                 ec.ig.Emit (OpCodes.Starg, arg_idx);
1654                         
1655                 }
1656
1657                 public void AddressOf (EmitContext ec)
1658                 {
1659                         if (arg_idx <= 255)
1660                                 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
1661                         else
1662                                 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
1663                 }
1664         }
1665         
1666         // <summary>
1667         //   Used for arguments to New(), Invocation()
1668         // </summary>
1669         public class Argument {
1670                 public enum AType {
1671                         Expression,
1672                         Ref,
1673                         Out
1674                 };
1675
1676                 public readonly AType ArgType;
1677                 public Expression expr;
1678
1679                 public Argument (Expression expr, AType type)
1680                 {
1681                         this.expr = expr;
1682                         this.ArgType = type;
1683                 }
1684
1685                 public Expression Expr {
1686                         get {
1687                                 return expr;
1688                         }
1689
1690                         set {
1691                                 expr = value;
1692                         }
1693                 }
1694
1695                 public Type Type {
1696                         get {
1697                                 return expr.Type;
1698                         }
1699                 }
1700
1701                 public Parameter.Modifier GetParameterModifier ()
1702                 {
1703                         if (ArgType == AType.Ref)
1704                                 return Parameter.Modifier.REF;
1705
1706                         if (ArgType == AType.Out)
1707                                 return Parameter.Modifier.OUT;
1708
1709                         return Parameter.Modifier.NONE;
1710                 }
1711
1712                 public static string FullDesc (Argument a)
1713                 {
1714                         StringBuilder sb = new StringBuilder ();
1715
1716                         if (a.ArgType == AType.Ref)
1717                                 sb.Append ("ref ");
1718
1719                         if (a.ArgType == AType.Out)
1720                                 sb.Append ("out ");
1721
1722                         sb.Append (TypeManager.CSharpName (a.Expr.Type));
1723
1724                         return sb.ToString ();
1725                 }
1726                 
1727                 public bool Resolve (EmitContext ec)
1728                 {
1729                         expr = expr.Resolve (ec);
1730
1731                         return expr != null;
1732                 }
1733
1734                 public void Emit (EmitContext ec)
1735                 {
1736                         expr.Emit (ec);
1737                 }
1738         }
1739
1740         // <summary>
1741         //   Invocation of methods or delegates.
1742         // </summary>
1743         public class Invocation : ExpressionStatement {
1744                 public readonly ArrayList Arguments;
1745                 public readonly Location Location;
1746
1747                 Expression expr;
1748                 MethodBase method = null;
1749                         
1750                 static Hashtable method_parameter_cache;
1751
1752                 static Invocation ()
1753                 {
1754                         method_parameter_cache = new Hashtable ();
1755                 }
1756                         
1757                 //
1758                 // arguments is an ArrayList, but we do not want to typecast,
1759                 // as it might be null.
1760                 //
1761                 // FIXME: only allow expr to be a method invocation or a
1762                 // delegate invocation (7.5.5)
1763                 //
1764                 public Invocation (Expression expr, ArrayList arguments, Location l)
1765                 {
1766                         this.expr = expr;
1767                         Arguments = arguments;
1768                         Location = l;
1769                 }
1770
1771                 public Expression Expr {
1772                         get {
1773                                 return expr;
1774                         }
1775                 }
1776
1777                 // <summary>
1778                 //   Returns the Parameters (a ParameterData interface) for the
1779                 //   Method `mb'
1780                 // </summary>
1781                 public static ParameterData GetParameterData (MethodBase mb)
1782                 {
1783                         object pd = method_parameter_cache [mb];
1784                         object ip;
1785                         
1786                         if (pd != null)
1787                                 return (ParameterData) pd;
1788
1789                         
1790                         ip = TypeContainer.LookupParametersByBuilder (mb);
1791                         if (ip != null){
1792                                 method_parameter_cache [mb] = ip;
1793
1794                                 return (ParameterData) ip;
1795                         } else {
1796                                 ParameterInfo [] pi = mb.GetParameters ();
1797                                 ReflectionParameters rp = new ReflectionParameters (pi);
1798                                 method_parameter_cache [mb] = rp;
1799
1800                                 return (ParameterData) rp;
1801                         }
1802                 }
1803
1804                 // <summary>
1805                 //   Tells whether a user defined conversion from Type `from' to
1806                 //   Type `to' exists.
1807                 //
1808                 //   FIXME: we could implement a cache here. 
1809                 // </summary>
1810                 static bool ConversionExists (EmitContext ec, Type from, Type to, Location loc)
1811                 {
1812                         // Locate user-defined implicit operators
1813
1814                         Expression mg;
1815                         
1816                         mg = MemberLookup (ec, to, "op_Implicit", false, loc);
1817
1818                         if (mg != null) {
1819                                 MethodGroupExpr me = (MethodGroupExpr) mg;
1820                                 
1821                                 for (int i = me.Methods.Length; i > 0;) {
1822                                         i--;
1823                                         MethodBase mb = me.Methods [i];
1824                                         ParameterData pd = GetParameterData (mb);
1825                                         
1826                                         if (from == pd.ParameterType (0))
1827                                                 return true;
1828                                 }
1829                         }
1830
1831                         mg = MemberLookup (ec, from, "op_Implicit", false, loc);
1832
1833                         if (mg != null) {
1834                                 MethodGroupExpr me = (MethodGroupExpr) mg;
1835
1836                                 for (int i = me.Methods.Length; i > 0;) {
1837                                         i--;
1838                                         MethodBase mb = me.Methods [i];
1839                                         MethodInfo mi = (MethodInfo) mb;
1840                                         
1841                                         if (mi.ReturnType == to)
1842                                                 return true;
1843                                 }
1844                         }
1845                         
1846                         return false;
1847                 }
1848                 
1849                 // <summary>
1850                 //  Determines "better conversion" as specified in 7.4.2.3
1851                 //  Returns : 1 if a->p is better
1852                 //            0 if a->q or neither is better 
1853                 // </summary>
1854                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, bool use_standard,
1855                                              Location loc)
1856                 {
1857                         Type argument_type = a.Type;
1858                         Expression argument_expr = a.Expr;
1859
1860                         if (argument_type == null)
1861                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1862
1863                         if (p == q)
1864                                 return 0;
1865                         
1866                         if (argument_type == p)
1867                                 return 1;
1868
1869                         if (argument_type == q)
1870                                 return 0;
1871
1872                         //
1873                         // Now probe whether an implicit constant expression conversion
1874                         // can be used.
1875                         //
1876                         // An implicit constant expression conversion permits the following
1877                         // conversions:
1878                         //
1879                         //    * A constant-expression of type `int' can be converted to type
1880                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
1881                         //      of the expression is withing the range of the destination type.
1882                         //
1883                         //    * A constant-expression of type long can be converted to type
1884                         //      ulong, provided the value of the constant expression is not negative
1885                         //
1886                         // FIXME: Note that this assumes that constant folding has
1887                         // taken place.  We dont do constant folding yet.
1888                         //
1889
1890                         if (argument_expr is IntLiteral){
1891                                 IntLiteral ei = (IntLiteral) argument_expr;
1892                                 int value = ei.Value;
1893                                 
1894                                 if (p == TypeManager.sbyte_type){
1895                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
1896                                                 return 1;
1897                                 } else if (p == TypeManager.byte_type){
1898                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1899                                                 return 1;
1900                                 } else if (p == TypeManager.short_type){
1901                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
1902                                                 return 1;
1903                                 } else if (p == TypeManager.ushort_type){
1904                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1905                                                 return 1;
1906                                 } else if (p == TypeManager.uint32_type){
1907                                         //
1908                                         // we can optimize this case: a positive int32
1909                                         // always fits on a uint32
1910                                         //
1911                                         if (value >= 0)
1912                                                 return 1;
1913                                 } else if (p == TypeManager.uint64_type){
1914                                         //
1915                                         // we can optimize this case: a positive int32
1916                                         // always fits on a uint64
1917                                         //
1918                                         if (value >= 0)
1919                                                 return 1;
1920                                 }
1921                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
1922                                 LongLiteral ll = (LongLiteral) argument_expr;
1923                                 
1924                                 if (p == TypeManager.uint64_type){
1925                                         if (ll.Value > 0)
1926                                                 return 1;
1927                                 }
1928                         }
1929
1930                         if (q == null) {
1931
1932                                 Expression tmp;
1933
1934                                 if (use_standard)
1935                                         tmp = ConvertImplicitStandard (ec, argument_expr, p, loc);
1936                                 else
1937                                         tmp = ConvertImplicit (ec, argument_expr, p, loc);
1938
1939                                 if (tmp != null)
1940                                         return 1;
1941                                 else
1942                                         return 0;
1943
1944                         }
1945
1946                         if (ConversionExists (ec, p, q, loc) == true &&
1947                             ConversionExists (ec, q, p, loc) == false)
1948                                 return 1;
1949
1950                         if (p == TypeManager.sbyte_type)
1951                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
1952                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
1953                                         return 1;
1954
1955                         if (p == TypeManager.short_type)
1956                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
1957                                     q == TypeManager.uint64_type)
1958                                         return 1;
1959
1960                         if (p == TypeManager.int32_type)
1961                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
1962                                         return 1;
1963
1964                         if (p == TypeManager.int64_type)
1965                                 if (q == TypeManager.uint64_type)
1966                                         return 1;
1967
1968                         return 0;
1969                 }
1970                 
1971                 // <summary>
1972                 //  Determines "Better function" and returns an integer indicating :
1973                 //  0 if candidate ain't better
1974                 //  1 if candidate is better than the current best match
1975                 // </summary>
1976                 static int BetterFunction (EmitContext ec, ArrayList args,
1977                                            MethodBase candidate, MethodBase best,
1978                                            bool use_standard, Location loc)
1979                 {
1980                         ParameterData candidate_pd = GetParameterData (candidate);
1981                         ParameterData best_pd;
1982                         int argument_count;
1983
1984                         if (args == null)
1985                                 argument_count = 0;
1986                         else
1987                                 argument_count = args.Count;
1988
1989                         if (candidate_pd.Count == 0 && argument_count == 0)
1990                                 return 1;
1991
1992                         if (best == null) {
1993                                 if (candidate_pd.Count == argument_count) {
1994                                         int x = 0;
1995                                         for (int j = argument_count; j > 0;) {
1996                                                 j--;
1997                                                 
1998                                                 Argument a = (Argument) args [j];
1999                                                 
2000                                                 x = BetterConversion (
2001                                                         ec, a, candidate_pd.ParameterType (j), null,
2002                                                         use_standard, loc);
2003                                                 
2004                                                 if (x <= 0)
2005                                                         break;
2006                                         }
2007                                         
2008                                         if (x > 0)
2009                                                 return 1;
2010                                         else
2011                                                 return 0;
2012                                         
2013                                 } else
2014                                         return 0;
2015                         }
2016
2017                         best_pd = GetParameterData (best);
2018
2019                         if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
2020                                 int rating1 = 0, rating2 = 0;
2021                                 
2022                                 for (int j = argument_count; j > 0;) {
2023                                         j--;
2024                                         int x, y;
2025                                         
2026                                         Argument a = (Argument) args [j];
2027
2028                                         x = BetterConversion (ec, a, candidate_pd.ParameterType (j),
2029                                                               best_pd.ParameterType (j), use_standard, loc);
2030                                         y = BetterConversion (ec, a, best_pd.ParameterType (j),
2031                                                               candidate_pd.ParameterType (j), use_standard,
2032                                                               loc);
2033                                         
2034                                         rating1 += x;
2035                                         rating2 += y;
2036                                 }
2037
2038                                 if (rating1 > rating2)
2039                                         return 1;
2040                                 else
2041                                         return 0;
2042                         } else
2043                                 return 0;
2044                         
2045                 }
2046
2047                 public static string FullMethodDesc (MethodBase mb)
2048                 {
2049                         StringBuilder sb = new StringBuilder (mb.Name);
2050                         ParameterData pd = GetParameterData (mb);
2051
2052                         int count = pd.Count;
2053                         sb.Append (" (");
2054                         
2055                         for (int i = count; i > 0; ) {
2056                                 i--;
2057                                 
2058                                 sb.Append (pd.ParameterDesc (count - i - 1));
2059                                 if (i != 0)
2060                                         sb.Append (", ");
2061                         }
2062                         
2063                         sb.Append (")");
2064                         return sb.ToString ();
2065                 }
2066
2067                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
2068                 {
2069                         MemberInfo [] miset;
2070                         MethodGroupExpr union;
2071                         
2072                         if (mg1 != null && mg2 != null) {
2073                                 
2074                                 MethodGroupExpr left_set = null, right_set = null;
2075                                 int length1 = 0, length2 = 0;
2076                                 
2077                                 left_set = (MethodGroupExpr) mg1;
2078                                 length1 = left_set.Methods.Length;
2079                                 
2080                                 right_set = (MethodGroupExpr) mg2;
2081                                 length2 = right_set.Methods.Length;
2082
2083                                 ArrayList common = new ArrayList ();
2084                                 
2085                                 for (int i = 0; i < left_set.Methods.Length; i++) {
2086                                         for (int j = 0; j < right_set.Methods.Length; j++) {
2087                                                 if (left_set.Methods [i] == right_set.Methods [j]) 
2088                                                         common.Add (left_set.Methods [i]);
2089                                         }
2090                                 }
2091                                 
2092                                 miset = new MemberInfo [length1 + length2 - common.Count];
2093
2094                                 left_set.Methods.CopyTo (miset, 0);
2095
2096                                 int k = 0;
2097                                 
2098                                 for (int j = 0; j < right_set.Methods.Length; j++)
2099                                         if (!common.Contains (right_set.Methods [j]))
2100                                                 miset [length1 + k++] = right_set.Methods [j];
2101                                 
2102                                 union = new MethodGroupExpr (miset);
2103
2104                                 return union;
2105
2106                         } else if (mg1 == null && mg2 != null) {
2107                                 
2108                                 MethodGroupExpr me = (MethodGroupExpr) mg2; 
2109                                 
2110                                 miset = new MemberInfo [me.Methods.Length];
2111                                 me.Methods.CopyTo (miset, 0);
2112
2113                                 union = new MethodGroupExpr (miset);
2114                                 
2115                                 return union;
2116
2117                         } else if (mg2 == null && mg1 != null) {
2118                                 
2119                                 MethodGroupExpr me = (MethodGroupExpr) mg1; 
2120                                 
2121                                 miset = new MemberInfo [me.Methods.Length];
2122                                 me.Methods.CopyTo (miset, 0);
2123
2124                                 union = new MethodGroupExpr (miset);
2125                                 
2126                                 return union;
2127                         }
2128                         
2129                         return null;
2130                 }
2131
2132                 // <summary>
2133                 //  Determines is the candidate method, if a params method, is applicable
2134                 //  in its expanded form to the given set of arguments
2135                 // </summary>
2136                 static bool IsParamsMethodApplicable (ArrayList arguments, MethodBase candidate)
2137                 {
2138                         int arg_count;
2139                         
2140                         if (arguments == null)
2141                                 arg_count = 0;
2142                         else
2143                                 arg_count = arguments.Count;
2144                         
2145                         ParameterData pd = GetParameterData (candidate);
2146                         
2147                         int pd_count = pd.Count;
2148
2149                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
2150                                 return false;
2151
2152                         if (pd_count - 1 > arg_count)
2153                                 return false;
2154
2155                         // If we have come this far, the case which remains is when the number of parameters
2156                         // is less than or equal to the argument count. So, we now check if the element type
2157                         // of the params array is compatible with each argument type
2158                         //
2159
2160                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
2161
2162                         for (int i = pd_count - 1; i < arg_count - 1; i++) {
2163                                 Argument a = (Argument) arguments [i];
2164                                 if (!StandardConversionExists (a.Type, element_type))
2165                                         return false;
2166                         }
2167                         
2168                         return true;
2169                 }
2170
2171                 // <summary>
2172                 //  Determines if the candidate method is applicable (section 14.4.2.1)
2173                 //  to the given set of arguments
2174                 // </summary>
2175                 static bool IsApplicable (ArrayList arguments, MethodBase candidate)
2176                 {
2177                         int arg_count;
2178
2179                         if (arguments == null)
2180                                 arg_count = 0;
2181                         else
2182                                 arg_count = arguments.Count;
2183
2184                         ParameterData pd = GetParameterData (candidate);
2185
2186                         int pd_count = pd.Count;
2187
2188                         if (arg_count != pd.Count)
2189                                 return false;
2190
2191                         for (int i = arg_count; i > 0; ) {
2192                                 i--;
2193
2194                                 Argument a = (Argument) arguments [i];
2195
2196                                 Parameter.Modifier a_mod = a.GetParameterModifier ();
2197                                 Parameter.Modifier p_mod = pd.ParameterModifier (i);
2198
2199                                 if (a_mod == p_mod) {
2200                                         
2201                                         if (a_mod == Parameter.Modifier.NONE)
2202                                                 if (!StandardConversionExists (a.Type, pd.ParameterType (i)))
2203                                                         return false;
2204                                         
2205                                         if (a_mod == Parameter.Modifier.REF ||
2206                                             a_mod == Parameter.Modifier.OUT)
2207                                                 if (pd.ParameterType (i) != a.Type)
2208                                                         return false;
2209                                 } else
2210                                         return false;
2211                         }
2212
2213                         return true;
2214                 }
2215                 
2216                 
2217
2218                 // <summary>
2219                 //   Find the Applicable Function Members (7.4.2.1)
2220                 //
2221                 //   me: Method Group expression with the members to select.
2222                 //       it might contain constructors or methods (or anything
2223                 //       that maps to a method).
2224                 //
2225                 //   Arguments: ArrayList containing resolved Argument objects.
2226                 //
2227                 //   loc: The location if we want an error to be reported, or a Null
2228                 //        location for "probing" purposes.
2229                 //
2230                 //   use_standard: controls whether OverloadResolve should use the 
2231                 //   ConvertImplicit or ConvertImplicitStandard during overload resolution.
2232                 //
2233                 //   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
2234                 //            that is the best match of me on Arguments.
2235                 //
2236                 // </summary>
2237                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
2238                                                           ArrayList Arguments, Location loc,
2239                                                           bool use_standard)
2240                 {
2241                         ArrayList afm = new ArrayList ();
2242                         int best_match_idx = -1;
2243                         MethodBase method = null;
2244                         int argument_count;
2245                         
2246                         for (int i = me.Methods.Length; i > 0; ){
2247                                 i--;
2248                                 MethodBase candidate  = me.Methods [i];
2249                                 int x;
2250
2251                                 // Check if candidate is applicable (section 14.4.2.1)
2252                                 if (!IsApplicable (Arguments, candidate))
2253                                         continue;
2254
2255                                 x = BetterFunction (ec, Arguments, candidate, method, use_standard, loc);
2256                                 
2257                                 if (x == 0)
2258                                         continue;
2259                                 else {
2260                                         best_match_idx = i;
2261                                         method = me.Methods [best_match_idx];
2262                                 }
2263                         }
2264
2265                         if (Arguments == null)
2266                                 argument_count = 0;
2267                         else
2268                                 argument_count = Arguments.Count;
2269
2270                         //
2271                         // Now we see if we can find params functions, applicable in their expanded form
2272                         // since if they were applicable in their normal form, they would have been selected
2273                         // above anyways
2274                         //
2275                         if (best_match_idx == -1) {
2276
2277                                 for (int i = me.Methods.Length; i > 0; ) {
2278                                         i--;
2279                                         MethodBase candidate = me.Methods [i];
2280
2281                                         if (IsParamsMethodApplicable (Arguments, candidate)) {
2282                                                 best_match_idx = i;
2283                                                 method = me.Methods [best_match_idx];
2284                                                 break;
2285                                         }
2286                                 }
2287                         }
2288
2289                         //
2290                         // Now we see if we can at least find a method with the same number of arguments
2291                         //
2292                         ParameterData pd;
2293                         
2294                         if (best_match_idx == -1) {
2295                                 
2296                                 for (int i = me.Methods.Length; i > 0;) {
2297                                         i--;
2298                                         MethodBase mb = me.Methods [i];
2299                                         pd = GetParameterData (mb);
2300                                         
2301                                         if (pd.Count == argument_count) {
2302                                                 best_match_idx = i;
2303                                                 method = me.Methods [best_match_idx];
2304                                                 break;
2305                                         } else
2306                                                 continue;
2307                                 }
2308                         }
2309
2310                         if (method == null)
2311                                 return null;
2312                         
2313                         // And now convert implicitly, each argument to the required type
2314                         
2315                         pd = GetParameterData (method);
2316                         int pd_count = pd.Count;
2317
2318                         for (int j = 0; j < argument_count; j++) {
2319
2320                                 Argument a = (Argument) Arguments [j];
2321                                 Expression a_expr = a.Expr;
2322                                 Type parameter_type = pd.ParameterType (j);
2323
2324                                 //
2325                                 // Note that we need to compare against the element type
2326                                 // when we have a params method
2327                                 //
2328                                 if (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS) {
2329                                         if (j >= pd_count - 1) 
2330                                                 parameter_type = pd.ParameterType (pd_count - 1).GetElementType ();
2331                                 }
2332
2333                                 if (a.Type != parameter_type){
2334                                         Expression conv;
2335                                         
2336                                         if (use_standard)
2337                                                 conv = ConvertImplicitStandard (ec, a_expr, parameter_type,
2338                                                                                 Location.Null);
2339                                         else
2340                                                 conv = ConvertImplicit (ec, a_expr, parameter_type,
2341                                                                         Location.Null);
2342
2343                                         if (conv == null) {
2344                                                 if (!Location.IsNull (loc)) {
2345                                                         Error (1502, loc,
2346                                                         "The best overloaded match for method '" + FullMethodDesc (method)+
2347                                                                "' has some invalid arguments");
2348                                                         Error (1503, loc,
2349                                                          "Argument " + (j+1) +
2350                                                          ": Cannot convert from '" + Argument.FullDesc (a) 
2351                                                          + "' to '" + pd.ParameterDesc (j) + "'");
2352                                                 }
2353                                                 return null;
2354                                         }
2355                                         
2356                         
2357                                         
2358                                         //
2359                                         // Update the argument with the implicit conversion
2360                                         //
2361                                         if (a_expr != conv)
2362                                                 a.Expr = conv;
2363
2364                                         // FIXME : For the case of params methods, we need to actually instantiate
2365                                         // an array and initialize it with the argument values etc etc.
2366
2367                                 }
2368                                 
2369                                 if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
2370                                     pd.ParameterModifier (j) != Parameter.Modifier.PARAMS) {
2371                                         if (!Location.IsNull (loc)) {
2372                                                 Error (1502, loc,
2373                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
2374                                                        "' has some invalid arguments");
2375                                                 Error (1503, loc,
2376                                                        "Argument " + (j+1) +
2377                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
2378                                                        + "' to '" + pd.ParameterDesc (j) + "'");
2379                                         }
2380                                         return null;
2381                                 }
2382                                 
2383                                 
2384                         }
2385                         
2386                         return method;
2387                 }
2388                 
2389                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
2390                                                           ArrayList Arguments, Location loc)
2391                 {
2392                         return OverloadResolve (ec, me, Arguments, loc, false);
2393                 }
2394                         
2395                 public override Expression DoResolve (EmitContext ec)
2396                 {
2397                         //
2398                         // First, resolve the expression that is used to
2399                         // trigger the invocation
2400                         //
2401                         expr = expr.Resolve (ec);
2402                         if (expr == null)
2403                                 return null;
2404
2405                         if (!(expr is MethodGroupExpr)) {
2406                                 Type expr_type = expr.Type;
2407
2408                                 if (expr_type != null){
2409                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
2410                                         if (IsDelegate)
2411                                                 return (new DelegateInvocation (
2412                                                         this.expr, Arguments, Location)).Resolve (ec);
2413                                 }
2414                         }
2415
2416                         if (!(expr is MethodGroupExpr)){
2417                                 report118 (Location, this.expr, "method group");
2418                                 return null;
2419                         }
2420
2421                         //
2422                         // Next, evaluate all the expressions in the argument list
2423                         //
2424                         if (Arguments != null){
2425                                 for (int i = Arguments.Count; i > 0;){
2426                                         --i;
2427                                         Argument a = (Argument) Arguments [i];
2428
2429                                         if (!a.Resolve (ec))
2430                                                 return null;
2431                                 }
2432                         }
2433
2434                         method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments,
2435                                                   Location);
2436
2437                         if (method == null){
2438                                 Error (-6, Location,
2439                                        "Could not find any applicable function for this argument list");
2440                                 return null;
2441                         }
2442
2443                         if (method is MethodInfo)
2444                                 type = ((MethodInfo)method).ReturnType;
2445
2446                         eclass = ExprClass.Value;
2447                         return this;
2448                 }
2449
2450                 public static void EmitArguments (EmitContext ec, ArrayList Arguments)
2451                 {
2452                         int top;
2453
2454                         if (Arguments != null)
2455                                 top = Arguments.Count;
2456                         else
2457                                 top = 0;
2458
2459                         for (int i = 0; i < top; i++){
2460                                 Argument a = (Argument) Arguments [i];
2461
2462                                 a.Emit (ec);
2463                         }
2464                 }
2465
2466                 public static void EmitCall (EmitContext ec,
2467                                              bool is_static, Expression instance_expr,
2468                                              MethodBase method, ArrayList Arguments)
2469                 {
2470                         ILGenerator ig = ec.ig;
2471                         bool struct_call = false;
2472                                 
2473                         if (!is_static){
2474                                 //
2475                                 // If this is ourselves, push "this"
2476                                 //
2477                                 if (instance_expr == null){
2478                                         ig.Emit (OpCodes.Ldarg_0);
2479                                 } else {
2480                                         //
2481                                         // Push the instance expression
2482                                         //
2483                                         if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
2484
2485                                                 struct_call = true;
2486
2487                                                 //
2488                                                 // If the expression implements IMemoryLocation, then
2489                                                 // we can optimize and use AddressOf on the
2490                                                 // return.
2491                                                 //
2492                                                 // If not we have to use some temporary storage for
2493                                                 // it.
2494                                                 if (instance_expr is IMemoryLocation)
2495                                                         ((IMemoryLocation) instance_expr).AddressOf (ec);
2496                                                 else {
2497                                                         Type t = instance_expr.Type;
2498                                                         
2499                                                         instance_expr.Emit (ec);
2500                                                         LocalBuilder temp = ec.GetTemporaryStorage (t);
2501                                                         ig.Emit (OpCodes.Stloc, temp);
2502                                                         ig.Emit (OpCodes.Ldloca, temp);
2503                                                 }
2504                                         } else 
2505                                                 instance_expr.Emit (ec);
2506                                 }
2507                         }
2508
2509                         if (Arguments != null)
2510                                 EmitArguments (ec, Arguments);
2511
2512                         if (is_static || struct_call){
2513                                 if (method is MethodInfo)
2514                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2515                                 else
2516                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2517                         } else {
2518                                 if (method is MethodInfo)
2519                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
2520                                 else
2521                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
2522                         }
2523                 }
2524                 
2525                 public override void Emit (EmitContext ec)
2526                 {
2527                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
2528                         EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments);
2529                 }
2530                 
2531                 public override void EmitStatement (EmitContext ec)
2532                 {
2533                         Emit (ec);
2534
2535                         // 
2536                         // Pop the return value if there is one
2537                         //
2538                         if (method is MethodInfo){
2539                                 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
2540                                         ec.ig.Emit (OpCodes.Pop);
2541                         }
2542                 }
2543         }
2544
2545         public class New : ExpressionStatement {
2546                 public readonly ArrayList Arguments;
2547                 public readonly string    RequestedType;
2548
2549                 Location Location;
2550                 MethodBase method = null;
2551
2552                 //
2553                 // If set, the new expression is for a value_target, and
2554                 // we will not leave anything on the stack.
2555                 //
2556                 Expression value_target;
2557                 
2558                 public New (string requested_type, ArrayList arguments, Location loc)
2559                 {
2560                         RequestedType = requested_type;
2561                         Arguments = arguments;
2562                         Location = loc;
2563                 }
2564
2565                 public Expression ValueTypeVariable {
2566                         get {
2567                                 return value_target;
2568                         }
2569
2570                         set {
2571                                 value_target = value;
2572                         }
2573                 }
2574
2575                 public override Expression DoResolve (EmitContext ec)
2576                 {
2577                         type = ec.TypeContainer.LookupType (RequestedType, false);
2578                         
2579                         if (type == null)
2580                                 return null;
2581                         
2582                         bool IsDelegate = TypeManager.IsDelegateType (type);
2583                         
2584                         if (IsDelegate)
2585                                 return (new NewDelegate (type, Arguments, Location)).Resolve (ec);
2586                         
2587                         Expression ml;
2588                         
2589                         ml = MemberLookup (ec, type, ".ctor", false,
2590                                            MemberTypes.Constructor, AllBindingsFlags, Location);
2591                         
2592                         bool is_struct = false;
2593                         is_struct = type.IsSubclassOf (TypeManager.value_type);
2594                         
2595                         if (! (ml is MethodGroupExpr)){
2596                                 if (!is_struct){
2597                                         report118 (Location, ml, "method group");
2598                                         return null;
2599                                 }
2600                         }
2601                         
2602                         if (ml != null) {
2603                                 if (Arguments != null){
2604                                         for (int i = Arguments.Count; i > 0;){
2605                                                 --i;
2606                                                 Argument a = (Argument) Arguments [i];
2607                                                 
2608                                                 if (!a.Resolve (ec))
2609                                                         return null;
2610                                         }
2611                                 }
2612
2613                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
2614                                                                      Arguments, Location);
2615                         }
2616                         
2617                         if (method == null && !is_struct) {
2618                                 Error (-6, Location,
2619                                        "New invocation: Can not find a constructor for " +
2620                                        "this argument list");
2621                                 return null;
2622                         }
2623                         
2624                         eclass = ExprClass.Value;
2625                         return this;
2626                 }
2627
2628                 //
2629                 // This DoEmit can be invoked in two contexts:
2630                 //    * As a mechanism that will leave a value on the stack (new object)
2631                 //    * As one that wont (init struct)
2632                 //
2633                 // You can control whether a value is required on the stack by passing
2634                 // need_value_on_stack.  The code *might* leave a value on the stack
2635                 // so it must be popped manually
2636                 //
2637                 // Returns whether a value is left on the stack
2638                 //
2639                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
2640                 {
2641                         if (method == null){
2642                                 IMemoryLocation ml = (IMemoryLocation) value_target;
2643
2644                                 ml.AddressOf (ec);
2645                         } else {
2646                                 Invocation.EmitArguments (ec, Arguments);
2647                                 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
2648                                 return true;
2649                         }
2650
2651                         //
2652                         // It must be a value type, sanity check
2653                         //
2654                         if (value_target != null){
2655                                 ec.ig.Emit (OpCodes.Initobj, type);
2656
2657                                 if (need_value_on_stack){
2658                                         value_target.Emit (ec);
2659                                         return true;
2660                                 }
2661                                 return false;
2662                         }
2663
2664                         throw new Exception ("No method and no value type");
2665                 }
2666
2667                 public override void Emit (EmitContext ec)
2668                 {
2669                         DoEmit (ec, true);
2670                 }
2671                 
2672                 public override void EmitStatement (EmitContext ec)
2673                 {
2674                         if (DoEmit (ec, false))
2675                                 ec.ig.Emit (OpCodes.Pop);
2676                 }
2677         }
2678
2679         // <summary>
2680         //   Represents an array creation expression.
2681         // </summary>
2682         //
2683         // <remarks>
2684         //   There are two possible scenarios here: one is an array creation
2685         //   expression that specifies the dimensions and optionally the
2686         //   initialization data
2687         // </remarks>
2688         public class ArrayCreation : ExpressionStatement {
2689
2690                 string RequestedType;
2691                 string Rank;
2692                 ArrayList Initializers;
2693                 Location  Location;
2694                 ArrayList Arguments;
2695
2696                 MethodBase method = null;
2697                 Type array_element_type;
2698                 bool IsOneDimensional = false;
2699                 
2700                 bool IsBuiltinType = false;
2701
2702                 public ArrayCreation (string requested_type, ArrayList exprs,
2703                                       string rank, ArrayList initializers, Location l)
2704                 {
2705                         RequestedType = requested_type;
2706                         Rank          = rank;
2707                         Initializers  = initializers;
2708                         Location      = l;
2709
2710                         Arguments = new ArrayList ();
2711
2712                         foreach (Expression e in exprs)
2713                                 Arguments.Add (new Argument (e, Argument.AType.Expression));
2714                         
2715                 }
2716
2717                 public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)
2718                 {
2719                         RequestedType = requested_type;
2720                         Rank = rank;
2721                         Initializers = initializers;
2722                         Location = l;
2723                 }
2724
2725                 public static string FormArrayType (string base_type, int idx_count, string rank)
2726                 {
2727                         StringBuilder sb = new StringBuilder (base_type);
2728
2729                         sb.Append (rank);
2730                         
2731                         sb.Append ("[");
2732                         for (int i = 1; i < idx_count; i++)
2733                                 sb.Append (",");
2734                         sb.Append ("]");
2735                         
2736                         return sb.ToString ();
2737                 }
2738
2739                 public static string FormElementType (string base_type, int idx_count, string rank)
2740                 {
2741                         StringBuilder sb = new StringBuilder (base_type);
2742                         
2743                         sb.Append ("[");
2744                         for (int i = 1; i < idx_count; i++)
2745                                 sb.Append (",");
2746                         sb.Append ("]");
2747
2748                         sb.Append (rank);
2749
2750                         string val = sb.ToString ();
2751
2752                         return val.Substring (0, val.LastIndexOf ("["));
2753                 }
2754                 
2755
2756                 public override Expression DoResolve (EmitContext ec)
2757                 {
2758                         int arg_count;
2759                         
2760                         if (Arguments == null)
2761                                 arg_count = 0;
2762                         else
2763                                 arg_count = Arguments.Count;
2764                         
2765                         string array_type = FormArrayType (RequestedType, arg_count, Rank);
2766
2767                         string element_type = FormElementType (RequestedType, arg_count, Rank);
2768
2769                         type = ec.TypeContainer.LookupType (array_type, false);
2770                         
2771                         array_element_type = ec.TypeContainer.LookupType (element_type, false);
2772                         
2773                         if (type == null)
2774                                 return null;
2775                         
2776                         if (arg_count == 1) {
2777                                 IsOneDimensional = true;
2778                                 eclass = ExprClass.Value;
2779                                 return this;
2780                         }
2781
2782                         IsBuiltinType = TypeManager.IsBuiltinType (type);
2783                         
2784                         if (IsBuiltinType) {
2785                                 
2786                                 Expression ml;
2787                                 
2788                                 ml = MemberLookup (ec, type, ".ctor", false, MemberTypes.Constructor,
2789                                                    AllBindingsFlags, Location);
2790                                 
2791                                 if (!(ml is MethodGroupExpr)){
2792                                         report118 (Location, ml, "method group");
2793                                         return null;
2794                                 }
2795                                 
2796                                 if (ml == null) {
2797                                         Report.Error (-6, Location, "New invocation: Can not find a constructor for " +
2798                                                       "this argument list");
2799                                         return null;
2800                                 }
2801                                 
2802                                 if (Arguments != null) {
2803                                         for (int i = arg_count; i > 0;){
2804                                                 --i;
2805                                                 Argument a = (Argument) Arguments [i];
2806                                                 
2807                                                 if (!a.Resolve (ec))
2808                                                         return null;
2809                                         }
2810                                 }
2811                                 
2812                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, Location);
2813                                 
2814                                 if (method == null) {
2815                                         Report.Error (-6, Location, "New invocation: Can not find a constructor for " +
2816                                                       "this argument list");
2817                                         return null;
2818                                 }
2819                                 
2820                                 eclass = ExprClass.Value;
2821                                 return this;
2822                                 
2823                         } else {
2824
2825                                 ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder;
2826
2827                                 ArrayList args = new ArrayList ();
2828                                 if (Arguments != null){
2829                                         for (int i = arg_count; i > 0;){
2830                                                 --i;
2831                                                 Argument a = (Argument) Arguments [i];
2832                                                 
2833                                                 if (!a.Resolve (ec))
2834                                                         return null;
2835                                                 
2836                                                 args.Add (a.Type);
2837                                         }
2838                                 }
2839                                 
2840                                 Type [] arg_types = null;
2841                                 
2842                                 if (args.Count > 0)
2843                                         arg_types = new Type [args.Count];
2844                                 
2845                                 args.CopyTo (arg_types, 0);
2846                                 
2847                                 method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
2848                                                             arg_types);
2849                                 
2850                                 if (method == null) {
2851                                         Report.Error (-6, Location, "New invocation: Can not find a constructor for " +
2852                                                       "this argument list");
2853                                         return null;
2854                                 }
2855                                 
2856                                 eclass = ExprClass.Value;
2857                                 return this;
2858                                 
2859                         }
2860                 }
2861
2862                 public override void Emit (EmitContext ec)
2863                 {
2864                         if (IsOneDimensional) {
2865                                 Invocation.EmitArguments (ec, Arguments);
2866                                 ec.ig.Emit (OpCodes.Newarr, array_element_type);
2867                                 
2868                         } else {
2869                                 Invocation.EmitArguments (ec, Arguments);
2870
2871                                 if (IsBuiltinType)
2872                                         ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
2873                                 else
2874                                         ec.ig.Emit (OpCodes.Newobj, (MethodInfo) method);
2875                         }
2876                         
2877                 }
2878                 
2879                 public override void EmitStatement (EmitContext ec)
2880                 {
2881                         Emit (ec);
2882                         ec.ig.Emit (OpCodes.Pop);
2883                 }
2884                 
2885         }
2886         
2887         //
2888         // Represents the `this' construct
2889         //
2890         public class This : Expression, IStackStore, IMemoryLocation {
2891                 Location loc;
2892                 
2893                 public This (Location loc)
2894                 {
2895                         this.loc = loc;
2896                 }
2897
2898                 public override Expression DoResolve (EmitContext ec)
2899                 {
2900                         eclass = ExprClass.Variable;
2901                         type = ec.TypeContainer.TypeBuilder;
2902
2903                         if (ec.IsStatic){
2904                                 Report.Error (26, loc,
2905                                               "Keyword this not valid in static code");
2906                                 return null;
2907                         }
2908                         
2909                         return this;
2910                 }
2911
2912                 public Expression DoResolveLValue (EmitContext ec)
2913                 {
2914                         DoResolve (ec);
2915                         
2916                         if (ec.TypeContainer is Class){
2917                                 Report.Error (1604, loc, "Cannot assign to `this'");
2918                                 return null;
2919                         }
2920
2921                         return this;
2922                 }
2923
2924                 public override void Emit (EmitContext ec)
2925                 {
2926                         ec.ig.Emit (OpCodes.Ldarg_0);
2927                 }
2928
2929                 public void Store (EmitContext ec)
2930                 {
2931                         ec.ig.Emit (OpCodes.Starg, 0);
2932                 }
2933
2934                 public void AddressOf (EmitContext ec)
2935                 {
2936                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
2937                 }
2938         }
2939
2940         // <summary>
2941         //   Implements the typeof operator
2942         // </summary>
2943         public class TypeOf : Expression {
2944                 public readonly string QueriedType;
2945                 Type typearg;
2946                 
2947                 public TypeOf (string queried_type)
2948                 {
2949                         QueriedType = queried_type;
2950                 }
2951
2952                 public override Expression DoResolve (EmitContext ec)
2953                 {
2954                         typearg = ec.TypeContainer.LookupType (QueriedType, false);
2955
2956                         if (typearg == null)
2957                                 return null;
2958
2959                         type = TypeManager.type_type;
2960                         eclass = ExprClass.Type;
2961                         return this;
2962                 }
2963
2964                 public override void Emit (EmitContext ec)
2965                 {
2966                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
2967                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
2968                 }
2969         }
2970
2971         public class SizeOf : Expression {
2972                 public readonly string QueriedType;
2973                 
2974                 public SizeOf (string queried_type)
2975                 {
2976                         this.QueriedType = queried_type;
2977                 }
2978
2979                 public override Expression DoResolve (EmitContext ec)
2980                 {
2981                         // FIXME: Implement;
2982                         throw new Exception ("Unimplemented");
2983                         // return this;
2984                 }
2985
2986                 public override void Emit (EmitContext ec)
2987                 {
2988                         throw new Exception ("Implement me");
2989                 }
2990         }
2991
2992         public class MemberAccess : Expression {
2993                 public readonly string Identifier;
2994                 Expression expr;
2995                 Expression member_lookup;
2996                 Location loc;
2997                 
2998                 public MemberAccess (Expression expr, string id, Location l)
2999                 {
3000                         this.expr = expr;
3001                         Identifier = id;
3002                         loc = l;
3003                 }
3004
3005                 public Expression Expr {
3006                         get {
3007                                 return expr;
3008                         }
3009                 }
3010
3011                 void error176 (Location loc, string name)
3012                 {
3013                         Report.Error (176, loc, "Static member `" +
3014                                       name + "' cannot be accessed " +
3015                                       "with an instance reference, qualify with a " +
3016                                       "type name instead");
3017                 }
3018                 
3019                 public override Expression DoResolve (EmitContext ec)
3020                 {
3021                         //
3022                         // We are the sole users of ResolveWithSimpleName (ie, the only
3023                         // ones that can cope with it
3024                         //
3025                         expr = expr.ResolveWithSimpleName (ec);
3026
3027                         if (expr == null)
3028                                 return null;
3029
3030                         if (expr is SimpleName){
3031                                 SimpleName child_expr = (SimpleName) expr;
3032                                 
3033                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
3034
3035                                 return expr.Resolve (ec);
3036                         }
3037                                         
3038                         member_lookup = MemberLookup (ec, expr.Type, Identifier, false, loc);
3039
3040                         if (member_lookup == null)
3041                                 return null;
3042                         
3043                         //
3044                         // Method Groups
3045                         //
3046                         if (member_lookup is MethodGroupExpr){
3047                                 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
3048                                 
3049                                 //
3050                                 // Type.MethodGroup
3051                                 //
3052                                 if (expr is TypeExpr){
3053                                         if (!mg.RemoveInstanceMethods ()){
3054                                                 SimpleName.Error120 (loc, mg.Methods [0].Name); 
3055                                                 return null;
3056                                         }
3057
3058                                         return member_lookup;
3059                                 }
3060
3061                                 //
3062                                 // Instance.MethodGroup
3063                                 //
3064                                 if (!mg.RemoveStaticMethods ()){
3065                                         error176 (loc, mg.Methods [0].Name);
3066                                         return null;
3067                                 }
3068                                 
3069                                 mg.InstanceExpression = expr;
3070                                         
3071                                 return member_lookup;
3072                         }
3073
3074                         if (member_lookup is FieldExpr){
3075                                 FieldExpr fe = (FieldExpr) member_lookup;
3076
3077                                 if (expr is TypeExpr){
3078                                         if (!fe.FieldInfo.IsStatic){
3079                                                 error176 (loc, fe.FieldInfo.Name);
3080                                                 return null;
3081                                         }
3082                                         return member_lookup;
3083                                 } else {
3084                                         if (fe.FieldInfo.IsStatic){
3085                                                 error176 (loc, fe.FieldInfo.Name);
3086                                                 return null;
3087                                         }
3088                                         fe.InstanceExpression = expr;
3089
3090                                         return fe;
3091                                 }
3092                         }
3093
3094                         if (member_lookup is PropertyExpr){
3095                                 PropertyExpr pe = (PropertyExpr) member_lookup;
3096
3097                                 if (expr is TypeExpr){
3098                                         if (!pe.IsStatic){
3099                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
3100                                                 return null;
3101                                         }
3102                                         return pe;
3103                                 } else {
3104                                         if (pe.IsStatic){
3105                                                 error176 (loc, pe.PropertyInfo.Name);
3106                                                 return null;
3107                                         }
3108                                         pe.InstanceExpression = expr;
3109
3110                                         return pe;
3111                                 }
3112                         }
3113                         
3114                         Console.WriteLine ("Support for [" + member_lookup + "] is not present yet");
3115                         Environment.Exit (0);
3116                         return null;
3117                 }
3118
3119                 public override void Emit (EmitContext ec)
3120                 {
3121                         throw new Exception ("Should not happen I think");
3122                 }
3123
3124         }
3125
3126         public class CheckedExpr : Expression {
3127
3128                 public Expression Expr;
3129
3130                 public CheckedExpr (Expression e)
3131                 {
3132                         Expr = e;
3133                 }
3134
3135                 public override Expression DoResolve (EmitContext ec)
3136                 {
3137                         Expr = Expr.Resolve (ec);
3138
3139                         if (Expr == null)
3140                                 return null;
3141
3142                         eclass = Expr.ExprClass;
3143                         type = Expr.Type;
3144                         return this;
3145                 }
3146
3147                 public override void Emit (EmitContext ec)
3148                 {
3149                         bool last_check = ec.CheckState;
3150                         
3151                         ec.CheckState = true;
3152                         Expr.Emit (ec);
3153                         ec.CheckState = last_check;
3154                 }
3155                 
3156         }
3157
3158         public class UnCheckedExpr : Expression {
3159
3160                 public Expression Expr;
3161
3162                 public UnCheckedExpr (Expression e)
3163                 {
3164                         Expr = e;
3165                 }
3166
3167                 public override Expression DoResolve (EmitContext ec)
3168                 {
3169                         Expr = Expr.Resolve (ec);
3170
3171                         if (Expr == null)
3172                                 return null;
3173
3174                         eclass = Expr.ExprClass;
3175                         type = Expr.Type;
3176                         return this;
3177                 }
3178
3179                 public override void Emit (EmitContext ec)
3180                 {
3181                         bool last_check = ec.CheckState;
3182                         
3183                         ec.CheckState = false;
3184                         Expr.Emit (ec);
3185                         ec.CheckState = last_check;
3186                 }
3187                 
3188         }
3189
3190         public class ElementAccess : Expression {
3191                 
3192                 public ArrayList  Arguments;
3193                 public Expression Expr;
3194                 public Location   loc;
3195                 
3196                 public ElementAccess (Expression e, ArrayList e_list, Location l)
3197                 {
3198                         Expr = e;
3199
3200                         Arguments = new ArrayList ();
3201                         foreach (Expression tmp in e_list)
3202                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
3203                         
3204                         loc  = l;
3205                 }
3206
3207                 bool CommonResolve (EmitContext ec)
3208                 {
3209                         Expr = Expr.Resolve (ec);
3210
3211                         if (Expr == null) 
3212                                 return false;
3213
3214                         if (Arguments == null)
3215                                 return false;
3216
3217                         for (int i = Arguments.Count; i > 0;){
3218                                 --i;
3219                                 Argument a = (Argument) Arguments [i];
3220                                 
3221                                 if (!a.Resolve (ec))
3222                                         return false;
3223                         }
3224
3225                         return true;
3226                 }
3227                                 
3228                 public override Expression DoResolve (EmitContext ec)
3229                 {
3230                         if (!CommonResolve (ec))
3231                                 return null;
3232
3233                         //
3234                         // We perform some simple tests, and then to "split" the emit and store
3235                         // code we create an instance of a different class, and return that.
3236                         //
3237                         // I am experimenting with this pattern.
3238                         //
3239                         if (Expr.Type == TypeManager.array_type)
3240                                 return (new ArrayAccess (this)).Resolve (ec);
3241                         else
3242                                 return (new IndexerAccess (this)).Resolve (ec);
3243                 }
3244
3245                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3246                 {
3247                         if (!CommonResolve (ec))
3248                                 return null;
3249
3250                         if (Expr.Type == TypeManager.array_type)
3251                                 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
3252                         else
3253                                 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
3254                 }
3255                 
3256                 public override void Emit (EmitContext ec)
3257                 {
3258                         throw new Exception ("Should never be reached");
3259                 }
3260         }
3261
3262         public class ArrayAccess : Expression, IStackStore {
3263                 //
3264                 // Points to our "data" repository
3265                 //
3266                 ElementAccess ea;
3267                 
3268                 public ArrayAccess (ElementAccess ea_data)
3269                 {
3270                         ea = ea_data;
3271                         eclass = ExprClass.Variable;
3272
3273                         //
3274                         // FIXME: Figure out the type here
3275                         //
3276                 }
3277
3278                 Expression CommonResolve (EmitContext ec)
3279                 {
3280                         return this;
3281                 }
3282                 
3283                 public override Expression DoResolve (EmitContext ec)
3284                 {
3285                         if (ea.Expr.ExprClass != ExprClass.Variable) {
3286                                 report118 (ea.loc, ea.Expr, "variable");
3287                                 return null;
3288                         }
3289                         
3290                         throw new Exception ("Implement me");
3291                 }
3292
3293                 public void Store (EmitContext ec)
3294                 {
3295                         throw new Exception ("Implement me !");
3296                 }
3297
3298                 public override void Emit (EmitContext ec)
3299                 {
3300                         throw new Exception ("Implement me !");
3301                 }
3302         }
3303
3304         class Indexers {
3305                 public ArrayList getters, setters;
3306                 static Hashtable map;
3307
3308                 static Indexers ()
3309                 {
3310                         map = new Hashtable ();
3311                 }
3312
3313                 Indexers (MemberInfo [] mi)
3314                 {
3315                         foreach (PropertyInfo property in mi){
3316                                 MethodInfo get, set;
3317                                 
3318                                 get = property.GetGetMethod (true);
3319                                 if (get != null){
3320                                         if (getters == null)
3321                                                 getters = new ArrayList ();
3322
3323                                         getters.Add (get);
3324                                 }
3325                                 
3326                                 set = property.GetSetMethod (true);
3327                                 if (set != null){
3328                                         if (setters == null)
3329                                                 setters = new ArrayList ();
3330                                         setters.Add (set);
3331                                 }
3332                         }
3333                 }
3334                 
3335                 static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) 
3336                 {
3337                         Indexers ix = (Indexers) map [t];
3338                         string p_name = TypeManager.IndexerPropertyName (t);
3339                         
3340                         if (ix != null)
3341                                 return ix;
3342
3343                         MemberInfo [] mi = tm.FindMembers (
3344                                 t, MemberTypes.Property,
3345                                 BindingFlags.Public | BindingFlags.Instance,
3346                                 Type.FilterName, p_name);
3347
3348                         if (mi == null || mi.Length == 0){
3349                                 Report.Error (21, loc,
3350                                               "Type `" + TypeManager.CSharpName (t) + "' does not have " +
3351                                               "any indexers defined");
3352                                 return null;
3353                         }
3354                         
3355                         ix = new Indexers (mi);
3356                         map [t] = ix;
3357
3358                         return ix;
3359                 }
3360         }
3361         
3362         public class IndexerAccess : Expression, IAssignMethod {
3363                 //
3364                 // Points to our "data" repository
3365                 //
3366                 ElementAccess ea;
3367                 MethodInfo get, set;
3368                 Indexers ilist;
3369                 ArrayList set_arguments;
3370                 
3371                 public IndexerAccess (ElementAccess ea_data)
3372                 {
3373                         ea = ea_data;
3374                         eclass = ExprClass.Value;
3375                 }
3376
3377                 public bool VerifyAssignable (Expression source)
3378                 {
3379                         throw new Exception ("Implement me!");
3380                 }
3381
3382                 public override Expression DoResolve (EmitContext ec)
3383                 {
3384                         Type indexer_type = ea.Expr.Type;
3385                         
3386                         //
3387                         // Step 1: Query for all `Item' *properties*.  Notice
3388                         // that the actual methods are pointed from here.
3389                         //
3390                         // This is a group of properties, piles of them.  
3391
3392                         if (ilist == null)
3393                                 ilist = Indexers.GetIndexersForType (
3394                                         indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc);
3395                         
3396                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
3397                                 get = (MethodInfo) Invocation.OverloadResolve (
3398                                         ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc);
3399
3400                         if (get == null){
3401                                 Report.Error (154, ea.loc,
3402                                               "indexer can not be used in this context, because " +
3403                                               "it lacks a `get' accessor");
3404                                         return null;
3405                         }
3406                                 
3407                         type = get.ReturnType;
3408                         eclass = ExprClass.Value;
3409                         return this;
3410                 }
3411
3412                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3413                 {
3414                         Type indexer_type = ea.Expr.Type;
3415                         Type right_type = right_side.Type;
3416
3417                         if (ilist == null)
3418                                 ilist = Indexers.GetIndexersForType (
3419                                         indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc);
3420
3421                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
3422                                 set_arguments = (ArrayList) ea.Arguments.Clone ();
3423                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
3424
3425                                 set = (MethodInfo) Invocation.OverloadResolve (
3426                                         ec, new MethodGroupExpr (ilist.setters), set_arguments, ea.loc);
3427                         }
3428                         
3429                         if (set == null){
3430                                 Report.Error (200, ea.loc,
3431                                               "indexer X.this [" + TypeManager.CSharpName (right_type) +
3432                                               "] lacks a `set' accessor");
3433                                         return null;
3434                         }
3435
3436                         type = TypeManager.void_type;
3437                         eclass = ExprClass.IndexerAccess;
3438                         return this;
3439                 }
3440                 
3441                 public override void Emit (EmitContext ec)
3442                 {
3443                         Invocation.EmitCall (ec, false, ea.Expr, get, ea.Arguments);
3444                 }
3445
3446                 //
3447                 // source is ignored, because we already have a copy of it from the
3448                 // LValue resolution and we have already constructed a pre-cached
3449                 // version of the arguments (ea.set_arguments);
3450                 //
3451                 public void EmitAssign (EmitContext ec, Expression source)
3452                 {
3453                         Invocation.EmitCall (ec, false, ea.Expr, set, set_arguments);
3454                 }
3455         }
3456         
3457         public class BaseAccess : Expression {
3458
3459                 public enum BaseAccessType {
3460                         Member,
3461                         Indexer
3462                 };
3463                 
3464                 public readonly BaseAccessType BAType;
3465                 public readonly string         Member;
3466                 public readonly ArrayList      Arguments;
3467
3468                 public BaseAccess (BaseAccessType t, string member, ArrayList args)
3469                 {
3470                         BAType = t;
3471                         Member = member;
3472                         Arguments = args;
3473                         
3474                 }
3475
3476                 public override Expression DoResolve (EmitContext ec)
3477                 {
3478                         // FIXME: Implement;
3479                         throw new Exception ("Unimplemented");
3480                         // return this;
3481                 }
3482
3483                 public override void Emit (EmitContext ec)
3484                 {
3485                         throw new Exception ("Unimplemented");
3486                 }
3487         }
3488
3489         // <summary>
3490         //   This class exists solely to pass the Type around and to be a dummy
3491         //   that can be passed to the conversion functions (this is used by
3492         //   foreach implementation to typecast the object return value from
3493         //   get_Current into the proper type.  All code has been generated and
3494         //   we only care about the side effect conversions to be performed
3495         // </summary>
3496         
3497         public class EmptyExpression : Expression {
3498                 public EmptyExpression ()
3499                 {
3500                         type = TypeManager.object_type;
3501                         eclass = ExprClass.Value;
3502                 }
3503
3504                 public override Expression DoResolve (EmitContext ec)
3505                 {
3506                         return this;
3507                 }
3508
3509                 public override void Emit (EmitContext ec)
3510                 {
3511                         // nothing, as we only exist to not do anything.
3512                 }
3513         }
3514
3515         public class UserCast : Expression {
3516                 MethodBase method;
3517                 Expression source;
3518                 
3519                 public UserCast (MethodInfo method, Expression source)
3520                 {
3521                         this.method = method;
3522                         this.source = source;
3523                         type = method.ReturnType;
3524                         eclass = ExprClass.Value;
3525                 }
3526
3527                 public override Expression DoResolve (EmitContext ec)
3528                 {
3529                         //
3530                         // We are born fully resolved
3531                         //
3532                         return this;
3533                 }
3534
3535                 public override void Emit (EmitContext ec)
3536                 {
3537                         ILGenerator ig = ec.ig;
3538
3539                         source.Emit (ec);
3540                         
3541                         if (method is MethodInfo)
3542                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
3543                         else
3544                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3545
3546                 }
3547
3548         }
3549 }