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