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