(ArrayAccess.DoResolve): Array Access can operate on
[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 Type.GetType (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                                                 if (pd.ParameterType (i) != a.Type)
3286                                                         return false;
3287                                 } else
3288                                         return false;
3289                                 
3290                         }
3291
3292                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
3293
3294                         for (int i = pd_count - 1; i < arg_count; i++) {
3295                                 Argument a = (Argument) arguments [i];
3296                                 
3297                                 if (!StandardConversionExists (a.Expr, element_type))
3298                                         return false;
3299                         }
3300                         
3301                         return true;
3302                 }
3303
3304                 /// <summary>
3305                 ///  Determines if the candidate method is applicable (section 14.4.2.1)
3306                 ///  to the given set of arguments
3307                 /// </summary>
3308                 static bool IsApplicable (ArrayList arguments, MethodBase candidate)
3309                 {
3310                         int arg_count;
3311
3312                         if (arguments == null)
3313                                 arg_count = 0;
3314                         else
3315                                 arg_count = arguments.Count;
3316
3317                         ParameterData pd = GetParameterData (candidate);
3318
3319                         int pd_count = pd.Count;
3320
3321                         if (arg_count != pd.Count)
3322                                 return false;
3323
3324                         for (int i = arg_count; i > 0; ) {
3325                                 i--;
3326
3327                                 Argument a = (Argument) arguments [i];
3328
3329                                 Parameter.Modifier a_mod = a.GetParameterModifier ();
3330                                 Parameter.Modifier p_mod = pd.ParameterModifier (i);
3331
3332                                 if (a_mod == p_mod) {
3333                                         if (a_mod == Parameter.Modifier.NONE)
3334                                                 if (!StandardConversionExists (a.Expr, pd.ParameterType (i)))
3335                                                         return false;
3336                                         
3337                                         if (a_mod == Parameter.Modifier.REF ||
3338                                             a_mod == Parameter.Modifier.OUT)
3339                                                 if (pd.ParameterType (i) != a.Type)
3340                                                         return false;
3341                                 } else
3342                                         return false;
3343                         }
3344
3345                         return true;
3346                 }
3347                 
3348                 
3349
3350                 /// <summary>
3351                 ///   Find the Applicable Function Members (7.4.2.1)
3352                 ///
3353                 ///   me: Method Group expression with the members to select.
3354                 ///       it might contain constructors or methods (or anything
3355                 ///       that maps to a method).
3356                 ///
3357                 ///   Arguments: ArrayList containing resolved Argument objects.
3358                 ///
3359                 ///   loc: The location if we want an error to be reported, or a Null
3360                 ///        location for "probing" purposes.
3361                 ///
3362                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3363                 ///            that is the best match of me on Arguments.
3364                 ///
3365                 /// </summary>
3366                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3367                                                           ArrayList Arguments, Location loc)
3368                 {
3369                         ArrayList afm = new ArrayList ();
3370                         int best_match_idx = -1;
3371                         MethodBase method = null;
3372                         int argument_count;
3373                         ArrayList candidates = new ArrayList ();
3374
3375                         for (int i = me.Methods.Length; i > 0; ){
3376                                 i--;
3377                                 MethodBase candidate  = me.Methods [i];
3378                                 int x;
3379
3380                                 // Check if candidate is applicable (section 14.4.2.1)
3381                                 if (!IsApplicable (Arguments, candidate))
3382                                         continue;
3383
3384                                 candidates.Add (candidate);
3385                                 
3386                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
3387                                 
3388                                 if (x == 0)
3389                                         continue;
3390                                 else {
3391                                         best_match_idx = i;
3392                                         method = me.Methods [best_match_idx];
3393                                 }
3394                         }
3395
3396                         if (Arguments == null)
3397                                 argument_count = 0;
3398                         else
3399                                 argument_count = Arguments.Count;
3400                         
3401                         //
3402                         // Now we see if we can find params functions, applicable in their expanded form
3403                         // since if they were applicable in their normal form, they would have been selected
3404                         // above anyways
3405                         //
3406                         bool chose_params_expanded = false;
3407                         
3408                         if (best_match_idx == -1) {
3409
3410                                 candidates = new ArrayList ();
3411                                 for (int i = me.Methods.Length; i > 0; ) {
3412                                         i--;
3413                                         MethodBase candidate = me.Methods [i];
3414
3415                                         if (!IsParamsMethodApplicable (Arguments, candidate))
3416                                                 continue;
3417
3418                                         candidates.Add (candidate);
3419
3420                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
3421
3422                                         if (x == 0)
3423                                                 continue;
3424                                         else {
3425                                                 best_match_idx = i;
3426                                                 method = me.Methods [best_match_idx];
3427                                                 chose_params_expanded = true;
3428                                         }
3429                                 }
3430                         }
3431
3432                         //
3433                         // Now we see if we can at least find a method with the same number of arguments
3434                         //
3435                         ParameterData pd;
3436
3437                         if (best_match_idx == -1) {
3438
3439                                 for (int i = me.Methods.Length; i > 0;) {
3440                                         i--;
3441                                         MethodBase mb = me.Methods [i];
3442                                         pd = GetParameterData (mb);
3443                                         
3444                                         if (pd.Count == argument_count) {
3445                                                 best_match_idx = i;
3446                                                 method = me.Methods [best_match_idx];
3447                                         } else
3448                                                 continue;
3449                                 }
3450                         }
3451
3452                         if (method == null)
3453                                 return null;
3454
3455                         //
3456                         // Now check that there are no ambiguities i.e the selected method
3457                         // should be better than all the others
3458                         //
3459
3460                         for (int i = 0; i < candidates.Count; ++i) {
3461                                 MethodBase candidate = (MethodBase) candidates [i];
3462
3463                                 if (candidate == method)
3464                                         continue;
3465
3466                                 //
3467                                 // If a normal method is applicable in the sense that it has the same
3468                                 // number of arguments, then the expanded params method is never applicable
3469                                 // so we debar the params method.
3470                                 //
3471                                 if (IsParamsMethodApplicable (Arguments, candidate) &&
3472                                     IsApplicable (Arguments, method))
3473                                         continue;
3474                                         
3475                                 int x = BetterFunction (ec, Arguments, method, candidate,
3476                                                         chose_params_expanded, loc);
3477
3478                                 if (x != 1) {
3479                                         Report.Error (
3480                                                 121, loc,
3481                                                 "Ambiguous call when selecting function due to implicit casts");
3482                                         return null;
3483                                 }
3484                         }
3485
3486                         //
3487                         // And now check if the arguments are all compatible, perform conversions
3488                         // if necessary etc. and return if everything is all right
3489                         //
3490
3491                         if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
3492                                                    chose_params_expanded, null, loc))
3493                                 return method;
3494                         else
3495                                 return null;
3496                 }
3497
3498                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
3499                                                           int argument_count,
3500                                                           MethodBase method, 
3501                                                           bool chose_params_expanded,
3502                                                           Type delegate_type,
3503                                                           Location loc)
3504                 {
3505                         ParameterData pd = GetParameterData (method);
3506                         int pd_count = pd.Count;
3507                         
3508                         for (int j = 0; j < argument_count; j++) {
3509                                 Argument a = (Argument) Arguments [j];
3510                                 Expression a_expr = a.Expr;
3511                                 Type parameter_type = pd.ParameterType (j);
3512
3513                                 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS && chose_params_expanded)
3514                                         parameter_type = parameter_type.GetElementType ();
3515
3516                                 if (a.Type != parameter_type){
3517                                         Expression conv;
3518                                         
3519                                         conv = ConvertImplicitStandard (ec, a_expr, parameter_type, loc);
3520
3521                                         if (conv == null) {
3522                                                 if (!Location.IsNull (loc)) {
3523                                                         if (delegate_type == null) 
3524                                                                 Error (1502, loc,
3525                                                                        "The best overloaded match for method '" +
3526                                                                        FullMethodDesc (method) +
3527                                                                        "' has some invalid arguments");
3528                                                         else
3529                                                                 Report.Error (1594, loc,
3530                                                                               "Delegate '" + delegate_type.ToString () +
3531                                                                               "' has some invalid arguments.");
3532                                                         Error (1503, loc,
3533                                                          "Argument " + (j+1) +
3534                                                          ": Cannot convert from '" + Argument.FullDesc (a) 
3535                                                          + "' to '" + pd.ParameterDesc (j) + "'");
3536                                                 }
3537                                                 
3538                                                 return false;
3539                                         }
3540                                         
3541                                         //
3542                                         // Update the argument with the implicit conversion
3543                                         //
3544                                         if (a_expr != conv)
3545                                                 a.Expr = conv;
3546                                 }
3547                                 
3548                                 if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
3549                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
3550                                         if (!Location.IsNull (loc)) {
3551                                                 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
3552                                                 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
3553                                                 Console.WriteLine ("PT:  " + parameter_type.IsByRef);
3554                                                 Error (1502, loc,
3555                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
3556                                                        "' has some invalid arguments");
3557                                                 Error (1503, loc,
3558                                                        "Argument " + (j+1) +
3559                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
3560                                                        + "' to '" + pd.ParameterDesc (j) + "'");
3561                                         }
3562                                         
3563                                         return false;
3564                                 }
3565                         }
3566
3567                         return true;
3568                 }
3569                 
3570                 public override Expression DoResolve (EmitContext ec)
3571                 {
3572                         //
3573                         // First, resolve the expression that is used to
3574                         // trigger the invocation
3575                         //
3576                         if (expr is BaseAccess)
3577                                 is_base = true;
3578
3579                         expr = expr.Resolve (ec);
3580                         if (expr == null)
3581                                 return null;
3582
3583                         if (!(expr is MethodGroupExpr)) {
3584                                 Type expr_type = expr.Type;
3585
3586                                 if (expr_type != null){
3587                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
3588                                         if (IsDelegate)
3589                                                 return (new DelegateInvocation (
3590                                                         this.expr, Arguments, loc)).Resolve (ec);
3591                                 }
3592                         }
3593
3594                         if (!(expr is MethodGroupExpr)){
3595                                 report118 (loc, this.expr, "method group");
3596                                 return null;
3597                         }
3598
3599                         //
3600                         // Next, evaluate all the expressions in the argument list
3601                         //
3602                         if (Arguments != null){
3603                                 for (int i = Arguments.Count; i > 0;){
3604                                         --i;
3605                                         Argument a = (Argument) Arguments [i];
3606
3607                                         if (!a.Resolve (ec, loc))
3608                                                 return null;
3609                                 }
3610                         }
3611
3612                         method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);
3613
3614                         if (method == null){
3615                                 Error (-6, loc,
3616                                        "Could not find any applicable function for this argument list");
3617                                 return null;
3618                         }
3619
3620                         if (method is MethodInfo)
3621                                 type = ((MethodInfo)method).ReturnType;
3622
3623                         if (type.IsPointer){
3624                                 if (!ec.InUnsafe){
3625                                         UnsafeError (loc);
3626                                         return null;
3627                                 }
3628                         }
3629                         
3630                         eclass = ExprClass.Value;
3631                         return this;
3632                 }
3633
3634                 // <summary>
3635                 //   Emits the list of arguments as an array
3636                 // </summary>
3637                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
3638                 {
3639                         ILGenerator ig = ec.ig;
3640                         int count = arguments.Count - idx;
3641                         Argument a = (Argument) arguments [idx];
3642                         Type t = a.expr.Type;
3643                         string array_type = t.FullName + "[]";
3644                         LocalBuilder array;
3645
3646                         array = ig.DeclareLocal (Type.GetType (array_type));
3647                         IntConstant.EmitInt (ig, count);
3648                         ig.Emit (OpCodes.Newarr, t);
3649                         ig.Emit (OpCodes.Stloc, array);
3650
3651                         int top = arguments.Count;
3652                         for (int j = idx; j < top; j++){
3653                                 a = (Argument) arguments [j];
3654                                 
3655                                 ig.Emit (OpCodes.Ldloc, array);
3656                                 IntConstant.EmitInt (ig, j - idx);
3657                                 a.Emit (ec);
3658                                 
3659                                 ArrayAccess.EmitStoreOpcode (ig, t);
3660                         }
3661                         ig.Emit (OpCodes.Ldloc, array);
3662                 }
3663                 
3664                 /// <summary>
3665                 ///   Emits a list of resolved Arguments that are in the arguments
3666                 ///   ArrayList.
3667                 /// 
3668                 ///   The MethodBase argument might be null if the
3669                 ///   emission of the arguments is known not to contain
3670                 ///   a `params' field (for example in constructors or other routines
3671                 ///   that keep their arguments in this structure
3672                 /// </summary>
3673                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
3674                 {
3675                         ParameterData pd;
3676                         if (mb != null)
3677                                 pd = GetParameterData (mb);
3678                         else
3679                                 pd = null;
3680
3681                         //
3682                         // If we are calling a params method with no arguments, special case it
3683                         //
3684                         if (arguments == null){
3685                                 if (pd != null && pd.Count > 0 &&
3686                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
3687                                         ILGenerator ig = ec.ig;
3688
3689                                         IntConstant.EmitInt (ig, 0);
3690                                         ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
3691                                 }
3692
3693                                 return;
3694                         }
3695
3696                         int top = arguments.Count;
3697
3698                         for (int i = 0; i < top; i++){
3699                                 Argument a = (Argument) arguments [i];
3700
3701                                 if (pd != null){
3702                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
3703                                                 //
3704                                                 // Special case if we are passing the same data as the
3705                                                 // params argument, do not put it in an array.
3706                                                 //
3707                                                 if (pd.ParameterType (i) == a.Type)
3708                                                         a.Emit (ec);
3709                                                 else
3710                                                         EmitParams (ec, i, arguments);
3711                                                 return;
3712                                         }
3713                                 }
3714                                             
3715                                 a.Emit (ec);
3716                         }
3717                 }
3718
3719                 /// <remarks>
3720                 ///   is_base tells whether we want to force the use of the `call'
3721                 ///   opcode instead of using callvirt.  Call is required to call
3722                 ///   a specific method, while callvirt will always use the most
3723                 ///   recent method in the vtable.
3724                 ///
3725                 ///   is_static tells whether this is an invocation on a static method
3726                 ///
3727                 ///   instance_expr is an expression that represents the instance
3728                 ///   it must be non-null if is_static is false.
3729                 ///
3730                 ///   method is the method to invoke.
3731                 ///
3732                 ///   Arguments is the list of arguments to pass to the method or constructor.
3733                 /// </remarks>
3734                 public static void EmitCall (EmitContext ec, bool is_base,
3735                                              bool is_static, Expression instance_expr,
3736                                              MethodBase method, ArrayList Arguments)
3737                 {
3738                         ILGenerator ig = ec.ig;
3739                         bool struct_call = false;
3740                                 
3741                         if (!is_static){
3742                                 
3743                                 if (method.DeclaringType.IsValueType)
3744                                         struct_call = true;
3745                                 //
3746                                 // If this is ourselves, push "this"
3747                                 //
3748                                 if (instance_expr == null){
3749                                         ig.Emit (OpCodes.Ldarg_0);
3750                                 } else {
3751                                         //
3752                                         // Push the instance expression
3753                                         //
3754                                         if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
3755                                                 //
3756                                                 // Special case: calls to a function declared in a 
3757                                                 // reference-type with a value-type argument need
3758                                                 // to have their value boxed.  
3759
3760                                                 struct_call = true;
3761                                                 if (method.DeclaringType.IsValueType){
3762                                                         //
3763                                                         // If the expression implements IMemoryLocation, then
3764                                                         // we can optimize and use AddressOf on the
3765                                                         // return.
3766                                                         //
3767                                                         // If not we have to use some temporary storage for
3768                                                         // it.
3769                                                         if (instance_expr is IMemoryLocation){
3770                                                                 ((IMemoryLocation)instance_expr).
3771                                                                         AddressOf (ec, AddressOp.LoadStore);
3772                                                         }
3773                                                         else {
3774                                                                 Type t = instance_expr.Type;
3775                                                                 
3776                                                                 instance_expr.Emit (ec);
3777                                                                 LocalBuilder temp = ig.DeclareLocal (t);
3778                                                                 ig.Emit (OpCodes.Stloc, temp);
3779                                                                 ig.Emit (OpCodes.Ldloca, temp);
3780                                                         }
3781                                                 } else {
3782                                                         instance_expr.Emit (ec);
3783                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
3784                                                 } 
3785                                         } else
3786                                                 instance_expr.Emit (ec);
3787                                 }
3788                         }
3789
3790                         EmitArguments (ec, method, Arguments);
3791
3792                         if (is_static || struct_call || is_base){
3793                                 if (method is MethodInfo)
3794                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3795                                 else
3796                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3797                         } else {
3798                                 if (method is MethodInfo)
3799                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3800                                 else
3801                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3802                         }
3803                 }
3804                 
3805                 public override void Emit (EmitContext ec)
3806                 {
3807                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3808
3809                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments);
3810                 }
3811                 
3812                 public override void EmitStatement (EmitContext ec)
3813                 {
3814                         Emit (ec);
3815
3816                         // 
3817                         // Pop the return value if there is one
3818                         //
3819                         if (method is MethodInfo){
3820                                 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3821                                         ec.ig.Emit (OpCodes.Pop);
3822                         }
3823                 }
3824         }
3825
3826         //
3827         // This class is used to "disable" the code generation for the
3828         // temporary variable when initializing value types.
3829         //
3830         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
3831                 public void AddressOf (EmitContext ec, AddressOp Mode)
3832                 {
3833                         // nothing
3834                 }
3835         }
3836         
3837         /// <summary>
3838         ///    Implements the new expression 
3839         /// </summary>
3840         public class New : ExpressionStatement {
3841                 public readonly ArrayList Arguments;
3842                 public readonly string    RequestedType;
3843
3844                 Location loc;
3845                 MethodBase method = null;
3846
3847                 //
3848                 // If set, the new expression is for a value_target, and
3849                 // we will not leave anything on the stack.
3850                 //
3851                 Expression value_target;
3852                 
3853                 public New (string requested_type, ArrayList arguments, Location l)
3854                 {
3855                         RequestedType = requested_type;
3856                         Arguments = arguments;
3857                         loc = l;
3858                 }
3859
3860                 public Expression ValueTypeVariable {
3861                         get {
3862                                 return value_target;
3863                         }
3864
3865                         set {
3866                                 value_target = value;
3867                         }
3868                 }
3869
3870                 //
3871                 // This function is used to disable the following code sequence for
3872                 // value type initialization:
3873                 //
3874                 // AddressOf (temporary)
3875                 // Construct/Init
3876                 // LoadTemporary
3877                 //
3878                 // Instead the provide will have provided us with the address on the
3879                 // stack to store the results.
3880                 //
3881                 static Expression MyEmptyExpression;
3882                 
3883                 public void DisableTemporaryValueType ()
3884                 {
3885                         if (MyEmptyExpression == null)
3886                                 MyEmptyExpression = new EmptyAddressOf ();
3887
3888                         //
3889                         // To enable this, look into:
3890                         // test-34 and test-89 and self bootstrapping.
3891                         //
3892                         // For instance, we can avoid a copy by using `newobj'
3893                         // instead of Call + Push-temp on value types.
3894 //                      value_target = MyEmptyExpression;
3895                 }
3896                 
3897                 public override Expression DoResolve (EmitContext ec)
3898                 {
3899                         type = RootContext.LookupType (ec.DeclSpace, RequestedType, false, loc);
3900                         
3901                         if (type == null)
3902                                 return null;
3903                         
3904                         bool IsDelegate = TypeManager.IsDelegateType (type);
3905                         
3906                         if (IsDelegate)
3907                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
3908                         
3909                         bool is_struct = false;
3910                         is_struct = type.IsSubclassOf (TypeManager.value_type);
3911                         eclass = ExprClass.Value;
3912
3913                         //
3914                         // SRE returns a match for .ctor () on structs (the object constructor), 
3915                         // so we have to manually ignore it.
3916                         //
3917                         if (is_struct && Arguments == null)
3918                                 return this;
3919                         
3920                         Expression ml;
3921                         ml = MemberLookup (ec, type, ".ctor",
3922                                            MemberTypes.Constructor,
3923                                            AllBindingFlags | BindingFlags.DeclaredOnly, loc);
3924                         
3925                         if (! (ml is MethodGroupExpr)){
3926                                 if (!is_struct){
3927                                         report118 (loc, ml, "method group");
3928                                         return null;
3929                                 }
3930                         }
3931
3932                         if (ml != null) {
3933                                 if (Arguments != null){
3934                                         for (int i = Arguments.Count; i > 0;){
3935                                                 --i;
3936                                                 Argument a = (Argument) Arguments [i];
3937                                                 
3938                                                 if (!a.Resolve (ec, loc))
3939                                                         return null;
3940                                         }
3941                                 }
3942
3943                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
3944                                                                      Arguments, loc);
3945                                 
3946                         }
3947                         
3948                         if (method == null && !is_struct) {
3949                                 Error (1501, loc,
3950                                        "New invocation: Can not find a constructor for " +
3951                                        "this argument list");
3952                                 return null;
3953                         }
3954                         return this;
3955                 }
3956
3957                 //
3958                 // This DoEmit can be invoked in two contexts:
3959                 //    * As a mechanism that will leave a value on the stack (new object)
3960                 //    * As one that wont (init struct)
3961                 //
3962                 // You can control whether a value is required on the stack by passing
3963                 // need_value_on_stack.  The code *might* leave a value on the stack
3964                 // so it must be popped manually
3965                 //
3966                 // If we are dealing with a ValueType, we have a few
3967                 // situations to deal with:
3968                 //
3969                 //    * The target is a ValueType, and we have been provided
3970                 //      the instance (this is easy, we are being assigned).
3971                 //
3972                 //    * The target of New is being passed as an argument,
3973                 //      to a boxing operation or a function that takes a
3974                 //      ValueType.
3975                 //
3976                 //      In this case, we need to create a temporary variable
3977                 //      that is the argument of New.
3978                 //
3979                 // Returns whether a value is left on the stack
3980                 //
3981                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
3982                 {
3983                         bool is_value_type = type.IsSubclassOf (TypeManager.value_type);
3984                         ILGenerator ig = ec.ig;
3985
3986                         if (is_value_type){
3987                                 IMemoryLocation ml;
3988
3989                                 if (value_target == null)
3990                                         value_target = new LocalTemporary (ec, type);
3991                                         
3992                                 ml = (IMemoryLocation) value_target;
3993                                 ml.AddressOf (ec, AddressOp.Store);
3994                         }
3995
3996                         if (method != null)
3997                                 Invocation.EmitArguments (ec, method, Arguments);
3998
3999                         if (is_value_type){
4000                                 if (method == null)
4001                                         ig.Emit (OpCodes.Initobj, type);
4002                                 else 
4003                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4004                                 if (need_value_on_stack){
4005                                         value_target.Emit (ec);
4006                                         return true;
4007                                 }
4008                                 return false;
4009                         } else {
4010                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4011                                 return true;
4012                         }
4013                 }
4014
4015                 public override void Emit (EmitContext ec)
4016                 {
4017                         DoEmit (ec, true);
4018                 }
4019                 
4020                 public override void EmitStatement (EmitContext ec)
4021                 {
4022                         if (DoEmit (ec, false))
4023                                 ec.ig.Emit (OpCodes.Pop);
4024                 }
4025         }
4026
4027         /// <summary>
4028         ///   Represents an array creation expression.
4029         /// </summary>
4030         ///
4031         /// <remarks>
4032         ///   There are two possible scenarios here: one is an array creation
4033         ///   expression that specifies the dimensions and optionally the
4034         ///   initialization data and the other which does not need dimensions
4035         ///   specified but where initialization data is mandatory.
4036         /// </remarks>
4037         public class ArrayCreation : ExpressionStatement {
4038                 string RequestedType;
4039                 string Rank;
4040                 ArrayList Initializers;
4041                 Location  loc;
4042
4043                 //
4044                 // The list of Argument types.
4045                 // This is used to constrcut the `newarray' or constructor signature
4046                 //
4047                 ArrayList Arguments;
4048
4049                 MethodBase method = null;
4050                 Type array_element_type;
4051                 bool IsOneDimensional = false;
4052                 bool IsBuiltinType = false;
4053                 bool ExpectInitializers = false;
4054
4055                 int dimensions = 0;
4056                 Type underlying_type;
4057
4058                 ArrayList ArrayData;
4059
4060                 Hashtable Bounds;
4061
4062                 //
4063                 // The number of array initializers that we can handle
4064                 // via the InitializeArray method - through EmitStaticInitializers
4065                 //
4066                 int num_automatic_initializers;
4067                 
4068                 public ArrayCreation (string requested_type, ArrayList exprs,
4069                                       string rank, ArrayList initializers, Location l)
4070                 {
4071                         RequestedType = requested_type;
4072                         Rank          = rank;
4073                         Initializers  = initializers;
4074                         loc = l;
4075
4076                         Arguments = new ArrayList ();
4077
4078                         foreach (Expression e in exprs)
4079                                 Arguments.Add (new Argument (e, Argument.AType.Expression));
4080                 }
4081
4082                 public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)
4083                 {
4084                         RequestedType = requested_type;
4085                         Initializers = initializers;
4086                         loc = l;
4087
4088                         Rank = rank.Substring (0, rank.LastIndexOf ("["));
4089
4090                         string tmp = rank.Substring (rank.LastIndexOf ("["));
4091
4092                         dimensions = tmp.Length - 1;
4093                         ExpectInitializers = true;
4094                 }
4095
4096                 public static string FormArrayType (string base_type, int idx_count, string rank)
4097                 {
4098                         StringBuilder sb = new StringBuilder (base_type);
4099
4100                         sb.Append (rank);
4101                         
4102                         sb.Append ("[");
4103                         for (int i = 1; i < idx_count; i++)
4104                                 sb.Append (",");
4105                         
4106                         sb.Append ("]");
4107
4108                         return sb.ToString ();
4109                 }
4110
4111                 public static string FormElementType (string base_type, int idx_count, string rank)
4112                 {
4113                         StringBuilder sb = new StringBuilder (base_type);
4114                         
4115                         sb.Append ("[");
4116                         for (int i = 1; i < idx_count; i++)
4117                                 sb.Append (",");
4118                         
4119                         sb.Append ("]");
4120                         
4121                         sb.Append (rank);
4122
4123                         string val = sb.ToString ();
4124
4125                         return val.Substring (0, val.LastIndexOf ("["));
4126                 }
4127
4128                 void error178 ()
4129                 {
4130                         Report.Error (178, loc, "Incorrectly structured array initializer");
4131                 }
4132                 
4133                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
4134                 {
4135                         if (specified_dims) { 
4136                                 Argument a = (Argument) Arguments [idx];
4137                                 
4138                                 if (!a.Resolve (ec, loc))
4139                                         return false;
4140                                 
4141                                 if (!(a.Expr is Constant)) {
4142                                         Report.Error (150, loc, "A constant value is expected");
4143                                         return false;
4144                                 }
4145                                 
4146                                 int value = (int) ((Constant) a.Expr).GetValue ();
4147                                 
4148                                 if (value != probe.Count) {
4149                                         error178 ();
4150                                         return false;
4151                                 }
4152                                 
4153                                 Bounds [idx] = value;
4154                         }
4155                         
4156                         foreach (object o in probe) {
4157                                 if (o is ArrayList) {
4158                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
4159                                         if (!ret)
4160                                                 return false;
4161                                 } else {
4162                                         Expression tmp = (Expression) o;
4163                                         tmp = tmp.Resolve (ec);
4164                                         if (tmp == null)
4165                                                 continue;
4166                                         
4167                                         // Handle initialization from vars, fields etc.
4168
4169                                         Expression conv = ConvertImplicitRequired (
4170                                                 ec, tmp, underlying_type, loc);
4171                                         
4172                                         if (conv == null) 
4173                                                 return false;
4174
4175                                         if (conv is StringConstant)
4176                                                 ArrayData.Add (conv);
4177                                         else if (conv is Constant) {
4178                                                 ArrayData.Add (conv);
4179                                                 num_automatic_initializers++;
4180                                         } else
4181                                                 ArrayData.Add (conv);
4182                                 }
4183                         }
4184
4185                         return true;
4186                 }
4187                 
4188                 public void UpdateIndices (EmitContext ec)
4189                 {
4190                         int i = 0;
4191                         for (ArrayList probe = Initializers; probe != null;) {
4192                                 if (probe.Count > 0 && probe [0] is ArrayList) {
4193                                         Expression e = new IntConstant (probe.Count);
4194                                         Arguments.Add (new Argument (e, Argument.AType.Expression));
4195
4196                                         Bounds [i++] =  probe.Count;
4197                                         
4198                                         probe = (ArrayList) probe [0];
4199                                         
4200                                 } else {
4201                                         Expression e = new IntConstant (probe.Count);
4202                                         Arguments.Add (new Argument (e, Argument.AType.Expression));
4203
4204                                         Bounds [i++] = probe.Count;
4205                                         probe = null;
4206                                 }
4207                         }
4208
4209                 }
4210                 
4211                 public bool ValidateInitializers (EmitContext ec)
4212                 {
4213                         if (Initializers == null) {
4214                                 if (ExpectInitializers)
4215                                         return false;
4216                                 else
4217                                         return true;
4218                         }
4219                         
4220                         underlying_type = RootContext.LookupType (
4221                                 ec.DeclSpace, RequestedType, false, loc);
4222                         
4223                         //
4224                         // We use this to store all the date values in the order in which we
4225                         // will need to store them in the byte blob later
4226                         //
4227                         ArrayData = new ArrayList ();
4228                         Bounds = new Hashtable ();
4229                         
4230                         bool ret;
4231
4232                         if (Arguments != null) {
4233                                 ret = CheckIndices (ec, Initializers, 0, true);
4234                                 return ret;
4235                                 
4236                         } else {
4237                                 Arguments = new ArrayList ();
4238
4239                                 ret = CheckIndices (ec, Initializers, 0, false);
4240                                 
4241                                 if (!ret)
4242                                         return false;
4243                                 
4244                                 UpdateIndices (ec);
4245                                 
4246                                 if (Arguments.Count != dimensions) {
4247                                         error178 ();
4248                                         return false;
4249                                 }
4250
4251                                 return ret;
4252                         }
4253                 }
4254                 
4255                 public override Expression DoResolve (EmitContext ec)
4256                 {
4257                         int arg_count;
4258
4259                         //
4260                         // First step is to validate the initializers and fill
4261                         // in any missing bits
4262                         //
4263                         if (!ValidateInitializers (ec))
4264                                 return null;
4265
4266                         if (Arguments == null)
4267                                 arg_count = 0;
4268                         else {
4269                                 arg_count = Arguments.Count;
4270                                 for (int i = 0; i < arg_count; i++){
4271                                         Argument a = (Argument) Arguments [i];
4272                                         
4273                                         if (!a.Resolve (ec, loc))
4274                                                 return null;
4275
4276                                         //
4277                                         // Now, convert that to an integer
4278                                         //
4279                                         Expression real_arg;
4280                                         bool old_checked = ec.CheckState;
4281                                         ec.CheckState = true;
4282                         
4283                                         real_arg = ConvertExplicit (
4284                                                 ec, a.expr, TypeManager.uint32_type, loc);
4285                                         ec.CheckState = old_checked;
4286                                         if (real_arg == null)
4287                                                 return null;
4288
4289                                         a.expr = real_arg;
4290                                 }
4291                         }
4292                         
4293                         string array_type = FormArrayType (RequestedType, arg_count, Rank);
4294                         string element_type = FormElementType (RequestedType, arg_count, Rank);
4295
4296                         type = RootContext.LookupType (ec.DeclSpace, array_type, false, loc);
4297                         
4298                         array_element_type = RootContext.LookupType (
4299                                 ec.DeclSpace, element_type, false, loc);
4300                         
4301                         if (type == null)
4302                                 return null;
4303                         
4304                         if (arg_count == 1) {
4305                                 IsOneDimensional = true;
4306                                 eclass = ExprClass.Value;
4307                                 return this;
4308                         }
4309
4310                         IsBuiltinType = TypeManager.IsBuiltinType (type);
4311                         
4312                         if (IsBuiltinType) {
4313
4314                                 Expression ml;
4315                                 
4316                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
4317                                                    AllBindingFlags, loc);
4318                                 
4319                                 if (!(ml is MethodGroupExpr)){
4320                                         report118 (loc, ml, "method group");
4321                                         return null;
4322                                 }
4323                                 
4324                                 if (ml == null) {
4325                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4326                                                       "this argument list");
4327                                         return null;
4328                                 }
4329                                 
4330                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
4331
4332                                 if (method == null) {
4333                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4334                                                       "this argument list");
4335                                         return null;
4336                                 }
4337                                 
4338                                 eclass = ExprClass.Value;
4339                                 return this;
4340                                 
4341                         } else {
4342
4343                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
4344
4345                                 ArrayList args = new ArrayList ();
4346                                 if (Arguments != null){
4347                                         for (int i = arg_count; i > 0;){
4348                                                 --i;
4349                                                 Argument a = (Argument) Arguments [i];
4350                                                 
4351                                                 args.Add (TypeManager.int32_type);
4352                                         }
4353                                 }
4354                                 
4355                                 Type [] arg_types = null;
4356
4357                                 if (args.Count > 0)
4358                                         arg_types = new Type [args.Count];
4359                                 
4360                                 args.CopyTo (arg_types, 0);
4361                                 
4362                                 method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
4363                                                             arg_types);
4364
4365                                 if (method == null) {
4366                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4367                                                       "this argument list");
4368                                         return null;
4369                                 }
4370                                 
4371                                 eclass = ExprClass.Value;
4372                                 return this;
4373                                 
4374                         }
4375                 }
4376
4377                 public static byte [] MakeByteBlob (ArrayList ArrayData, Type underlying_type, Location loc)
4378                 {
4379                         int factor;
4380                         byte [] data;
4381                         byte [] element;
4382                         int count = ArrayData.Count;
4383
4384                         factor = GetTypeSize (underlying_type);
4385                         if (factor == 0)
4386                                 return null;
4387
4388                         data = new byte [(count * factor + 4) & ~3];
4389                         int idx = 0;
4390                         
4391                         for (int i = 0; i < count; ++i) {
4392                                 object v = ArrayData [i];
4393
4394                                 if (v is EnumConstant)
4395                                         v = ((EnumConstant) v).Child;
4396                                 
4397                                 if (v is Constant && !(v is StringConstant))
4398                                         v = ((Constant) v).GetValue ();
4399                                 else {
4400                                         idx += factor;
4401                                         continue;
4402                                 }
4403                                 
4404                                 if (underlying_type == TypeManager.int64_type){
4405                                         if (!(v is Expression)){
4406                                                 long val = (long) v;
4407                                                 
4408                                                 for (int j = 0; j < factor; ++j) {
4409                                                         data [idx + j] = (byte) (val & 0xFF);
4410                                                         val = (val >> 8);
4411                                                 }
4412                                         }
4413                                 } else if (underlying_type == TypeManager.uint64_type){
4414                                         if (!(v is Expression)){
4415                                                 ulong val = (ulong) v;
4416
4417                                                 for (int j = 0; j < factor; ++j) {
4418                                                         data [idx + j] = (byte) (val & 0xFF);
4419                                                         val = (val >> 8);
4420                                                 }
4421                                         }
4422                                 } else if (underlying_type == TypeManager.float_type) {
4423                                         if (!(v is Expression)){
4424                                                 element = BitConverter.GetBytes ((float) v);
4425                                                         
4426                                                 for (int j = 0; j < factor; ++j)
4427                                                         data [idx + j] = element [j];
4428                                         }
4429                                 } else if (underlying_type == TypeManager.double_type) {
4430                                         if (!(v is Expression)){
4431                                                 element = BitConverter.GetBytes ((double) v);
4432
4433                                                 for (int j = 0; j < factor; ++j)
4434                                                         data [idx + j] = element [j];
4435                                         }
4436                                 } else if (underlying_type == TypeManager.char_type){
4437                                         if (!(v is Expression)){
4438                                                 int val = (int) ((char) v);
4439                                                 
4440                                                 data [idx] = (byte) (val & 0xff);
4441                                                 data [idx+1] = (byte) (val >> 8);
4442                                         }
4443                                 } else if (underlying_type == TypeManager.short_type){
4444                                         if (!(v is Expression)){
4445                                                 int val = (int) ((short) v);
4446                                         
4447                                                 data [idx] = (byte) (val & 0xff);
4448                                                 data [idx+1] = (byte) (val >> 8);
4449                                         }
4450                                 } else if (underlying_type == TypeManager.ushort_type){
4451                                         if (!(v is Expression)){
4452                                                 int val = (int) ((ushort) v);
4453                                         
4454                                                 data [idx] = (byte) (val & 0xff);
4455                                                 data [idx+1] = (byte) (val >> 8);
4456                                         }
4457                                 } else if (underlying_type == TypeManager.int32_type) {
4458                                         if (!(v is Expression)){
4459                                                 int val = (int) v;
4460                                         
4461                                                 data [idx]   = (byte) (val & 0xff);
4462                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4463                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4464                                                 data [idx+3] = (byte) (val >> 24);
4465                                         }
4466                                 } else if (underlying_type == TypeManager.uint32_type) {
4467                                         if (!(v is Expression)){
4468                                                 uint val = (uint) v;
4469                                         
4470                                                 data [idx]   = (byte) (val & 0xff);
4471                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4472                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4473                                                 data [idx+3] = (byte) (val >> 24);
4474                                         }
4475                                 } else if (underlying_type == TypeManager.sbyte_type) {
4476                                         if (!(v is Expression)){
4477                                                 sbyte val = (sbyte) v;
4478                                                 data [idx] = (byte) val;
4479                                         }
4480                                 } else if (underlying_type == TypeManager.byte_type) {
4481                                         if (!(v is Expression)){
4482                                                 byte val = (byte) v;
4483                                                 data [idx] = (byte) val;
4484                                         }
4485                                 } else
4486                                         throw new Exception ("Unrecognized type in MakeByteBlob");
4487
4488                                 idx += factor;
4489                         }
4490
4491                         return data;
4492                 }
4493
4494                 //
4495                 // Emits the initializers for the array
4496                 //
4497                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
4498                 {
4499                         //
4500                         // First, the static data
4501                         //
4502                         FieldBuilder fb;
4503                         ILGenerator ig = ec.ig;
4504                         
4505                         byte [] data = MakeByteBlob (ArrayData, underlying_type, loc);
4506                         
4507                         if (data != null) {
4508                                 fb = RootContext.MakeStaticData (data);
4509
4510                                 if (is_expression)
4511                                         ig.Emit (OpCodes.Dup);
4512                                 ig.Emit (OpCodes.Ldtoken, fb);
4513                                 ig.Emit (OpCodes.Call,
4514                                          TypeManager.void_initializearray_array_fieldhandle);
4515                         }
4516                 }
4517                 
4518                 //
4519                 // Emits pieces of the array that can not be computed at compile
4520                 // time (variables and string locations).
4521                 //
4522                 // This always expect the top value on the stack to be the array
4523                 //
4524                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
4525                 {
4526                         ILGenerator ig = ec.ig;
4527                         int dims = Bounds.Count;
4528                         int [] current_pos = new int [dims];
4529                         int top = ArrayData.Count;
4530                         LocalBuilder temp = ig.DeclareLocal (type);
4531
4532                         ig.Emit (OpCodes.Stloc, temp);
4533
4534                         MethodInfo set = null;
4535
4536                         if (dims != 1){
4537                                 Type [] args;
4538                                 ModuleBuilder mb = null;
4539                                 mb = CodeGen.ModuleBuilder;
4540                                 args = new Type [dims + 1];
4541
4542                                 int j;
4543                                 for (j = 0; j < dims; j++)
4544                                         args [j] = TypeManager.int32_type;
4545
4546                                 args [j] = array_element_type;
4547                                 
4548                                 set = mb.GetArrayMethod (
4549                                         type, "Set",
4550                                         CallingConventions.HasThis | CallingConventions.Standard,
4551                                         TypeManager.void_type, args);
4552                         }
4553                         
4554                         for (int i = 0; i < top; i++){
4555
4556                                 Expression e = null;
4557
4558                                 if (ArrayData [i] is Expression)
4559                                         e = (Expression) ArrayData [i];
4560
4561                                 if (e != null) {
4562                                         //
4563                                         // Basically we do this for string literals and
4564                                         // other non-literal expressions
4565                                         //
4566                                         if (e is StringConstant || !(e is Constant) ||
4567                                             num_automatic_initializers <= 2) {
4568                                                 Type etype = e.Type;
4569                                                 
4570                                                 ig.Emit (OpCodes.Ldloc, temp);
4571
4572                                                 for (int idx = dims; idx > 0; ) {
4573                                                         idx--;
4574                                                         IntConstant.EmitInt (ig, current_pos [idx]);
4575                                                 }
4576
4577                                                 //
4578                                                 // If we are dealing with a struct, get the
4579                                                 // address of it, so we can store it.
4580                                                 //
4581                                                 if (etype.IsSubclassOf (TypeManager.value_type) &&
4582                                                     !TypeManager.IsBuiltinType (etype)){
4583                                                         if (e is New){
4584                                                                 New n = (New) e;
4585
4586                                                                 //
4587                                                                 // Let new know that we are providing
4588                                                                 // the address where to store the results
4589                                                                 //
4590                                                                 n.DisableTemporaryValueType ();
4591                                                         }
4592                                                                              
4593                                                         ig.Emit (OpCodes.Ldelema, etype);
4594                                                 }
4595                                                     
4596                                                 e.Emit (ec);
4597                                                 
4598                                                 if (dims == 1)
4599                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
4600                                                 else 
4601                                                         ig.Emit (OpCodes.Call, set);
4602                                         }
4603                                 }
4604                                 
4605                                 //
4606                                 // Advance counter
4607                                 //
4608                                 for (int j = 0; j < dims; j++){
4609                                         current_pos [j]++;
4610                                         if (current_pos [j] < (int) Bounds [j])
4611                                                 break;
4612                                         current_pos [j] = 0;
4613                                 }
4614                         }
4615
4616                         if (is_expression)
4617                                 ig.Emit (OpCodes.Ldloc, temp);
4618                 }
4619
4620                 void EmitArrayArguments (EmitContext ec)
4621                 {
4622                         foreach (Argument a in Arguments)
4623                                 a.Emit (ec);
4624                 }
4625                 
4626                 void DoEmit (EmitContext ec, bool is_statement)
4627                 {
4628                         ILGenerator ig = ec.ig;
4629                         
4630                         EmitArrayArguments (ec);
4631                         if (IsOneDimensional)
4632                                 ig.Emit (OpCodes.Newarr, array_element_type);
4633                         else {
4634                                 if (IsBuiltinType) 
4635                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4636                                 else 
4637                                         ig.Emit (OpCodes.Newobj, (MethodInfo) method);
4638                         }
4639                         
4640                         if (Initializers != null){
4641                                 //
4642                                 // FIXME: Set this variable correctly.
4643                                 // 
4644                                 bool dynamic_initializers = true;
4645
4646                                 if (underlying_type != TypeManager.string_type &&
4647                                     underlying_type != TypeManager.object_type) {
4648                                         if (num_automatic_initializers > 2)
4649                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
4650                                 }
4651                                 
4652                                 if (dynamic_initializers)
4653                                         EmitDynamicInitializers (ec, !is_statement);
4654                         }
4655                 }
4656                 
4657                 public override void Emit (EmitContext ec)
4658                 {
4659                         DoEmit (ec, false);
4660                 }
4661
4662                 public override void EmitStatement (EmitContext ec)
4663                 {
4664                         DoEmit (ec, true);
4665                 }
4666                 
4667         }
4668         
4669         /// <summary>
4670         ///   Represents the `this' construct
4671         /// </summary>
4672         public class This : Expression, IAssignMethod, IMemoryLocation {
4673                 Location loc;
4674                 
4675                 public This (Location loc)
4676                 {
4677                         this.loc = loc;
4678                 }
4679
4680                 public override Expression DoResolve (EmitContext ec)
4681                 {
4682                         eclass = ExprClass.Variable;
4683                         type = ec.ContainerType;
4684
4685                         if (ec.IsStatic){
4686                                 Report.Error (26, loc,
4687                                               "Keyword this not valid in static code");
4688                                 return null;
4689                         }
4690                         
4691                         return this;
4692                 }
4693
4694                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4695                 {
4696                         DoResolve (ec);
4697                         
4698                         if (ec.TypeContainer is Class){
4699                                 Report.Error (1604, loc, "Cannot assign to `this'");
4700                                 return null;
4701                         }
4702
4703                         return this;
4704                 }
4705
4706                 public override void Emit (EmitContext ec)
4707                 {
4708                         ec.ig.Emit (OpCodes.Ldarg_0);
4709                 }
4710
4711                 public void EmitAssign (EmitContext ec, Expression source)
4712                 {
4713                         source.Emit (ec);
4714                         ec.ig.Emit (OpCodes.Starg, 0);
4715                 }
4716
4717                 public void AddressOf (EmitContext ec, AddressOp mode)
4718                 {
4719                         ec.ig.Emit (OpCodes.Ldarg_0);
4720
4721                         // FIMXE
4722                         // FIGURE OUT WHY LDARG_S does not work
4723                         //
4724                         // consider: struct X { int val; int P { set { val = value; }}}
4725                         //
4726                         // Yes, this looks very bad. Look at `NOTAS' for
4727                         // an explanation.
4728                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4729                 }
4730         }
4731
4732         /// <summary>
4733         ///   Implements the typeof operator
4734         /// </summary>
4735         public class TypeOf : Expression {
4736                 public readonly string QueriedType;
4737                 Type typearg;
4738                 Location loc;
4739                 
4740                 public TypeOf (string queried_type, Location l)
4741                 {
4742                         QueriedType = queried_type;
4743                         loc = l;
4744                 }
4745
4746                 public override Expression DoResolve (EmitContext ec)
4747                 {
4748                         typearg = RootContext.LookupType (
4749                                 ec.DeclSpace, QueriedType, false, loc);
4750
4751                         if (typearg == null)
4752                                 return null;
4753
4754                         type = TypeManager.type_type;
4755                         eclass = ExprClass.Type;
4756                         return this;
4757                 }
4758
4759                 public override void Emit (EmitContext ec)
4760                 {
4761                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
4762                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4763                 }
4764
4765                 public Type TypeArg { 
4766                         get { return typearg; }
4767                 }
4768         }
4769
4770         /// <summary>
4771         ///   Implements the sizeof expression
4772         /// </summary>
4773         public class SizeOf : Expression {
4774                 public readonly string QueriedType;
4775                 Type type_queried;
4776                 Location loc;
4777                 
4778                 public SizeOf (string queried_type, Location l)
4779                 {
4780                         this.QueriedType = queried_type;
4781                         loc = l;
4782                 }
4783
4784                 public override Expression DoResolve (EmitContext ec)
4785                 {
4786                         type_queried = RootContext.LookupType (
4787                                 ec.DeclSpace, QueriedType, false, loc);
4788                         if (type_queried == null)
4789                                 return null;
4790
4791                         type = TypeManager.int32_type;
4792                         eclass = ExprClass.Value;
4793                         return this;
4794                 }
4795
4796                 public override void Emit (EmitContext ec)
4797                 {
4798                         int size = GetTypeSize (type_queried);
4799
4800                         if (size == 0)
4801                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
4802                         else
4803                                 IntConstant.EmitInt (ec.ig, size);
4804                 }
4805         }
4806
4807         /// <summary>
4808         ///   Implements the member access expression
4809         /// </summary>
4810         public class MemberAccess : Expression {
4811                 public readonly string Identifier;
4812                 Expression expr;
4813                 Expression member_lookup;
4814                 Location loc;
4815                 
4816                 public MemberAccess (Expression expr, string id, Location l)
4817                 {
4818                         this.expr = expr;
4819                         Identifier = id;
4820                         loc = l;
4821                 }
4822
4823                 public Expression Expr {
4824                         get {
4825                                 return expr;
4826                         }
4827                 }
4828
4829                 static void error176 (Location loc, string name)
4830                 {
4831                         Report.Error (176, loc, "Static member `" +
4832                                       name + "' cannot be accessed " +
4833                                       "with an instance reference, qualify with a " +
4834                                       "type name instead");
4835                 }
4836
4837                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
4838                 {
4839                         if (left_original == null)
4840                                 return false;
4841
4842                         if (!(left_original is SimpleName))
4843                                 return false;
4844
4845                         SimpleName sn = (SimpleName) left_original;
4846
4847                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
4848                         if (t != null)
4849                                 return true;
4850
4851                         return false;
4852                 }
4853                 
4854                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
4855                                                               Expression left, Location loc,
4856                                                               Expression left_original)
4857                 {
4858                         //
4859                         // Method Groups
4860                         //
4861                         if (member_lookup is MethodGroupExpr){
4862                                 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
4863
4864                                 //
4865                                 // Type.MethodGroup
4866                                 //
4867                                 if (left is TypeExpr){
4868                                         if (!mg.RemoveInstanceMethods ()){
4869                                                 SimpleName.Error120 (loc, mg.Methods [0].Name); 
4870                                                 return null;
4871                                         }
4872
4873                                         return member_lookup;
4874                                 }
4875
4876                                 //
4877                                 // Instance.MethodGroup
4878                                 //
4879                                 if (IdenticalNameAndTypeName (ec, left_original, loc)){
4880                                         if (mg.RemoveInstanceMethods ())
4881                                                 return member_lookup;
4882                                 }
4883                                 
4884                                 if (!mg.RemoveStaticMethods ()){
4885                                         error176 (loc, mg.Methods [0].Name);
4886                                         return null;
4887                                 } 
4888                                 
4889                                 mg.InstanceExpression = left;
4890                                 return member_lookup;
4891 #if ORIGINAL
4892                                 if (!mg.RemoveStaticMethods ()){
4893                                         if (IdenticalNameAndTypeName (ec, left_original, loc)){
4894                                                 if (!mg.RemoveInstanceMethods ()){
4895                                                         SimpleName.Error120 (loc, mg.Methods [0].Name);
4896                                                         return null;
4897                                                 }
4898                                                 return member_lookup;
4899                                         }
4900                                         
4901                                         error176 (loc, mg.Methods [0].Name);
4902                                         return null;
4903                                 }
4904                                 
4905                                 mg.InstanceExpression = left;
4906                                         
4907                                 return member_lookup;
4908 #endif
4909                         }
4910
4911                         if (member_lookup is FieldExpr){
4912                                 FieldExpr fe = (FieldExpr) member_lookup;
4913                                 FieldInfo fi = fe.FieldInfo;
4914                                 Type decl_type = fi.DeclaringType;
4915                                 
4916                                 if (fi is FieldBuilder) {
4917                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
4918                                         
4919                                         if (c != null) {
4920                                                 object o = c.LookupConstantValue (ec);
4921                                                 object real_value = ((Constant) c.Expr).GetValue ();
4922
4923                                                 return Constantify (real_value, fi.FieldType);
4924                                         }
4925                                 }
4926
4927                                 if (fi.IsLiteral) {
4928                                         Type t = fi.FieldType;
4929                                         
4930                                         object o;
4931
4932                                         if (fi is FieldBuilder)
4933                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
4934                                         else
4935                                                 o = fi.GetValue (fi);
4936                                         
4937                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
4938                                                 Expression enum_member = MemberLookup (
4939                                                         ec, decl_type, "value__", MemberTypes.Field,
4940                                                         AllBindingFlags, loc); 
4941
4942                                                 Enum en = TypeManager.LookupEnum (decl_type);
4943
4944                                                 Constant c;
4945                                                 if (en != null)
4946                                                         c = Constantify (o, en.UnderlyingType);
4947                                                 else 
4948                                                         c = Constantify (o, enum_member.Type);
4949                                                 
4950                                                 return new EnumConstant (c, decl_type);
4951                                         }
4952                                         
4953                                         Expression exp = Constantify (o, t);
4954
4955                                         if (!(left is TypeExpr)) {
4956                                                 error176 (loc, fe.FieldInfo.Name);
4957                                                 return null;
4958                                         }
4959                                         
4960                                         return exp;
4961                                 }
4962
4963                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
4964                                         UnsafeError (loc);
4965                                         return null;
4966                                 }
4967                                 
4968                                 if (left is TypeExpr){
4969                                         // and refers to a type name or an 
4970                                         if (!fe.FieldInfo.IsStatic){
4971                                                 error176 (loc, fe.FieldInfo.Name);
4972                                                 return null;
4973                                         }
4974                                         return member_lookup;
4975                                 } else {
4976                                         if (fe.FieldInfo.IsStatic){
4977                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
4978                                                         return member_lookup;
4979
4980                                                 error176 (loc, fe.FieldInfo.Name);
4981                                                 return null;
4982                                         }
4983                                         fe.InstanceExpression = left;
4984
4985                                         return fe;
4986                                 }
4987                         }
4988
4989                         if (member_lookup is PropertyExpr){
4990                                 PropertyExpr pe = (PropertyExpr) member_lookup;
4991
4992                                 if (left is TypeExpr){
4993                                         if (!pe.IsStatic){
4994                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
4995                                                 return null;
4996                                         }
4997                                         return pe;
4998                                 } else {
4999                                         if (pe.IsStatic){
5000                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5001                                                         return member_lookup;
5002                                                 error176 (loc, pe.PropertyInfo.Name);
5003                                                 return null;
5004                                         }
5005                                         pe.InstanceExpression = left;
5006                                         
5007                                         return pe;
5008                                 }
5009                         }
5010
5011                         if (member_lookup is EventExpr) {
5012
5013                                 EventExpr ee = (EventExpr) member_lookup;
5014                                 
5015                                 //
5016                                 // If the event is local to this class, we transform ourselves into
5017                                 // a FieldExpr
5018                                 //
5019
5020                                 Expression ml = MemberLookup (
5021                                         ec, ec.ContainerType,
5022                                         ee.EventInfo.Name, MemberTypes.Event, AllBindingFlags, loc);
5023
5024                                 if (ml != null) {
5025                                         MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
5026
5027                                         if (mi == null) {
5028                                                 //
5029                                                 // If this happens, then we have an event with its own
5030                                                 // accessors and private field etc so there's no need
5031                                                 // to transform ourselves : we should instead flag an error
5032                                                 //
5033                                                 Assign.error70 (ee.EventInfo, loc);
5034                                                 return null;
5035                                         }
5036
5037                                         ml = ExprClassFromMemberInfo (ec, mi, loc);
5038                                         
5039                                         if (ml == null) {
5040                                                 Report.Error (-200, loc, "Internal error!!");
5041                                                 return null;
5042                                         }
5043                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
5044                                 }
5045
5046                                 if (left is TypeExpr) {
5047                                         if (!ee.IsStatic) {
5048                                                 SimpleName.Error120 (loc, ee.EventInfo.Name);
5049                                                 return null;
5050                                         }
5051
5052                                         return ee;
5053
5054                                 } else {
5055                                         if (ee.IsStatic) {
5056                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5057                                                         return ee;
5058                                                     
5059                                                 error176 (loc, ee.EventInfo.Name);
5060                                                 return null;
5061                                         }
5062
5063                                         ee.InstanceExpression = left;
5064
5065                                         return ee;
5066                                 }
5067                         }
5068
5069                         if (member_lookup is TypeExpr){
5070                                 member_lookup.Resolve (ec);
5071                                 return member_lookup;
5072                         }
5073                         
5074                         Console.WriteLine ("Left is: " + left);
5075                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
5076                         Environment.Exit (0);
5077                         return null;
5078                 }
5079                 
5080                 public override Expression DoResolve (EmitContext ec)
5081                 {
5082                         //
5083                         // We are the sole users of ResolveWithSimpleName (ie, the only
5084                         // ones that can cope with it
5085                         //
5086                         Expression original = expr;
5087                         expr = expr.ResolveWithSimpleName (ec);
5088
5089                         if (expr == null)
5090                                 return null;
5091
5092                         if (expr is SimpleName){
5093                                 SimpleName child_expr = (SimpleName) expr;
5094                                 
5095                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
5096
5097                                 return expr.ResolveWithSimpleName (ec);
5098                         }
5099                                         
5100                         //
5101                         // TODO: I mailed Ravi about this, and apparently we can get rid
5102                         // of this and put it in the right place.
5103                         // 
5104                         // Handle enums here when they are in transit.
5105                         // Note that we cannot afford to hit MemberLookup in this case because
5106                         // it will fail to find any members at all
5107                         //
5108
5109                         Type expr_type = expr.Type;
5110                         if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
5111                                 
5112                                 Enum en = TypeManager.LookupEnum (expr_type);
5113                                 
5114                                 if (en != null) {
5115                                         object value = en.LookupEnumValue (ec, Identifier, loc);
5116
5117                                         if (value != null){
5118                                                 Constant c = Constantify (value, en.UnderlyingType);
5119                                                 return new EnumConstant (c, expr_type);
5120                                         }
5121                                 }
5122                         }
5123
5124                         if (expr_type.IsPointer){
5125                                 Report.Error (23, loc,
5126                                               "The `.' operator can not be applied to pointer operands (" +
5127                                               TypeManager.CSharpName (expr_type) + ")");
5128                                 return null;
5129                         }
5130                         
5131                         member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
5132
5133                         if (member_lookup == null){
5134                                 Report.Error (117, loc, "`" + expr_type + "' does not contain a " +
5135                                               "definition for `" + Identifier + "'");
5136                                               
5137                                 return null;
5138                         }
5139
5140                         return ResolveMemberAccess (ec, member_lookup, expr, loc, original);
5141                 }
5142
5143                 public override void Emit (EmitContext ec)
5144                 {
5145                         throw new Exception ("Should not happen");
5146                 }
5147         }
5148
5149         /// <summary>
5150         ///   Implements checked expressions
5151         /// </summary>
5152         public class CheckedExpr : Expression {
5153
5154                 public Expression Expr;
5155
5156                 public CheckedExpr (Expression e)
5157                 {
5158                         Expr = e;
5159                 }
5160
5161                 public override Expression DoResolve (EmitContext ec)
5162                 {
5163                         bool last_const_check = ec.ConstantCheckState;
5164
5165                         ec.ConstantCheckState = true;
5166                         Expr = Expr.Resolve (ec);
5167                         ec.ConstantCheckState = last_const_check;
5168                         
5169                         if (Expr == null)
5170                                 return null;
5171
5172                         eclass = Expr.eclass;
5173                         type = Expr.Type;
5174                         return this;
5175                 }
5176
5177                 public override void Emit (EmitContext ec)
5178                 {
5179                         bool last_check = ec.CheckState;
5180                         bool last_const_check = ec.ConstantCheckState;
5181                         
5182                         ec.CheckState = true;
5183                         ec.ConstantCheckState = true;
5184                         Expr.Emit (ec);
5185                         ec.CheckState = last_check;
5186                         ec.ConstantCheckState = last_const_check;
5187                 }
5188                 
5189         }
5190
5191         /// <summary>
5192         ///   Implements the unchecked expression
5193         /// </summary>
5194         public class UnCheckedExpr : Expression {
5195
5196                 public Expression Expr;
5197
5198                 public UnCheckedExpr (Expression e)
5199                 {
5200                         Expr = e;
5201                 }
5202
5203                 public override Expression DoResolve (EmitContext ec)
5204                 {
5205                         bool last_const_check = ec.ConstantCheckState;
5206
5207                         ec.ConstantCheckState = false;
5208                         Expr = Expr.Resolve (ec);
5209                         ec.ConstantCheckState = last_const_check;
5210
5211                         if (Expr == null)
5212                                 return null;
5213
5214                         eclass = Expr.eclass;
5215                         type = Expr.Type;
5216                         return this;
5217                 }
5218
5219                 public override void Emit (EmitContext ec)
5220                 {
5221                         bool last_check = ec.CheckState;
5222                         bool last_const_check = ec.ConstantCheckState;
5223                         
5224                         ec.CheckState = false;
5225                         ec.ConstantCheckState = false;
5226                         Expr.Emit (ec);
5227                         ec.CheckState = last_check;
5228                         ec.ConstantCheckState = last_const_check;
5229                 }
5230                 
5231         }
5232
5233         /// <summary>
5234         ///   An Element Access expression.
5235         ///
5236         ///   During semantic analysis these are transformed into 
5237         ///   IndexerAccess or ArrayAccess 
5238         /// </summary>
5239         public class ElementAccess : Expression {
5240                 public ArrayList  Arguments;
5241                 public Expression Expr;
5242                 public Location   loc;
5243                 
5244                 public ElementAccess (Expression e, ArrayList e_list, Location l)
5245                 {
5246                         Expr = e;
5247
5248                         loc  = l;
5249                         
5250                         if (e_list == null)
5251                                 return;
5252                         
5253                         Arguments = new ArrayList ();
5254                         foreach (Expression tmp in e_list)
5255                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
5256                         
5257                 }
5258
5259                 bool CommonResolve (EmitContext ec)
5260                 {
5261                         Expr = Expr.Resolve (ec);
5262
5263                         if (Expr == null) 
5264                                 return false;
5265
5266                         if (Arguments == null)
5267                                 return false;
5268
5269                         for (int i = Arguments.Count; i > 0;){
5270                                 --i;
5271                                 Argument a = (Argument) Arguments [i];
5272                                 
5273                                 if (!a.Resolve (ec, loc))
5274                                         return false;
5275                         }
5276
5277                         return true;
5278                 }
5279
5280                 Expression MakePointerAccess ()
5281                 {
5282                         Type t = Expr.Type;
5283
5284                         if (t == TypeManager.void_ptr_type){
5285                                 Report.Error (
5286                                         242, loc,
5287                                         "The array index operation is not valid for void pointers");
5288                                 return null;
5289                         }
5290                         if (Arguments.Count != 1){
5291                                 Report.Error (
5292                                         196, loc,
5293                                         "A pointer must be indexed by a single value");
5294                                 return null;
5295                         }
5296                         Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t);
5297                         return new Indirection (p);
5298                 }
5299                 
5300                 public override Expression DoResolve (EmitContext ec)
5301                 {
5302                         if (!CommonResolve (ec))
5303                                 return null;
5304
5305                         //
5306                         // We perform some simple tests, and then to "split" the emit and store
5307                         // code we create an instance of a different class, and return that.
5308                         //
5309                         // I am experimenting with this pattern.
5310                         //
5311                         Type t = Expr.Type;
5312
5313                         if (t.IsSubclassOf (TypeManager.array_type))
5314                                 return (new ArrayAccess (this)).Resolve (ec);
5315                         else if (t.IsPointer)
5316                                 return MakePointerAccess ();
5317                         else
5318                                 return (new IndexerAccess (this)).Resolve (ec);
5319                 }
5320
5321                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5322                 {
5323                         if (!CommonResolve (ec))
5324                                 return null;
5325
5326                         Type t = Expr.Type;
5327                         if (t.IsSubclassOf (TypeManager.array_type))
5328                                 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
5329                         else if (t.IsPointer)
5330                                 return MakePointerAccess ();
5331                         else
5332                                 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
5333                 }
5334                 
5335                 public override void Emit (EmitContext ec)
5336                 {
5337                         throw new Exception ("Should never be reached");
5338                 }
5339         }
5340
5341         /// <summary>
5342         ///   Implements array access 
5343         /// </summary>
5344         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
5345                 //
5346                 // Points to our "data" repository
5347                 //
5348                 ElementAccess ea;
5349                 
5350                 public ArrayAccess (ElementAccess ea_data)
5351                 {
5352                         ea = ea_data;
5353                         eclass = ExprClass.Variable;
5354                 }
5355
5356                 public override Expression DoResolve (EmitContext ec)
5357                 {
5358                         ExprClass eclass = ea.Expr.eclass;
5359                         
5360                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.Value)) {
5361                                 report118 (ea.loc, ea.Expr, "variable or value");
5362                                 return null;
5363                         }
5364
5365                         Type t = ea.Expr.Type;
5366                         if (t.GetArrayRank () != ea.Arguments.Count){
5367                                 Report.Error (22, ea.loc,
5368                                               "Incorrect number of indexes for array " +
5369                                               " expected: " + t.GetArrayRank () + " got: " +
5370                                               ea.Arguments.Count);
5371                                 return null;
5372                         }
5373                         type = t.GetElementType ();
5374                         if (type.IsPointer && !ec.InUnsafe){
5375                                 UnsafeError (ea.loc);
5376                                 return null;
5377                         }
5378                         
5379                         eclass = ExprClass.Variable;
5380
5381                         return this;
5382                 }
5383
5384                 /// <summary>
5385                 ///    Emits the right opcode to load an object of Type `t'
5386                 ///    from an array of T
5387                 /// </summary>
5388                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
5389                 {
5390                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
5391                                 ig.Emit (OpCodes.Ldelem_I1);
5392                         else if (type == TypeManager.sbyte_type)
5393                                 ig.Emit (OpCodes.Ldelem_U1);
5394                         else if (type == TypeManager.short_type)
5395                                 ig.Emit (OpCodes.Ldelem_I2);
5396                         else if (type == TypeManager.ushort_type)
5397                                 ig.Emit (OpCodes.Ldelem_U2);
5398                         else if (type == TypeManager.int32_type)
5399                                 ig.Emit (OpCodes.Ldelem_I4);
5400                         else if (type == TypeManager.uint32_type)
5401                                 ig.Emit (OpCodes.Ldelem_U4);
5402                         else if (type == TypeManager.uint64_type)
5403                                 ig.Emit (OpCodes.Ldelem_I8);
5404                         else if (type == TypeManager.int64_type)
5405                                 ig.Emit (OpCodes.Ldelem_I8);
5406                         else if (type == TypeManager.float_type)
5407                                 ig.Emit (OpCodes.Ldelem_R4);
5408                         else if (type == TypeManager.double_type)
5409                                 ig.Emit (OpCodes.Ldelem_R8);
5410                         else if (type == TypeManager.intptr_type)
5411                                 ig.Emit (OpCodes.Ldelem_I);
5412                         else if (type.IsValueType){
5413                                 ig.Emit (OpCodes.Ldelema, type);
5414                                 ig.Emit (OpCodes.Ldobj, type);
5415                         } else 
5416                                 ig.Emit (OpCodes.Ldelem_Ref);
5417                 }
5418
5419                 /// <summary>
5420                 ///    Emits the right opcode to store an object of Type `t'
5421                 ///    from an array of T.  
5422                 /// </summary>
5423                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
5424                 {
5425                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
5426                             t == TypeManager.bool_type)
5427                                 ig.Emit (OpCodes.Stelem_I1);
5428                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
5429                                 ig.Emit (OpCodes.Stelem_I2);
5430                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
5431                                 ig.Emit (OpCodes.Stelem_I4);
5432                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
5433                                 ig.Emit (OpCodes.Stelem_I8);
5434                         else if (t == TypeManager.float_type)
5435                                 ig.Emit (OpCodes.Stelem_R4);
5436                         else if (t == TypeManager.double_type)
5437                                 ig.Emit (OpCodes.Stelem_R8);
5438                         else if (t == TypeManager.intptr_type)
5439                                 ig.Emit (OpCodes.Stelem_I);
5440                         else if (t.IsValueType)
5441                                 ig.Emit (OpCodes.Stobj, t);
5442                         else
5443                                 ig.Emit (OpCodes.Stelem_Ref);
5444                 }
5445
5446                 MethodInfo FetchGetMethod ()
5447                 {
5448                         ModuleBuilder mb = CodeGen.ModuleBuilder;
5449                         int arg_count = ea.Arguments.Count;
5450                         Type [] args = new Type [arg_count];
5451                         MethodInfo get;
5452                         
5453                         for (int i = 0; i < arg_count; i++){
5454                                 //args [i++] = a.Type;
5455                                 args [i] = TypeManager.int32_type;
5456                         }
5457                         
5458                         get = mb.GetArrayMethod (
5459                                 ea.Expr.Type, "Get",
5460                                 CallingConventions.HasThis |
5461                                 CallingConventions.Standard,
5462                                 type, args);
5463                         return get;
5464                 }
5465                                 
5466
5467                 MethodInfo FetchAddressMethod ()
5468                 {
5469                         ModuleBuilder mb = CodeGen.ModuleBuilder;
5470                         int arg_count = ea.Arguments.Count;
5471                         Type [] args = new Type [arg_count];
5472                         MethodInfo address;
5473                         string ptr_type_name;
5474                         Type ret_type;
5475                         
5476                         ptr_type_name = type.FullName + "&";
5477                         ret_type = Type.GetType (ptr_type_name);
5478                         
5479                         //
5480                         // It is a type defined by the source code we are compiling
5481                         //
5482                         if (ret_type == null){
5483                                 ret_type = mb.GetType (ptr_type_name);
5484                         }
5485
5486                         for (int i = 0; i < arg_count; i++){
5487                                 //args [i++] = a.Type;
5488                                 args [i] = TypeManager.int32_type;
5489                         }
5490                         
5491                         address = mb.GetArrayMethod (
5492                                 ea.Expr.Type, "Address",
5493                                 CallingConventions.HasThis |
5494                                 CallingConventions.Standard,
5495                                 ret_type, args);
5496
5497                         return address;
5498                 }
5499                 
5500                 public override void Emit (EmitContext ec)
5501                 {
5502                         int rank = ea.Expr.Type.GetArrayRank ();
5503                         ILGenerator ig = ec.ig;
5504
5505                         ea.Expr.Emit (ec);
5506
5507                         foreach (Argument a in ea.Arguments)
5508                                 a.Expr.Emit (ec);
5509
5510                         if (rank == 1)
5511                                 EmitLoadOpcode (ig, type);
5512                         else {
5513                                 MethodInfo method;
5514                                 
5515                                 method = FetchGetMethod ();
5516                                 ig.Emit (OpCodes.Call, method);
5517                         }
5518                 }
5519
5520                 public void EmitAssign (EmitContext ec, Expression source)
5521                 {
5522                         int rank = ea.Expr.Type.GetArrayRank ();
5523                         ILGenerator ig = ec.ig;
5524
5525                         ea.Expr.Emit (ec);
5526
5527                         foreach (Argument a in ea.Arguments)
5528                                 a.Expr.Emit (ec);
5529
5530                         Type t = source.Type;
5531
5532                         //
5533                         // The stobj opcode used by value types will need
5534                         // an address on the stack, not really an array/array
5535                         // pair
5536                         //
5537                         if (rank == 1){
5538                                 if (t.IsValueType && !TypeManager.IsBuiltinType (t))
5539                                         ig.Emit (OpCodes.Ldelema, t);
5540                         }
5541                         
5542                         source.Emit (ec);
5543
5544                         if (rank == 1)
5545                                 EmitStoreOpcode (ig, t);
5546                         else {
5547                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5548                                 int arg_count = ea.Arguments.Count;
5549                                 Type [] args = new Type [arg_count + 1];
5550                                 MethodInfo set;
5551                                 
5552                                 for (int i = 0; i < arg_count; i++){
5553                                         //args [i++] = a.Type;
5554                                         args [i] = TypeManager.int32_type;
5555                                 }
5556
5557                                 args [arg_count] = type;
5558                                 
5559                                 set = mb.GetArrayMethod (
5560                                         ea.Expr.Type, "Set",
5561                                         CallingConventions.HasThis |
5562                                         CallingConventions.Standard,
5563                                         TypeManager.void_type, args);
5564                                 
5565                                 ig.Emit (OpCodes.Call, set);
5566                         }
5567                 }
5568
5569                 public void AddressOf (EmitContext ec, AddressOp mode)
5570                 {
5571                         int rank = ea.Expr.Type.GetArrayRank ();
5572                         ILGenerator ig = ec.ig;
5573                         
5574                         ea.Expr.Emit (ec);
5575
5576                         foreach (Argument a in ea.Arguments)
5577                                 a.Expr.Emit (ec);
5578
5579                         if (rank == 1){
5580                                 ig.Emit (OpCodes.Ldelema, type);
5581                         } else {
5582                                 MethodInfo address = FetchAddressMethod ();
5583                                 ig.Emit (OpCodes.Call, address);
5584                         }
5585                 }
5586         }
5587
5588         
5589         class Indexers {
5590                 public ArrayList getters, setters;
5591                 static Hashtable map;
5592
5593                 static Indexers ()
5594                 {
5595                         map = new Hashtable ();
5596                 }
5597
5598                 Indexers (MemberInfo [] mi)
5599                 {
5600                         foreach (PropertyInfo property in mi){
5601                                 MethodInfo get, set;
5602                                 
5603                                 get = property.GetGetMethod (true);
5604                                 if (get != null){
5605                                         if (getters == null)
5606                                                 getters = new ArrayList ();
5607
5608                                         getters.Add (get);
5609                                 }
5610                                 
5611                                 set = property.GetSetMethod (true);
5612                                 if (set != null){
5613                                         if (setters == null)
5614                                                 setters = new ArrayList ();
5615                                         setters.Add (set);
5616                                 }
5617                         }
5618                 }
5619                 
5620                 static public Indexers GetIndexersForType (Type t, Location loc) 
5621                 {
5622                         Indexers ix = (Indexers) map [t];
5623                         string p_name = TypeManager.IndexerPropertyName (t);
5624                         
5625                         if (ix != null)
5626                                 return ix;
5627
5628                         MemberInfo [] mi = TypeManager.FindMembers (
5629                                 t, MemberTypes.Property,
5630                                 BindingFlags.Public | BindingFlags.Instance,
5631                                 Type.FilterName, p_name);
5632
5633                         if (mi == null || mi.Length == 0){
5634                                 Report.Error (21, loc,
5635                                               "Type `" + TypeManager.CSharpName (t) + "' does not have " +
5636                                               "any indexers defined");
5637                                 return null;
5638                         }
5639                         
5640                         ix = new Indexers (mi);
5641                         map [t] = ix;
5642
5643                         return ix;
5644                 }
5645         }
5646
5647         /// <summary>
5648         ///   Expressions that represent an indexer call.
5649         /// </summary>
5650         public class IndexerAccess : Expression, IAssignMethod {
5651                 //
5652                 // Points to our "data" repository
5653                 //
5654                 ElementAccess ea;
5655                 MethodInfo get, set;
5656                 Indexers ilist;
5657                 ArrayList set_arguments;
5658                 
5659                 public IndexerAccess (ElementAccess ea_data)
5660                 {
5661                         ea = ea_data;
5662                         eclass = ExprClass.Value;
5663                 }
5664
5665                 public override Expression DoResolve (EmitContext ec)
5666                 {
5667                         Type indexer_type = ea.Expr.Type;
5668                         
5669                         //
5670                         // Step 1: Query for all `Item' *properties*.  Notice
5671                         // that the actual methods are pointed from here.
5672                         //
5673                         // This is a group of properties, piles of them.  
5674
5675                         if (ilist == null)
5676                                 ilist = Indexers.GetIndexersForType (
5677                                         indexer_type, ea.loc);
5678
5679
5680                         //
5681                         // Step 2: find the proper match
5682                         //
5683                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0){
5684                                 Location loc = ea.loc;
5685                                 
5686                                 get = (MethodInfo) Invocation.OverloadResolve (
5687                                         ec, new MethodGroupExpr (ilist.getters, loc), ea.Arguments, loc);
5688                         }
5689
5690                         if (get == null){
5691                                 Report.Error (154, ea.loc,
5692                                               "indexer can not be used in this context, because " +
5693                                               "it lacks a `get' accessor");
5694                                 return null;
5695                         }
5696
5697                         type = get.ReturnType;
5698                         if (type.IsPointer && !ec.InUnsafe){
5699                                 UnsafeError (ea.loc);
5700                                 return null;
5701                         }
5702                         
5703                         eclass = ExprClass.IndexerAccess;
5704                         return this;
5705                 }
5706
5707                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5708                 {
5709                         Type indexer_type = ea.Expr.Type;
5710                         Type right_type = right_side.Type;
5711
5712                         if (ilist == null)
5713                                 ilist = Indexers.GetIndexersForType (
5714                                         indexer_type, ea.loc);
5715
5716                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
5717                                 Location loc = ea.loc;
5718                                 
5719                                 set_arguments = (ArrayList) ea.Arguments.Clone ();
5720                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
5721
5722                                 set = (MethodInfo) Invocation.OverloadResolve (
5723                                         ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
5724                         }
5725                         
5726                         if (set == null){
5727                                 Report.Error (200, ea.loc,
5728                                               "indexer X.this [" + TypeManager.CSharpName (right_type) +
5729                                               "] lacks a `set' accessor");
5730                                         return null;
5731                         }
5732
5733                         type = TypeManager.void_type;
5734                         eclass = ExprClass.IndexerAccess;
5735                         return this;
5736                 }
5737                 
5738                 public override void Emit (EmitContext ec)
5739                 {
5740                         Invocation.EmitCall (ec, false, false, ea.Expr, get, ea.Arguments);
5741                 }
5742
5743                 //
5744                 // source is ignored, because we already have a copy of it from the
5745                 // LValue resolution and we have already constructed a pre-cached
5746                 // version of the arguments (ea.set_arguments);
5747                 //
5748                 public void EmitAssign (EmitContext ec, Expression source)
5749                 {
5750                         Invocation.EmitCall (ec, false, false, ea.Expr, set, set_arguments);
5751                 }
5752         }
5753
5754         /// <summary>
5755         ///   The base operator for method names
5756         /// </summary>
5757         public class BaseAccess : Expression {
5758                 string member;
5759                 Location loc;
5760                 
5761                 public BaseAccess (string member, Location l)
5762                 {
5763                         this.member = member;
5764                         loc = l;
5765                 }
5766
5767                 public override Expression DoResolve (EmitContext ec)
5768                 {
5769                         Expression member_lookup;
5770                         Type current_type = ec.ContainerType;
5771                         Type base_type = current_type.BaseType;
5772                         Expression e;
5773
5774                         if (ec.IsStatic){
5775                                 Report.Error (1511, loc,
5776                                               "Keyword base is not allowed in static method");
5777                                 return null;
5778                         }
5779                         
5780                         member_lookup = MemberLookup (ec, base_type, member, loc);
5781                         if (member_lookup == null)
5782                                 return null;
5783
5784                         Expression left;
5785                         
5786                         if (ec.IsStatic)
5787                                 left = new TypeExpr (base_type);
5788                         else
5789                                 left = ec.This;
5790                         
5791                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
5792                         if (e is PropertyExpr){
5793                                 PropertyExpr pe = (PropertyExpr) e;
5794
5795                                 pe.IsBase = true;
5796                         }
5797
5798                         return e;
5799                 }
5800
5801                 public override void Emit (EmitContext ec)
5802                 {
5803                         throw new Exception ("Should never be called"); 
5804                 }
5805         }
5806
5807         /// <summary>
5808         ///   The base indexer operator
5809         /// </summary>
5810         public class BaseIndexerAccess : Expression {
5811                 ArrayList Arguments;
5812                 Location loc;
5813                 
5814                 public BaseIndexerAccess (ArrayList args, Location l)
5815                 {
5816                         Arguments = args;
5817                         loc = l;
5818                 }
5819
5820                 public override Expression DoResolve (EmitContext ec)
5821                 {
5822                         Type current_type = ec.ContainerType;
5823                         Type base_type = current_type.BaseType;
5824                         Expression member_lookup;
5825
5826                         if (ec.IsStatic){
5827                                 Report.Error (1511, loc,
5828                                               "Keyword base is not allowed in static method");
5829                                 return null;
5830                         }
5831                         
5832                         member_lookup = MemberLookup (ec, base_type, "get_Item", MemberTypes.Method, AllBindingFlags, loc);
5833                         if (member_lookup == null)
5834                                 return null;
5835
5836                         return MemberAccess.ResolveMemberAccess (ec, member_lookup, ec.This, loc, null);
5837                 }
5838
5839                 public override void Emit (EmitContext ec)
5840                 {
5841                         throw new Exception ("Should never be called");
5842                 }
5843         }
5844         
5845         /// <summary>
5846         ///   This class exists solely to pass the Type around and to be a dummy
5847         ///   that can be passed to the conversion functions (this is used by
5848         ///   foreach implementation to typecast the object return value from
5849         ///   get_Current into the proper type.  All code has been generated and
5850         ///   we only care about the side effect conversions to be performed
5851         ///
5852         ///   This is also now used as a placeholder where a no-action expression
5853         ///   is needed (the `New' class).
5854         /// </summary>
5855         public class EmptyExpression : Expression {
5856                 public EmptyExpression ()
5857                 {
5858                         type = TypeManager.object_type;
5859                         eclass = ExprClass.Value;
5860                 }
5861
5862                 public EmptyExpression (Type t)
5863                 {
5864                         type = t;
5865                         eclass = ExprClass.Value;
5866                 }
5867                 
5868                 public override Expression DoResolve (EmitContext ec)
5869                 {
5870                         return this;
5871                 }
5872
5873                 public override void Emit (EmitContext ec)
5874                 {
5875                         // nothing, as we only exist to not do anything.
5876                 }
5877
5878                 //
5879                 // This is just because we might want to reuse this bad boy
5880                 // instead of creating gazillions of EmptyExpressions.
5881                 // (CanConvertImplicit uses it)
5882                 //
5883                 public void SetType (Type t)
5884                 {
5885                         type = t;
5886                 }
5887         }
5888
5889         public class UserCast : Expression {
5890                 MethodBase method;
5891                 Expression source;
5892                 
5893                 public UserCast (MethodInfo method, Expression source)
5894                 {
5895                         this.method = method;
5896                         this.source = source;
5897                         type = method.ReturnType;
5898                         eclass = ExprClass.Value;
5899                 }
5900
5901                 public override Expression DoResolve (EmitContext ec)
5902                 {
5903                         //
5904                         // We are born fully resolved
5905                         //
5906                         return this;
5907                 }
5908
5909                 public override void Emit (EmitContext ec)
5910                 {
5911                         ILGenerator ig = ec.ig;
5912
5913                         source.Emit (ec);
5914                         
5915                         if (method is MethodInfo)
5916                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
5917                         else
5918                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5919
5920                 }
5921         }
5922
5923         // <summary>
5924         //   This class is used to "construct" the type during a typecast
5925         //   operation.  Since the Type.GetType class in .NET can parse
5926         //   the type specification, we just use this to construct the type
5927         //   one bit at a time.
5928         // </summary>
5929         public class ComposedCast : Expression {
5930                 Expression left;
5931                 string dim;
5932                 Location loc;
5933                 
5934                 public ComposedCast (Expression left, string dim, Location l)
5935                 {
5936                         this.left = left;
5937                         this.dim = dim;
5938                         loc = l;
5939                 }
5940
5941                 public override Expression DoResolve (EmitContext ec)
5942                 {
5943                         left = left.Resolve (ec);
5944                         if (left == null)
5945                                 return null;
5946
5947                         if (left.eclass != ExprClass.Type){
5948                                 report118 (loc, left, "type");
5949                                 return null;
5950                         }
5951                         
5952                         type = RootContext.LookupType (
5953                                 ec.DeclSpace, left.Type.FullName + dim, false, loc);
5954                         if (type == null)
5955                                 return null;
5956
5957                         if (!ec.InUnsafe && type.IsPointer){
5958                                 UnsafeError (loc);
5959                                 return null;
5960                         }
5961                         
5962                         eclass = ExprClass.Type;
5963                         return this;
5964                 }
5965
5966                 public override void Emit (EmitContext ec)
5967                 {
5968                         throw new Exception ("This should never be called");
5969                 }
5970         }
5971
5972         //
5973         // This class is used to represent the address of an array, used
5974         // only by the Fixed statement, this is like the C "&a [0]" construct.
5975         //
5976         public class ArrayPtr : Expression {
5977                 Expression array;
5978                 
5979                 public ArrayPtr (Expression array)
5980                 {
5981                         Type array_type = array.Type.GetElementType ();
5982
5983                         this.array = array;
5984                         
5985                         string array_ptr_type_name = array_type.FullName + "*";
5986                         
5987                         type = Type.GetType (array_ptr_type_name);
5988                         if (type == null){
5989                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5990                                 
5991                                 type = mb.GetType (array_ptr_type_name);
5992                         }
5993
5994                         eclass = ExprClass.Value;
5995                 }
5996
5997                 public override void Emit (EmitContext ec)
5998                 {
5999                         ILGenerator ig = ec.ig;
6000                         
6001                         array.Emit (ec);
6002                         IntLiteral.EmitInt (ig, 0);
6003                         ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
6004                 }
6005
6006                 public override Expression DoResolve (EmitContext ec)
6007                 {
6008                         //
6009                         // We are born fully resolved
6010                         //
6011                         return this;
6012                 }
6013         }
6014
6015         //
6016         // Used by the fixed statement
6017         //
6018         public class StringPtr : Expression {
6019                 LocalBuilder b;
6020                 
6021                 public StringPtr (LocalBuilder b)
6022                 {
6023                         this.b = b;
6024                         eclass = ExprClass.Value;
6025                         type = TypeManager.char_ptr_type;
6026                 }
6027
6028                 public override Expression DoResolve (EmitContext ec)
6029                 {
6030                         // This should never be invoked, we are born in fully
6031                         // initialized state.
6032
6033                         return this;
6034                 }
6035
6036                 public override void Emit (EmitContext ec)
6037                 {
6038                         ILGenerator ig = ec.ig;
6039
6040                         ig.Emit (OpCodes.Ldloc, b);
6041                         ig.Emit (OpCodes.Conv_I);
6042                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
6043                         ig.Emit (OpCodes.Add);
6044                 }
6045         }
6046         
6047         //
6048         // Implements the `stackalloc' keyword
6049         //
6050         public class StackAlloc : Expression {
6051                 Type otype;
6052                 string t;
6053                 Expression count;
6054                 Location loc;
6055                 
6056                 public StackAlloc (string type, Expression count, Location l)
6057                 {
6058                         t = type;
6059                         this.count = count;
6060                         loc = l;
6061                 }
6062
6063                 public override Expression DoResolve (EmitContext ec)
6064                 {
6065                         count = count.Resolve (ec);
6066                         if (count == null)
6067                                 return null;
6068                         
6069                         if (count.Type != TypeManager.int32_type){
6070                                 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
6071                                 if (count == null)
6072                                         return null;
6073                         }
6074
6075                         if (ec.InCatch || ec.InFinally){
6076                                 Report.Error (255, loc,
6077                                               "stackalloc can not be used in a catch or finally block");
6078                                 return null;
6079                         }
6080                         
6081                         otype = RootContext.LookupType (ec.DeclSpace, t, false, loc);
6082
6083                         if (otype == null)
6084                                 return null;
6085
6086                         if (!TypeManager.VerifyUnManaged (otype, loc))
6087                                 return null;
6088
6089                         string ptr_name = otype.FullName + "*";
6090                         type = Type.GetType (ptr_name);
6091                         if (type == null){
6092                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6093                                 
6094                                 type = mb.GetType (ptr_name);
6095                         }
6096                         eclass = ExprClass.Value;
6097
6098                         return this;
6099                 }
6100
6101                 public override void Emit (EmitContext ec)
6102                 {
6103                         int size = GetTypeSize (otype);
6104                         ILGenerator ig = ec.ig;
6105                                 
6106                         if (size == 0)
6107                                 ig.Emit (OpCodes.Sizeof, otype);
6108                         else
6109                                 IntConstant.EmitInt (ig, size);
6110                         count.Emit (ec);
6111                         ig.Emit (OpCodes.Mul);
6112                         ig.Emit (OpCodes.Localloc);
6113                 }
6114         }
6115 }