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