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