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