2002-06-21 Martin Baulig <martin@gnome.org>
[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 (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 = 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 string ProbeType;
928                 protected Expression expr;
929                 protected Type probe_type;
930                 protected Location loc;
931                 
932                 public Probe (Expression expr, string 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 = RootContext.LookupType (ec.DeclSpace, 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, string 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, string 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                 Expression CheckShiftArguments (EmitContext ec)
1800                 {
1801                         Expression e;
1802                         Type l = left.Type;
1803                         Type r = right.Type;
1804
1805                         e = ForceConversion (ec, right, TypeManager.int32_type);
1806                         if (e == null){
1807                                 Error_OperatorCannotBeApplied ();
1808                                 return null;
1809                         }
1810                         right = e;
1811
1812                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
1813                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
1814                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
1815                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
1816                                 left = e;
1817                                 type = e.Type;
1818
1819                                 return this;
1820                         }
1821                         Error_OperatorCannotBeApplied ();
1822                         return null;
1823                 }
1824
1825                 Expression ResolveOperator (EmitContext ec)
1826                 {
1827                         Type l = left.Type;
1828                         Type r = right.Type;
1829
1830                         bool overload_failed = false;
1831
1832                         //
1833                         // Step 1: Perform Operator Overload location
1834                         //
1835                         Expression left_expr, right_expr;
1836                                 
1837                         string op = oper_names [(int) oper];
1838                                 
1839                         MethodGroupExpr union;
1840                         left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
1841                         if (r != l){
1842                                 right_expr = MemberLookup (
1843                                         ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
1844                                 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
1845                         } else
1846                                 union = (MethodGroupExpr) left_expr;
1847                                 
1848                         if (union != null) {
1849                                 Arguments = new ArrayList ();
1850                                 Arguments.Add (new Argument (left, Argument.AType.Expression));
1851                                 Arguments.Add (new Argument (right, Argument.AType.Expression));
1852                                 
1853                                 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
1854                                 if (method != null) {
1855                                         MethodInfo mi = (MethodInfo) method;
1856                                         
1857                                         type = mi.ReturnType;
1858                                         return this;
1859                                 } else {
1860                                         overload_failed = true;
1861                                 }
1862                         }       
1863                         
1864                         //
1865                         // Step 2: Default operations on CLI native types.
1866                         //
1867
1868                         //
1869                         // Step 0: String concatenation (because overloading will get this wrong)
1870                         //
1871                         if (oper == Operator.Addition){
1872                                 //
1873                                 // If any of the arguments is a string, cast to string
1874                                 //
1875                                 
1876                                 if (l == TypeManager.string_type){
1877                                         
1878                                         if (r == TypeManager.void_type) {
1879                                                 Error_OperatorCannotBeApplied ();
1880                                                 return null;
1881                                         }
1882                                         
1883                                         if (r == TypeManager.string_type){
1884                                                 if (left is Constant && right is Constant){
1885                                                         StringConstant ls = (StringConstant) left;
1886                                                         StringConstant rs = (StringConstant) right;
1887                                                         
1888                                                         return new StringConstant (
1889                                                                 ls.Value + rs.Value);
1890                                                 }
1891                                                 
1892                                                 // string + string
1893                                                 method = TypeManager.string_concat_string_string;
1894                                         } else {
1895                                                 // string + object
1896                                                 method = TypeManager.string_concat_object_object;
1897                                                 right = ConvertImplicit (ec, right,
1898                                                                          TypeManager.object_type, loc);
1899                                         }
1900                                         type = TypeManager.string_type;
1901
1902                                         Arguments = new ArrayList ();
1903                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1904                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1905
1906                                         return this;
1907                                         
1908                                 } else if (r == TypeManager.string_type){
1909                                         // object + string
1910
1911                                         if (l == TypeManager.void_type) {
1912                                                 Error_OperatorCannotBeApplied ();
1913                                                 return null;
1914                                         }
1915                                         
1916                                         method = TypeManager.string_concat_object_object;
1917                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
1918                                         Arguments = new ArrayList ();
1919                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1920                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1921
1922                                         type = TypeManager.string_type;
1923
1924                                         return this;
1925                                 }
1926
1927                                 //
1928                                 // Transform a + ( - b) into a - b
1929                                 //
1930                                 if (right is Unary){
1931                                         Unary right_unary = (Unary) right;
1932
1933                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
1934                                                 oper = Operator.Subtraction;
1935                                                 right = right_unary.Expr;
1936                                                 r = right.Type;
1937                                         }
1938                                 }
1939                         }
1940
1941                         if (oper == Operator.Equality || oper == Operator.Inequality){
1942                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1943                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1944                                                 Error_OperatorCannotBeApplied ();
1945                                                 return null;
1946                                         }
1947                                         
1948                                         type = TypeManager.bool_type;
1949                                         return this;
1950                                 }
1951
1952                                 //
1953                                 // operator != (object a, object b)
1954                                 // operator == (object a, object b)
1955                                 //
1956                                 // For this to be used, both arguments have to be reference-types.
1957                                 // Read the rationale on the spec (14.9.6)
1958                                 //
1959                                 // Also, if at compile time we know that the classes do not inherit
1960                                 // one from the other, then we catch the error there.
1961                                 //
1962                                 if (!(l.IsValueType || r.IsValueType)){
1963                                         type = TypeManager.bool_type;
1964
1965                                         if (l == r)
1966                                                 return this;
1967                                         
1968                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
1969                                                 return this;
1970
1971                                         //
1972                                         // Also, a standard conversion must exist from either one
1973                                         //
1974                                         if (!(StandardConversionExists (left, r) ||
1975                                               StandardConversionExists (right, l))){
1976                                                 Error_OperatorCannotBeApplied ();
1977                                                 return null;
1978                                         }
1979                                         //
1980                                         // We are going to have to convert to an object to compare
1981                                         //
1982                                         if (l != TypeManager.object_type)
1983                                                 left = new EmptyCast (left, TypeManager.object_type);
1984                                         if (r != TypeManager.object_type)
1985                                                 right = new EmptyCast (right, TypeManager.object_type);
1986
1987                                         //
1988                                         // FIXME: CSC here catches errors cs254 and cs252
1989                                         //
1990                                         return this;
1991                                 }
1992                         }
1993
1994                         // Only perform numeric promotions on:
1995                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1996                         //
1997                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
1998                                 if (l.IsSubclassOf (TypeManager.delegate_type) &&
1999                                     r.IsSubclassOf (TypeManager.delegate_type)) {
2000                                         
2001                                         Arguments = new ArrayList ();
2002                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2003                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2004                                         
2005                                         if (oper == Operator.Addition)
2006                                                 method = TypeManager.delegate_combine_delegate_delegate;
2007                                         else
2008                                                 method = TypeManager.delegate_remove_delegate_delegate;
2009                                         
2010                                         DelegateOperation = true;
2011                                         type = l;
2012                                         return this;
2013                                 }
2014
2015                                 //
2016                                 // Pointer arithmetic:
2017                                 //
2018                                 // T* operator + (T* x, int y);
2019                                 // T* operator + (T* x, uint y);
2020                                 // T* operator + (T* x, long y);
2021                                 // T* operator + (T* x, ulong y);
2022                                 //
2023                                 // T* operator + (int y,   T* x);
2024                                 // T* operator + (uint y,  T *x);
2025                                 // T* operator + (long y,  T *x);
2026                                 // T* operator + (ulong y, T *x);
2027                                 //
2028                                 // T* operator - (T* x, int y);
2029                                 // T* operator - (T* x, uint y);
2030                                 // T* operator - (T* x, long y);
2031                                 // T* operator - (T* x, ulong y);
2032                                 //
2033                                 // long operator - (T* x, T *y)
2034                                 //
2035                                 if (l.IsPointer){
2036                                         if (r.IsPointer && oper == Operator.Subtraction){
2037                                                 if (r == l)
2038                                                         return new PointerArithmetic (
2039                                                                 false, left, right, TypeManager.int64_type);
2040                                         } else if (is_32_or_64 (r))
2041                                                 return new PointerArithmetic (
2042                                                         oper == Operator.Addition, left, right, l);
2043                                 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2044                                         return new PointerArithmetic (
2045                                                 true, right, left, r);
2046                         }
2047                         
2048                         //
2049                         // Enumeration operators
2050                         //
2051                         bool lie = TypeManager.IsEnumType (l);
2052                         bool rie = TypeManager.IsEnumType (r);
2053                         if (lie || rie){
2054                                 Expression temp;
2055
2056                                 //
2057                                 // operator + (E e, U x)
2058                                 //
2059                                 if (oper == Operator.Addition){
2060                                         if (lie && rie){
2061                                                 Error_OperatorCannotBeApplied ();
2062                                                 return null;
2063                                         }
2064
2065                                         Type enum_type = lie ? l : r;
2066                                         Type other_type = lie ? r : l;
2067                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2068 ;
2069                                         
2070                                         if (underlying_type != other_type){
2071                                                 Error_OperatorCannotBeApplied ();
2072                                                 return null;
2073                                         }
2074
2075                                         type = enum_type;
2076                                         return this;
2077                                 }
2078                                 
2079                                 if (!rie){
2080                                         temp = ConvertImplicit (ec, right, l, loc);
2081                                         if (temp != null)
2082                                                 right = temp;
2083                                 } if (!lie){
2084                                         temp = ConvertImplicit (ec, left, r, loc);
2085                                         if (temp != null){
2086                                                 left = temp;
2087                                                 l = r;
2088                                         }
2089                                 }
2090                                  
2091                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2092                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2093                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2094                                         type = TypeManager.bool_type;
2095                                         return this;
2096                                 }
2097
2098                                 if (oper == Operator.BitwiseAnd ||
2099                                     oper == Operator.BitwiseOr ||
2100                                     oper == Operator.ExclusiveOr){
2101                                         type = l;
2102                                         return this;
2103                                 }
2104                                 return null;
2105                         }
2106                         
2107                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2108                                 return CheckShiftArguments (ec);
2109
2110                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2111                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
2112                                         Error_OperatorCannotBeApplied ();
2113                                         return null;
2114                                 }
2115
2116                                 type = TypeManager.bool_type;
2117                                 return this;
2118                         } 
2119
2120                         //
2121                         // operator & (bool x, bool y)
2122                         // operator | (bool x, bool y)
2123                         // operator ^ (bool x, bool y)
2124                         //
2125                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2126                                 if (oper == Operator.BitwiseAnd ||
2127                                     oper == Operator.BitwiseOr ||
2128                                     oper == Operator.ExclusiveOr){
2129                                         type = l;
2130                                         return this;
2131                                 }
2132                         }
2133                         
2134                         //
2135                         // Pointer comparison
2136                         //
2137                         if (l.IsPointer && r.IsPointer){
2138                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2139                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2140                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2141                                         type = TypeManager.bool_type;
2142                                         return this;
2143                                 }
2144                         }
2145                         
2146                         //
2147                         // We are dealing with numbers
2148                         //
2149                         if (overload_failed){
2150                                 Error_OperatorCannotBeApplied ();
2151                                 return null;
2152                         }
2153
2154                         if (!DoNumericPromotions (ec, l, r)){
2155                                 Error_OperatorCannotBeApplied ();
2156                                 return null;
2157                         }
2158
2159                         if (left == null || right == null)
2160                                 return null;
2161
2162                         //
2163                         // reload our cached types if required
2164                         //
2165                         l = left.Type;
2166                         r = right.Type;
2167                         
2168                         if (oper == Operator.BitwiseAnd ||
2169                             oper == Operator.BitwiseOr ||
2170                             oper == Operator.ExclusiveOr){
2171                                 if (l == r){
2172                                         if (!((l == TypeManager.int32_type) ||
2173                                               (l == TypeManager.uint32_type) ||
2174                                               (l == TypeManager.int64_type) ||
2175                                               (l == TypeManager.uint64_type)))
2176                                                 type = l;
2177                                 } else {
2178                                         Error_OperatorCannotBeApplied ();
2179                                         return null;
2180                                 }
2181                         }
2182
2183                         if (oper == Operator.Equality ||
2184                             oper == Operator.Inequality ||
2185                             oper == Operator.LessThanOrEqual ||
2186                             oper == Operator.LessThan ||
2187                             oper == Operator.GreaterThanOrEqual ||
2188                             oper == Operator.GreaterThan){
2189                                 type = TypeManager.bool_type;
2190                         }
2191
2192                         return this;
2193                 }
2194
2195                 public override Expression DoResolve (EmitContext ec)
2196                 {
2197                         left = left.Resolve (ec);
2198                         right = right.Resolve (ec);
2199
2200                         if (left == null || right == null)
2201                                 return null;
2202
2203                         if (left.Type == null)
2204                                 throw new Exception (
2205                                         "Resolve returned non null, but did not set the type! (" +
2206                                         left + ") at Line: " + loc.Row);
2207                         if (right.Type == null)
2208                                 throw new Exception (
2209                                         "Resolve returned non null, but did not set the type! (" +
2210                                         right + ") at Line: "+ loc.Row);
2211
2212                         eclass = ExprClass.Value;
2213
2214                         if (left is Constant && right is Constant){
2215                                 Expression e = ConstantFold.BinaryFold (
2216                                         ec, oper, (Constant) left, (Constant) right, loc);
2217                                 if (e != null)
2218                                         return e;
2219                         }
2220
2221                         return ResolveOperator (ec);
2222                 }
2223
2224                 public bool IsBranchable ()
2225                 {
2226                         if (oper == Operator.Equality ||
2227                             oper == Operator.Inequality ||
2228                             oper == Operator.LessThan ||
2229                             oper == Operator.GreaterThan ||
2230                             oper == Operator.LessThanOrEqual ||
2231                             oper == Operator.GreaterThanOrEqual){
2232                                 return true;
2233                         } else
2234                                 return false;
2235                 }
2236
2237                 /// <summary>
2238                 ///   This entry point is used by routines that might want
2239                 ///   to emit a brfalse/brtrue after an expression, and instead
2240                 ///   they could use a more compact notation.
2241                 ///
2242                 ///   Typically the code would generate l.emit/r.emit, followed
2243                 ///   by the comparission and then a brtrue/brfalse.  The comparissions
2244                 ///   are sometimes inneficient (there are not as complete as the branches
2245                 ///   look for the hacks in Emit using double ceqs).
2246                 ///
2247                 ///   So for those cases we provide EmitBranchable that can emit the
2248                 ///   branch with the test
2249                 /// </summary>
2250                 public void EmitBranchable (EmitContext ec, int target)
2251                 {
2252                         OpCode opcode;
2253                         bool close_target = false;
2254                         ILGenerator ig = ec.ig;
2255                                 
2256                         //
2257                         // short-circuit operators
2258                         //
2259                         if (oper == Operator.LogicalAnd){
2260                                 left.Emit (ec);
2261                                 ig.Emit (OpCodes.Brfalse, target);
2262                                 right.Emit (ec);
2263                                 ig.Emit (OpCodes.Brfalse, target);
2264                         } else if (oper == Operator.LogicalOr){
2265                                 left.Emit (ec);
2266                                 ig.Emit (OpCodes.Brtrue, target);
2267                                 right.Emit (ec);
2268                                 ig.Emit (OpCodes.Brfalse, target);
2269                         }
2270                                 
2271                         left.Emit (ec);
2272                         right.Emit (ec);
2273                         
2274                         switch (oper){
2275                         case Operator.Equality:
2276                                 if (close_target)
2277                                         opcode = OpCodes.Beq_S;
2278                                 else
2279                                         opcode = OpCodes.Beq;
2280                                 break;
2281
2282                         case Operator.Inequality:
2283                                 if (close_target)
2284                                         opcode = OpCodes.Bne_Un_S;
2285                                 else
2286                                         opcode = OpCodes.Bne_Un;
2287                                 break;
2288
2289                         case Operator.LessThan:
2290                                 if (close_target)
2291                                         opcode = OpCodes.Blt_S;
2292                                 else
2293                                         opcode = OpCodes.Blt;
2294                                 break;
2295
2296                         case Operator.GreaterThan:
2297                                 if (close_target)
2298                                         opcode = OpCodes.Bgt_S;
2299                                 else
2300                                         opcode = OpCodes.Bgt;
2301                                 break;
2302
2303                         case Operator.LessThanOrEqual:
2304                                 if (close_target)
2305                                         opcode = OpCodes.Ble_S;
2306                                 else
2307                                         opcode = OpCodes.Ble;
2308                                 break;
2309
2310                         case Operator.GreaterThanOrEqual:
2311                                 if (close_target)
2312                                         opcode = OpCodes.Bge_S;
2313                                 else
2314                                         opcode = OpCodes.Ble;
2315                                 break;
2316
2317                         default:
2318                                 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
2319                                                      + oper.ToString ());
2320                         }
2321
2322                         ig.Emit (opcode, target);
2323                 }
2324                 
2325                 public override void Emit (EmitContext ec)
2326                 {
2327                         ILGenerator ig = ec.ig;
2328                         Type l = left.Type;
2329                         Type r = right.Type;
2330                         OpCode opcode;
2331
2332                         if (method != null) {
2333
2334                                 // Note that operators are static anyway
2335                                 
2336                                 if (Arguments != null) 
2337                                         Invocation.EmitArguments (ec, method, Arguments);
2338                                 
2339                                 if (method is MethodInfo)
2340                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2341                                 else
2342                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2343
2344                                 if (DelegateOperation)
2345                                         ig.Emit (OpCodes.Castclass, type);
2346                                         
2347                                 return;
2348                         }
2349
2350                         //
2351                         // Handle short-circuit operators differently
2352                         // than the rest
2353                         //
2354                         if (oper == Operator.LogicalAnd){
2355                                 Label load_zero = ig.DefineLabel ();
2356                                 Label end = ig.DefineLabel ();
2357                                 
2358                                 left.Emit (ec);
2359                                 ig.Emit (OpCodes.Brfalse, load_zero);
2360                                 right.Emit (ec);
2361                                 ig.Emit (OpCodes.Br, end);
2362                                 ig.MarkLabel (load_zero);
2363                                 ig.Emit (OpCodes.Ldc_I4_0);
2364                                 ig.MarkLabel (end);
2365                                 return;
2366                         } else if (oper == Operator.LogicalOr){
2367                                 Label load_one = ig.DefineLabel ();
2368                                 Label end = ig.DefineLabel ();
2369                                 
2370                                 left.Emit (ec);
2371                                 ig.Emit (OpCodes.Brtrue, load_one);
2372                                 right.Emit (ec);
2373                                 ig.Emit (OpCodes.Br, end);
2374                                 ig.MarkLabel (load_one);
2375                                 ig.Emit (OpCodes.Ldc_I4_1);
2376                                 ig.MarkLabel (end);
2377                                 return;
2378                         }
2379                         
2380                         left.Emit (ec);
2381                         right.Emit (ec);
2382
2383                         switch (oper){
2384                         case Operator.Multiply:
2385                                 if (ec.CheckState){
2386                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2387                                                 opcode = OpCodes.Mul_Ovf;
2388                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2389                                                 opcode = OpCodes.Mul_Ovf_Un;
2390                                         else
2391                                                 opcode = OpCodes.Mul;
2392                                 } else
2393                                         opcode = OpCodes.Mul;
2394
2395                                 break;
2396
2397                         case Operator.Division:
2398                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2399                                         opcode = OpCodes.Div_Un;
2400                                 else
2401                                         opcode = OpCodes.Div;
2402                                 break;
2403
2404                         case Operator.Modulus:
2405                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2406                                         opcode = OpCodes.Rem_Un;
2407                                 else
2408                                         opcode = OpCodes.Rem;
2409                                 break;
2410
2411                         case Operator.Addition:
2412                                 if (ec.CheckState){
2413                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2414                                                 opcode = OpCodes.Add_Ovf;
2415                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2416                                                 opcode = OpCodes.Add_Ovf_Un;
2417                                         else
2418                                                 opcode = OpCodes.Add;
2419                                 } else
2420                                         opcode = OpCodes.Add;
2421                                 break;
2422
2423                         case Operator.Subtraction:
2424                                 if (ec.CheckState){
2425                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2426                                                 opcode = OpCodes.Sub_Ovf;
2427                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2428                                                 opcode = OpCodes.Sub_Ovf_Un;
2429                                         else
2430                                                 opcode = OpCodes.Sub;
2431                                 } else
2432                                         opcode = OpCodes.Sub;
2433                                 break;
2434
2435                         case Operator.RightShift:
2436                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2437                                         opcode = OpCodes.Shr_Un;
2438                                 else
2439                                         opcode = OpCodes.Shr;
2440                                 break;
2441                                 
2442                         case Operator.LeftShift:
2443                                 opcode = OpCodes.Shl;
2444                                 break;
2445
2446                         case Operator.Equality:
2447                                 opcode = OpCodes.Ceq;
2448                                 break;
2449
2450                         case Operator.Inequality:
2451                                 ec.ig.Emit (OpCodes.Ceq);
2452                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
2453                                 
2454                                 opcode = OpCodes.Ceq;
2455                                 break;
2456
2457                         case Operator.LessThan:
2458                                 opcode = OpCodes.Clt;
2459                                 break;
2460
2461                         case Operator.GreaterThan:
2462                                 opcode = OpCodes.Cgt;
2463                                 break;
2464
2465                         case Operator.LessThanOrEqual:
2466                                 ec.ig.Emit (OpCodes.Cgt);
2467                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
2468                                 
2469                                 opcode = OpCodes.Ceq;
2470                                 break;
2471
2472                         case Operator.GreaterThanOrEqual:
2473                                 ec.ig.Emit (OpCodes.Clt);
2474                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
2475                                 
2476                                 opcode = OpCodes.Sub;
2477                                 break;
2478
2479                         case Operator.BitwiseOr:
2480                                 opcode = OpCodes.Or;
2481                                 break;
2482
2483                         case Operator.BitwiseAnd:
2484                                 opcode = OpCodes.And;
2485                                 break;
2486
2487                         case Operator.ExclusiveOr:
2488                                 opcode = OpCodes.Xor;
2489                                 break;
2490
2491                         default:
2492                                 throw new Exception ("This should not happen: Operator = "
2493                                                      + oper.ToString ());
2494                         }
2495
2496                         ig.Emit (opcode);
2497                 }
2498
2499                 public bool IsBuiltinOperator {
2500                         get {
2501                                 return method == null;
2502                         }
2503                 }
2504         }
2505
2506         public class PointerArithmetic : Expression {
2507                 Expression left, right;
2508                 bool is_add;
2509
2510                 //
2511                 // We assume that `l' is always a pointer
2512                 //
2513                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t)
2514                 {
2515                         type = t;
2516                         eclass = ExprClass.Variable;
2517                         left = l;
2518                         right = r;
2519                         is_add = is_addition;
2520                 }
2521
2522                 public override Expression DoResolve (EmitContext ec)
2523                 {
2524                         //
2525                         // We are born fully resolved
2526                         //
2527                         return this;
2528                 }
2529
2530                 public override void Emit (EmitContext ec)
2531                 {
2532                         Type op_type = left.Type;
2533                         ILGenerator ig = ec.ig;
2534                         int size = GetTypeSize (op_type.GetElementType ());
2535                         
2536                         if (right.Type.IsPointer){
2537                                 //
2538                                 // handle (pointer - pointer)
2539                                 //
2540                                 left.Emit (ec);
2541                                 right.Emit (ec);
2542                                 ig.Emit (OpCodes.Sub);
2543
2544                                 if (size != 1){
2545                                         if (size == 0)
2546                                                 ig.Emit (OpCodes.Sizeof, op_type);
2547                                         else 
2548                                                 IntLiteral.EmitInt (ig, size);
2549                                         ig.Emit (OpCodes.Div);
2550                                 }
2551                                 ig.Emit (OpCodes.Conv_I8);
2552                         } else {
2553                                 //
2554                                 // handle + and - on (pointer op int)
2555                                 //
2556                                 left.Emit (ec);
2557                                 ig.Emit (OpCodes.Conv_I);
2558                                 right.Emit (ec);
2559                                 if (size != 1){
2560                                         if (size == 0)
2561                                                 ig.Emit (OpCodes.Sizeof, op_type);
2562                                         else 
2563                                                 IntLiteral.EmitInt (ig, size);
2564                                         ig.Emit (OpCodes.Mul);
2565                                 }
2566                                 if (is_add)
2567                                         ig.Emit (OpCodes.Add);
2568                                 else
2569                                         ig.Emit (OpCodes.Sub);
2570                         }
2571                 }
2572         }
2573         
2574         /// <summary>
2575         ///   Implements the ternary conditiona operator (?:)
2576         /// </summary>
2577         public class Conditional : Expression {
2578                 Expression expr, trueExpr, falseExpr;
2579                 Location loc;
2580                 
2581                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2582                 {
2583                         this.expr = expr;
2584                         this.trueExpr = trueExpr;
2585                         this.falseExpr = falseExpr;
2586                         this.loc = l;
2587                 }
2588
2589                 public Expression Expr {
2590                         get {
2591                                 return expr;
2592                         }
2593                 }
2594
2595                 public Expression TrueExpr {
2596                         get {
2597                                 return trueExpr;
2598                         }
2599                 }
2600
2601                 public Expression FalseExpr {
2602                         get {
2603                                 return falseExpr;
2604                         }
2605                 }
2606
2607                 public override Expression DoResolve (EmitContext ec)
2608                 {
2609                         expr = expr.Resolve (ec);
2610
2611                         if (expr.Type != TypeManager.bool_type)
2612                                 expr = Expression.ConvertImplicitRequired (
2613                                         ec, expr, TypeManager.bool_type, loc);
2614                         
2615                         trueExpr = trueExpr.Resolve (ec);
2616                         falseExpr = falseExpr.Resolve (ec);
2617
2618                         if (expr == null || trueExpr == null || falseExpr == null)
2619                                 return null;
2620
2621                         eclass = ExprClass.Value;
2622                         if (trueExpr.Type == falseExpr.Type)
2623                                 type = trueExpr.Type;
2624                         else {
2625                                 Expression conv;
2626                                 Type true_type = trueExpr.Type;
2627                                 Type false_type = falseExpr.Type;
2628
2629                                 if (trueExpr is NullLiteral){
2630                                         type = false_type;
2631                                         return this;
2632                                 } else if (falseExpr is NullLiteral){
2633                                         type = true_type;
2634                                         return this;
2635                                 }
2636                                 
2637                                 //
2638                                 // First, if an implicit conversion exists from trueExpr
2639                                 // to falseExpr, then the result type is of type falseExpr.Type
2640                                 //
2641                                 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
2642                                 if (conv != null){
2643                                         //
2644                                         // Check if both can convert implicitl to each other's type
2645                                         //
2646                                         if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
2647                                                 Report.Error (
2648                                                         172, loc,
2649                                                         "Can not compute type of conditional expression " +
2650                                                         "as `" + TypeManager.CSharpName (trueExpr.Type) +
2651                                                         "' and `" + TypeManager.CSharpName (falseExpr.Type) +
2652                                                         "' convert implicitly to each other");
2653                                                 return null;
2654                                         }
2655                                         type = false_type;
2656                                         trueExpr = conv;
2657                                 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
2658                                         type = true_type;
2659                                         falseExpr = conv;
2660                                 } else {
2661                                         Error (173, loc, "The type of the conditional expression can " +
2662                                                "not be computed because there is no implicit conversion" +
2663                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2664                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2665                                         return null;
2666                                 }
2667                         }
2668
2669                         if (expr is BoolConstant){
2670                                 BoolConstant bc = (BoolConstant) expr;
2671
2672                                 if (bc.Value)
2673                                         return trueExpr;
2674                                 else
2675                                         return falseExpr;
2676                         }
2677
2678                         return this;
2679                 }
2680
2681                 public override void Emit (EmitContext ec)
2682                 {
2683                         ILGenerator ig = ec.ig;
2684                         Label false_target = ig.DefineLabel ();
2685                         Label end_target = ig.DefineLabel ();
2686
2687                         expr.Emit (ec);
2688                         ig.Emit (OpCodes.Brfalse, false_target);
2689                         trueExpr.Emit (ec);
2690                         ig.Emit (OpCodes.Br, end_target);
2691                         ig.MarkLabel (false_target);
2692                         falseExpr.Emit (ec);
2693                         ig.MarkLabel (end_target);
2694                 }
2695
2696         }
2697
2698         /// <summary>
2699         ///   Local variables
2700         /// </summary>
2701         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation {
2702                 public readonly string Name;
2703                 public readonly Block Block;
2704                 Location loc;
2705                 VariableInfo variable_info;
2706                 
2707                 public LocalVariableReference (Block block, string name, Location l)
2708                 {
2709                         Block = block;
2710                         Name = name;
2711                         loc = l;
2712                         eclass = ExprClass.Variable;
2713                 }
2714
2715                 public VariableInfo VariableInfo {
2716                         get {
2717                                 if (variable_info == null)
2718                                         variable_info = Block.GetVariableInfo (Name);
2719                                 return variable_info;
2720                         }
2721                 }
2722                 
2723                 public override Expression DoResolve (EmitContext ec)
2724                 {
2725                         VariableInfo vi = VariableInfo;
2726
2727                         if (Block.IsConstant (Name)) {
2728                                 Expression e = Block.GetConstantExpression (Name);
2729
2730                                 vi.Used = true;
2731                                 return e;
2732                         }
2733
2734                         type = vi.VariableType;
2735                         return this;
2736                 }
2737
2738                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2739                 {
2740                         Expression e = DoResolve (ec);
2741
2742                         if (e == null)
2743                                 return null;
2744
2745                         VariableInfo vi = VariableInfo;
2746
2747 #if BROKEN
2748                         //
2749                         // Sigh:  this breaks `using' and `fixed'.  Need to review that
2750                         //
2751                         if (vi.ReadOnly){
2752                                 Report.Error (
2753                                         1604, loc,
2754                                         "cannot assign to `" + Name + "' because it is readonly");
2755                                 return null;
2756                         }
2757 #endif
2758                         
2759                         return this;
2760                 }
2761
2762                 public override void Emit (EmitContext ec)
2763                 {
2764                         VariableInfo vi = VariableInfo;
2765                         ILGenerator ig = ec.ig;
2766
2767                         ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
2768                         vi.Used = true;
2769                 }
2770                 
2771                 public void EmitAssign (EmitContext ec, Expression source)
2772                 {
2773                         ILGenerator ig = ec.ig;
2774                         VariableInfo vi = VariableInfo;
2775
2776                         vi.Assigned = true;
2777
2778                         source.Emit (ec);
2779                         
2780                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2781                 }
2782                 
2783                 public void AddressOf (EmitContext ec, AddressOp mode)
2784                 {
2785                         VariableInfo vi = VariableInfo;
2786
2787                         if ((mode & AddressOp.Load) != 0)
2788                                 vi.Used = true;
2789                         if ((mode & AddressOp.Store) != 0)
2790                                 vi.Assigned = true;
2791
2792                         ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
2793                 }
2794         }
2795
2796         /// <summary>
2797         ///   This represents a reference to a parameter in the intermediate
2798         ///   representation.
2799         /// </summary>
2800         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation {
2801                 Parameters pars;
2802                 String name;
2803                 int idx;
2804                 public bool is_ref;
2805                 
2806                 public ParameterReference (Parameters pars, int idx, string name)
2807                 {
2808                         this.pars = pars;
2809                         this.idx  = idx;
2810                         this.name = name;
2811                         eclass = ExprClass.Variable;
2812                 }
2813
2814                 //
2815                 // Notice that for ref/out parameters, the type exposed is not the
2816                 // same type exposed externally.
2817                 //
2818                 // for "ref int a":
2819                 //   externally we expose "int&"
2820                 //   here we expose       "int".
2821                 //
2822                 // We record this in "is_ref".  This means that the type system can treat
2823                 // the type as it is expected, but when we generate the code, we generate
2824                 // the alternate kind of code.
2825                 //
2826                 public override Expression DoResolve (EmitContext ec)
2827                 {
2828                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out is_ref);
2829                         eclass = ExprClass.Variable;
2830
2831                         return this;
2832                 }
2833
2834                 //
2835                 // This method is used by parameters that are references, that are
2836                 // being passed as references:  we only want to pass the pointer (that
2837                 // is already stored in the parameter, not the address of the pointer,
2838                 // and not the value of the variable).
2839                 //
2840                 public void EmitLoad (EmitContext ec)
2841                 {
2842                         ILGenerator ig = ec.ig;
2843                         int arg_idx = idx;
2844
2845                         if (!ec.IsStatic)
2846                                 arg_idx++;
2847                         
2848                         if (arg_idx <= 255)
2849                                 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2850                         else
2851                                 ig.Emit (OpCodes.Ldarg, arg_idx);
2852                 }
2853                 
2854                 public override void Emit (EmitContext ec)
2855                 {
2856                         ILGenerator ig = ec.ig;
2857                         int arg_idx = idx;
2858
2859                         if (!ec.IsStatic)
2860                                 arg_idx++;
2861                         
2862                         if (arg_idx <= 255)
2863                                 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2864                         else
2865                                 ig.Emit (OpCodes.Ldarg, arg_idx);
2866
2867                         if (!is_ref)
2868                                 return;
2869
2870                         //
2871                         // If we are a reference, we loaded on the stack a pointer
2872                         // Now lets load the real value
2873                         //
2874                         LoadFromPtr (ig, type);
2875                 }
2876
2877                 public void EmitAssign (EmitContext ec, Expression source)
2878                 {
2879                         ILGenerator ig = ec.ig;
2880                         int arg_idx = idx;
2881
2882                         if (!ec.IsStatic)
2883                                 arg_idx++;
2884
2885                         if (is_ref){
2886                                 // Load the pointer
2887                                 if (arg_idx <= 255)
2888                                         ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2889                                 else
2890                                         ig.Emit (OpCodes.Ldarg, arg_idx);
2891                         }
2892                         
2893                         source.Emit (ec);
2894
2895                         if (is_ref)
2896                                 StoreFromPtr (ig, type);
2897                         else {
2898                                 if (arg_idx <= 255)
2899                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
2900                                 else
2901                                         ig.Emit (OpCodes.Starg, arg_idx);
2902                         }
2903                         
2904                 }
2905
2906                 public void AddressOf (EmitContext ec, AddressOp mode)
2907                 {
2908                         int arg_idx = idx;
2909
2910                         if (!ec.IsStatic)
2911                                 arg_idx++;
2912
2913                         if (arg_idx <= 255)
2914                                 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
2915                         else
2916                                 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
2917                 }
2918         }
2919         
2920         /// <summary>
2921         ///   Used for arguments to New(), Invocation()
2922         /// </summary>
2923         public class Argument {
2924                 public enum AType : byte {
2925                         Expression,
2926                         Ref,
2927                         Out
2928                 };
2929
2930                 public readonly AType ArgType;
2931                 public Expression expr;
2932                 
2933                 public Argument (Expression expr, AType type)
2934                 {
2935                         this.expr = expr;
2936                         this.ArgType = type;
2937                 }
2938
2939                 public Expression Expr {
2940                         get {
2941                                 return expr;
2942                         }
2943
2944                         set {
2945                                 expr = value;
2946                         }
2947                 }
2948
2949                 public Type Type {
2950                         get {
2951                                 if (ArgType == AType.Ref || ArgType == AType.Out)
2952                                         return TypeManager.LookupType (expr.Type.ToString () + "&");
2953                                 else
2954                                         return expr.Type;
2955                         }
2956                 }
2957
2958                 public Parameter.Modifier GetParameterModifier ()
2959                 {
2960                         if (ArgType == AType.Ref || ArgType == AType.Out)
2961                                 return Parameter.Modifier.OUT;
2962
2963                         return Parameter.Modifier.NONE;
2964                 }
2965
2966                 public static string FullDesc (Argument a)
2967                 {
2968                         return (a.ArgType == AType.Ref ? "ref " :
2969                                 (a.ArgType == AType.Out ? "out " : "")) +
2970                                 TypeManager.CSharpName (a.Expr.Type);
2971                 }
2972                 
2973                 public bool Resolve (EmitContext ec, Location loc)
2974                 {
2975                         expr = expr.Resolve (ec);
2976
2977                         if (ArgType == AType.Expression)
2978                                 return expr != null;
2979
2980                         if (expr.eclass != ExprClass.Variable){
2981                                 //
2982                                 // We just probe to match the CSC output
2983                                 //
2984                                 if (expr.eclass == ExprClass.PropertyAccess ||
2985                                     expr.eclass == ExprClass.IndexerAccess){
2986                                         Report.Error (
2987                                                 206, loc,
2988                                                 "A property or indexer can not be passed as an out or ref " +
2989                                                 "parameter");
2990                                 } else {
2991                                         Report.Error (
2992                                                 1510, loc,
2993                                                 "An lvalue is required as an argument to out or ref");
2994                                 }
2995                                 return false;
2996                         }
2997                                 
2998                         return expr != null;
2999                 }
3000
3001                 public void Emit (EmitContext ec)
3002                 {
3003                         //
3004                         // Ref and Out parameters need to have their addresses taken.
3005                         //
3006                         // ParameterReferences might already be references, so we want
3007                         // to pass just the value
3008                         //
3009                         if (ArgType == AType.Ref || ArgType == AType.Out){
3010                                 AddressOp mode = AddressOp.Store;
3011
3012                                 if (ArgType == AType.Ref)
3013                                         mode |= AddressOp.Load;
3014                                 
3015                                 if (expr is ParameterReference){
3016                                         ParameterReference pr = (ParameterReference) expr;
3017
3018                                         if (pr.is_ref)
3019                                                 pr.EmitLoad (ec);
3020                                         else {
3021                                                 
3022                                                 pr.AddressOf (ec, mode);
3023                                         }
3024                                 } else
3025                                         ((IMemoryLocation)expr).AddressOf (ec, mode);
3026                         } else
3027                                 expr.Emit (ec);
3028                 }
3029         }
3030
3031         /// <summary>
3032         ///   Invocation of methods or delegates.
3033         /// </summary>
3034         public class Invocation : ExpressionStatement {
3035                 public readonly ArrayList Arguments;
3036                 Location loc;
3037
3038                 Expression expr;
3039                 MethodBase method = null;
3040                 bool is_base;
3041                 
3042                 static Hashtable method_parameter_cache;
3043
3044                 static Invocation ()
3045                 {
3046                         method_parameter_cache = new PtrHashtable ();
3047                 }
3048                         
3049                 //
3050                 // arguments is an ArrayList, but we do not want to typecast,
3051                 // as it might be null.
3052                 //
3053                 // FIXME: only allow expr to be a method invocation or a
3054                 // delegate invocation (7.5.5)
3055                 //
3056                 public Invocation (Expression expr, ArrayList arguments, Location l)
3057                 {
3058                         this.expr = expr;
3059                         Arguments = arguments;
3060                         loc = l;
3061                 }
3062
3063                 public Expression Expr {
3064                         get {
3065                                 return expr;
3066                         }
3067                 }
3068
3069                 /// <summary>
3070                 ///   Returns the Parameters (a ParameterData interface) for the
3071                 ///   Method `mb'
3072                 /// </summary>
3073                 public static ParameterData GetParameterData (MethodBase mb)
3074                 {
3075                         object pd = method_parameter_cache [mb];
3076                         object ip;
3077                         
3078                         if (pd != null)
3079                                 return (ParameterData) pd;
3080
3081                         
3082                         ip = TypeManager.LookupParametersByBuilder (mb);
3083                         if (ip != null){
3084                                 method_parameter_cache [mb] = ip;
3085
3086                                 return (ParameterData) ip;
3087                         } else {
3088                                 ParameterInfo [] pi = mb.GetParameters ();
3089                                 ReflectionParameters rp = new ReflectionParameters (pi);
3090                                 method_parameter_cache [mb] = rp;
3091
3092                                 return (ParameterData) rp;
3093                         }
3094                 }
3095
3096                 /// <summary>
3097                 ///  Determines "better conversion" as specified in 7.4.2.3
3098                 ///  Returns : 1 if a->p is better
3099                 ///            0 if a->q or neither is better 
3100                 /// </summary>
3101                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
3102                 {
3103                         Type argument_type = a.Type;
3104                         Expression argument_expr = a.Expr;
3105
3106                         if (argument_type == null)
3107                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3108
3109                         if (p == q)
3110                                 return 0;
3111                         
3112                         if (argument_type == p)
3113                                 return 1;
3114
3115                         if (argument_type == q)
3116                                 return 0;
3117
3118                         //
3119                         // Now probe whether an implicit constant expression conversion
3120                         // can be used.
3121                         //
3122                         // An implicit constant expression conversion permits the following
3123                         // conversions:
3124                         //
3125                         //    * A constant-expression of type `int' can be converted to type
3126                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
3127                         //      of the expression is withing the range of the destination type.
3128                         //
3129                         //    * A constant-expression of type long can be converted to type
3130                         //      ulong, provided the value of the constant expression is not negative
3131                         //
3132                         // FIXME: Note that this assumes that constant folding has
3133                         // taken place.  We dont do constant folding yet.
3134                         //
3135
3136                         if (argument_expr is IntConstant){
3137                                 IntConstant ei = (IntConstant) argument_expr;
3138                                 int value = ei.Value;
3139                                 
3140                                 if (p == TypeManager.sbyte_type){
3141                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
3142                                                 return 1;
3143                                 } else if (p == TypeManager.byte_type){
3144                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3145                                                 return 1;
3146                                 } else if (p == TypeManager.short_type){
3147                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
3148                                                 return 1;
3149                                 } else if (p == TypeManager.ushort_type){
3150                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3151                                                 return 1;
3152                                 } else if (p == TypeManager.uint32_type){
3153                                         //
3154                                         // we can optimize this case: a positive int32
3155                                         // always fits on a uint32
3156                                         //
3157                                         if (value >= 0)
3158                                                 return 1;
3159                                 } else if (p == TypeManager.uint64_type){
3160                                         //
3161                                         // we can optimize this case: a positive int32
3162                                         // always fits on a uint64
3163                                         //
3164                                         if (value >= 0)
3165                                                 return 1;
3166                                 }
3167                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
3168                                 LongConstant lc = (LongConstant) argument_expr;
3169                                 
3170                                 if (p == TypeManager.uint64_type){
3171                                         if (lc.Value > 0)
3172                                                 return 1;
3173                                 }
3174                         }
3175
3176                         if (q == null) {
3177                                 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
3178                                 
3179                                 if (tmp != null)
3180                                         return 1;
3181                                 else
3182                                         return 0;
3183                         }
3184
3185                         Expression p_tmp = new EmptyExpression (p);
3186                         Expression q_tmp = new EmptyExpression (q);
3187                         
3188                         if (StandardConversionExists (p_tmp, q) == true &&
3189                             StandardConversionExists (q_tmp, p) == false)
3190                                 return 1;
3191
3192                         if (p == TypeManager.sbyte_type)
3193                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3194                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3195                                         return 1;
3196
3197                         if (p == TypeManager.short_type)
3198                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3199                                     q == TypeManager.uint64_type)
3200                                         return 1;
3201
3202                         if (p == TypeManager.int32_type)
3203                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3204                                         return 1;
3205
3206                         if (p == TypeManager.int64_type)
3207                                 if (q == TypeManager.uint64_type)
3208                                         return 1;
3209
3210                         return 0;
3211                 }
3212                 
3213                 /// <summary>
3214                 ///  Determines "Better function"
3215                 /// </summary>
3216                 /// <remarks>
3217                 ///    and returns an integer indicating :
3218                 ///    0 if candidate ain't better
3219                 ///    1 if candidate is better than the current best match
3220                 /// </remarks>
3221                 static int BetterFunction (EmitContext ec, ArrayList args,
3222                                            MethodBase candidate, MethodBase best,
3223                                            bool expanded_form, Location loc)
3224                 {
3225                         ParameterData candidate_pd = GetParameterData (candidate);
3226                         ParameterData best_pd;
3227                         int argument_count;
3228                 
3229                         if (args == null)
3230                                 argument_count = 0;
3231                         else
3232                                 argument_count = args.Count;
3233
3234                         int cand_count = candidate_pd.Count;
3235
3236                         if (cand_count == 0 && argument_count == 0)
3237                                 return 1;
3238
3239                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3240                                 if (cand_count != argument_count)
3241                                         return 0;
3242                         
3243                         if (best == null) {
3244                                 int x = 0;
3245
3246                                 if (argument_count == 0 && cand_count == 1 &&
3247                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
3248                                         return 1;
3249                                 
3250                                 for (int j = argument_count; j > 0;) {
3251                                         j--;
3252
3253                                         Argument a = (Argument) args [j];
3254                                         Type t = candidate_pd.ParameterType (j);
3255
3256                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3257                                                 if (expanded_form)
3258                                                         t = t.GetElementType ();
3259
3260                                         x = BetterConversion (ec, a, t, null, loc);
3261                                         
3262                                         if (x <= 0)
3263                                                 break;
3264                                 }
3265                                 
3266                                 if (x > 0)
3267                                         return 1;
3268                                 else
3269                                         return 0;
3270                         }
3271
3272                         best_pd = GetParameterData (best);
3273
3274                         int rating1 = 0, rating2 = 0;
3275                         
3276                         for (int j = 0; j < argument_count; ++j) {
3277                                 int x, y;
3278                                 
3279                                 Argument a = (Argument) args [j];
3280
3281                                 Type ct = candidate_pd.ParameterType (j);
3282                                 Type bt = best_pd.ParameterType (j);
3283
3284                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3285                                         if (expanded_form)
3286                                                 ct = ct.GetElementType ();
3287
3288                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3289                                         if (expanded_form)
3290                                                 bt = bt.GetElementType ();
3291                                 
3292                                 x = BetterConversion (ec, a, ct, bt, loc);
3293                                 y = BetterConversion (ec, a, bt, ct, loc);
3294
3295                                 if (x < y)
3296                                         return 0;
3297                                 
3298                                 rating1 += x;
3299                                 rating2 += y;
3300                         }
3301
3302                         if (rating1 > rating2)
3303                                 return 1;
3304                         else
3305                                 return 0;
3306                 }
3307
3308                 public static string FullMethodDesc (MethodBase mb)
3309                 {
3310                         string ret_type = "";
3311
3312                         if (mb is MethodInfo)
3313                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
3314                         
3315                         StringBuilder sb = new StringBuilder (ret_type + " " + mb.Name);
3316                         ParameterData pd = GetParameterData (mb);
3317
3318                         int count = pd.Count;
3319                         sb.Append (" (");
3320                         
3321                         for (int i = count; i > 0; ) {
3322                                 i--;
3323
3324                                 sb.Append (pd.ParameterDesc (count - i - 1));
3325                                 if (i != 0)
3326                                         sb.Append (", ");
3327                         }
3328                         
3329                         sb.Append (")");
3330                         return sb.ToString ();
3331                 }
3332
3333                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3334                 {
3335                         MemberInfo [] miset;
3336                         MethodGroupExpr union;
3337
3338                         if (mg1 == null){
3339                                 if (mg2 == null)
3340                                         return null;
3341                                 return (MethodGroupExpr) mg2;
3342                         } else {
3343                                 if (mg2 == null)
3344                                         return (MethodGroupExpr) mg1;
3345                         }
3346                         
3347                         MethodGroupExpr left_set = null, right_set = null;
3348                         int length1 = 0, length2 = 0;
3349                         
3350                         left_set = (MethodGroupExpr) mg1;
3351                         length1 = left_set.Methods.Length;
3352                         
3353                         right_set = (MethodGroupExpr) mg2;
3354                         length2 = right_set.Methods.Length;
3355                         
3356                         ArrayList common = new ArrayList ();
3357
3358                         foreach (MethodBase l in left_set.Methods){
3359                                 foreach (MethodBase r in right_set.Methods){
3360                                         if (l != r)
3361                                                 continue;
3362                                         common.Add (r);
3363                                         break;
3364                                 }
3365                         }
3366                         
3367                         miset = new MemberInfo [length1 + length2 - common.Count];
3368                         left_set.Methods.CopyTo (miset, 0);
3369                         
3370                         int k = length1;
3371
3372                         foreach (MemberInfo mi in right_set.Methods){
3373                                 if (!common.Contains (mi))
3374                                         miset [k++] = mi;
3375                         }
3376                         
3377                         union = new MethodGroupExpr (miset, loc);
3378                         
3379                         return union;
3380                 }
3381
3382                 /// <summary>
3383                 ///  Determines is the candidate method, if a params method, is applicable
3384                 ///  in its expanded form to the given set of arguments
3385                 /// </summary>
3386                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3387                 {
3388                         int arg_count;
3389                         
3390                         if (arguments == null)
3391                                 arg_count = 0;
3392                         else
3393                                 arg_count = arguments.Count;
3394                         
3395                         ParameterData pd = GetParameterData (candidate);
3396                         
3397                         int pd_count = pd.Count;
3398
3399                         if (pd_count == 0)
3400                                 return false;
3401                         
3402                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
3403                                 return false;
3404                         
3405                         if (pd_count - 1 > arg_count)
3406                                 return false;
3407                         
3408                         if (pd_count == 1 && arg_count == 0)
3409                                 return true;
3410
3411                         //
3412                         // If we have come this far, the case which remains is when the number of parameters
3413                         // is less than or equal to the argument count.
3414                         //
3415                         for (int i = 0; i < pd_count - 1; ++i) {
3416
3417                                 Argument a = (Argument) arguments [i];
3418
3419                                 Parameter.Modifier a_mod = a.GetParameterModifier ();
3420                                 Parameter.Modifier p_mod = pd.ParameterModifier (i);
3421
3422                                 if (a_mod == p_mod) {
3423
3424                                         if (a_mod == Parameter.Modifier.NONE)
3425                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3426                                                         return false;
3427                                                                                 
3428                                         if (a_mod == Parameter.Modifier.REF ||
3429                                             a_mod == Parameter.Modifier.OUT) {
3430                                                 Type pt = pd.ParameterType (i);
3431
3432                                                 if (!pt.IsByRef)
3433                                                         pt = TypeManager.LookupType (pt.FullName + "&");
3434                                                 
3435                                                 if (pt != a.Type)
3436                                                         return false;
3437                                         }
3438                                 } else
3439                                         return false;
3440                                 
3441                         }
3442
3443                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
3444
3445                         for (int i = pd_count - 1; i < arg_count; i++) {
3446                                 Argument a = (Argument) arguments [i];
3447                                 
3448                                 if (!StandardConversionExists (a.Expr, element_type))
3449                                         return false;
3450                         }
3451                         
3452                         return true;
3453                 }
3454
3455                 /// <summary>
3456                 ///  Determines if the candidate method is applicable (section 14.4.2.1)
3457                 ///  to the given set of arguments
3458                 /// </summary>
3459                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3460                 {
3461                         int arg_count;
3462
3463                         if (arguments == null)
3464                                 arg_count = 0;
3465                         else
3466                                 arg_count = arguments.Count;
3467
3468                         ParameterData pd = GetParameterData (candidate);
3469
3470                         int pd_count = pd.Count;
3471
3472                         if (arg_count != pd.Count)
3473                                 return false;
3474                         
3475                         for (int i = arg_count; i > 0; ) {
3476                                 i--;
3477
3478                                 Argument a = (Argument) arguments [i];
3479
3480                                 Parameter.Modifier a_mod = a.GetParameterModifier ();
3481                                 Parameter.Modifier p_mod = pd.ParameterModifier (i);
3482
3483                                 if (a_mod == p_mod ||
3484                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3485                                         if (a_mod == Parameter.Modifier.NONE)
3486                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3487                                                         return false;
3488                                         
3489                                         if (a_mod == Parameter.Modifier.REF ||
3490                                             a_mod == Parameter.Modifier.OUT) {
3491                                                 Type pt = pd.ParameterType (i);
3492
3493                                                 if (!pt.IsByRef)
3494                                                         pt = TypeManager.LookupType (pt.FullName + "&");
3495
3496                                                 if (pt != a.Type)
3497                                                         return false;
3498                                         }
3499                                 } else
3500                                         return false;
3501                         }
3502
3503                         return true;
3504                 }
3505                 
3506                 
3507
3508                 /// <summary>
3509                 ///   Find the Applicable Function Members (7.4.2.1)
3510                 ///
3511                 ///   me: Method Group expression with the members to select.
3512                 ///       it might contain constructors or methods (or anything
3513                 ///       that maps to a method).
3514                 ///
3515                 ///   Arguments: ArrayList containing resolved Argument objects.
3516                 ///
3517                 ///   loc: The location if we want an error to be reported, or a Null
3518                 ///        location for "probing" purposes.
3519                 ///
3520                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3521                 ///            that is the best match of me on Arguments.
3522                 ///
3523                 /// </summary>
3524                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3525                                                           ArrayList Arguments, Location loc)
3526                 {
3527                         ArrayList afm = new ArrayList ();
3528                         MethodBase method = null;
3529                         int argument_count;
3530                         ArrayList candidates = new ArrayList ();
3531                         
3532
3533                         foreach (MethodBase candidate in me.Methods){
3534                                 int x;
3535
3536                                 // Check if candidate is applicable (section 14.4.2.1)
3537                                 if (!IsApplicable (ec, Arguments, candidate))
3538                                         continue;
3539
3540                                 candidates.Add (candidate);
3541                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
3542                                 
3543                                 if (x == 0)
3544                                         continue;
3545
3546                                 method = candidate;
3547                         }
3548
3549                         if (Arguments == null)
3550                                 argument_count = 0;
3551                         else
3552                                 argument_count = Arguments.Count;
3553                         
3554                         //
3555                         // Now we see if we can find params functions, applicable in their expanded form
3556                         // since if they were applicable in their normal form, they would have been selected
3557                         // above anyways
3558                         //
3559                         bool chose_params_expanded = false;
3560                         
3561                         if (method == null) {
3562                                 candidates = new ArrayList ();
3563                                 foreach (MethodBase candidate in me.Methods){
3564                                         if (!IsParamsMethodApplicable (ec, Arguments, candidate))
3565                                                 continue;
3566
3567                                         candidates.Add (candidate);
3568
3569                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
3570                                         if (x == 0)
3571                                                 continue;
3572
3573                                         method = candidate; 
3574                                         chose_params_expanded = true;
3575                                 }
3576                         }
3577
3578                         if (method == null)
3579                                 return null;
3580
3581                         //
3582                         // Now check that there are no ambiguities i.e the selected method
3583                         // should be better than all the others
3584                         //
3585
3586                         foreach (MethodBase candidate in candidates){
3587                                 if (candidate == method)
3588                                         continue;
3589
3590                                 //
3591                                 // If a normal method is applicable in the sense that it has the same
3592                                 // number of arguments, then the expanded params method is never applicable
3593                                 // so we debar the params method.
3594                                 //
3595                                 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
3596                                     IsApplicable (ec, Arguments, method))
3597                                         continue;
3598                                         
3599                                 int x = BetterFunction (ec, Arguments, method, candidate,
3600                                                         chose_params_expanded, loc);
3601
3602                                 if (x != 1) {
3603                                         Report.Error (
3604                                                 121, loc,
3605                                                 "Ambiguous call when selecting function due to implicit casts");
3606                                         return null;
3607                                 }
3608                         }
3609
3610                         //
3611                         // And now check if the arguments are all compatible, perform conversions
3612                         // if necessary etc. and return if everything is all right
3613                         //
3614
3615                         if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
3616                                                    chose_params_expanded, null, loc))
3617                                 return method;
3618                         else
3619                                 return null;
3620                 }
3621
3622                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
3623                                                           int argument_count,
3624                                                           MethodBase method, 
3625                                                           bool chose_params_expanded,
3626                                                           Type delegate_type,
3627                                                           Location loc)
3628                 {
3629                         ParameterData pd = GetParameterData (method);
3630                         int pd_count = pd.Count;
3631                         
3632                         for (int j = 0; j < argument_count; j++) {
3633                                 Argument a = (Argument) Arguments [j];
3634                                 Expression a_expr = a.Expr;
3635                                 Type parameter_type = pd.ParameterType (j);
3636
3637                                 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
3638                                     chose_params_expanded)
3639                                         parameter_type = parameter_type.GetElementType ();
3640
3641                                 if (a.Type != parameter_type){
3642                                         Expression conv;
3643                                         
3644                                         conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
3645
3646                                         if (conv == null) {
3647                                                 if (!Location.IsNull (loc)) {
3648                                                         if (delegate_type == null) 
3649                                                                 Error (1502, loc,
3650                                                                        "The best overloaded match for method '" +
3651                                                                        FullMethodDesc (method) +
3652                                                                        "' has some invalid arguments");
3653                                                         else
3654                                                                 Report.Error (1594, loc,
3655                                                                               "Delegate '" + delegate_type.ToString () +
3656                                                                               "' has some invalid arguments.");
3657                                                         Error (1503, loc,
3658                                                          "Argument " + (j+1) +
3659                                                          ": Cannot convert from '" + Argument.FullDesc (a) 
3660                                                          + "' to '" + pd.ParameterDesc (j) + "'");
3661                                                 }
3662                                                 
3663                                                 return false;
3664                                         }
3665                                         
3666                                         //
3667                                         // Update the argument with the implicit conversion
3668                                         //
3669                                         if (a_expr != conv)
3670                                                 a.Expr = conv;
3671                                 }
3672                                 
3673                                 if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
3674                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
3675                                         if (!Location.IsNull (loc)) {
3676                                                 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
3677                                                 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
3678                                                 Console.WriteLine ("PT:  " + parameter_type.IsByRef);
3679                                                 Error (1502, loc,
3680                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
3681                                                        "' has some invalid arguments");
3682                                                 Error (1503, loc,
3683                                                        "Argument " + (j+1) +
3684                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
3685                                                        + "' to '" + pd.ParameterDesc (j) + "'");
3686                                         }
3687                                         
3688                                         return false;
3689                                 }
3690                         }
3691
3692                         return true;
3693                 }
3694                 
3695                 public override Expression DoResolve (EmitContext ec)
3696                 {
3697                         //
3698                         // First, resolve the expression that is used to
3699                         // trigger the invocation
3700                         //
3701                         if (expr is BaseAccess)
3702                                 is_base = true;
3703
3704                         expr = expr.Resolve (ec);
3705                         if (expr == null)
3706                                 return null;
3707
3708                         if (!(expr is MethodGroupExpr)) {
3709                                 Type expr_type = expr.Type;
3710
3711                                 if (expr_type != null){
3712                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
3713                                         if (IsDelegate)
3714                                                 return (new DelegateInvocation (
3715                                                         this.expr, Arguments, loc)).Resolve (ec);
3716                                 }
3717                         }
3718
3719                         if (!(expr is MethodGroupExpr)){
3720                                 report118 (loc, this.expr, "method group");
3721                                 return null;
3722                         }
3723
3724                         //
3725                         // Next, evaluate all the expressions in the argument list
3726                         //
3727                         if (Arguments != null){
3728                                 foreach (Argument a in Arguments){
3729                                         if (!a.Resolve (ec, loc))
3730                                                 return null;
3731                                 }
3732                         }
3733
3734                         method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);
3735
3736                         if (method == null){
3737                                 Error (-6, loc,
3738                                        "Could not find any applicable function for this argument list");
3739                                 return null;
3740                         }
3741
3742                         if (method is MethodInfo)
3743                                 type = ((MethodInfo)method).ReturnType;
3744
3745                         if (type.IsPointer){
3746                                 if (!ec.InUnsafe){
3747                                         UnsafeError (loc);
3748                                         return null;
3749                                 }
3750                         }
3751                         
3752                         eclass = ExprClass.Value;
3753                         return this;
3754                 }
3755
3756                 // <summary>
3757                 //   Emits the list of arguments as an array
3758                 // </summary>
3759                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
3760                 {
3761                         ILGenerator ig = ec.ig;
3762                         int count = arguments.Count - idx;
3763                         Argument a = (Argument) arguments [idx];
3764                         Type t = a.expr.Type;
3765                         string array_type = t.FullName + "[]";
3766                         LocalBuilder array;
3767
3768                         array = ig.DeclareLocal (Type.GetType (array_type));
3769                         IntConstant.EmitInt (ig, count);
3770                         ig.Emit (OpCodes.Newarr, t);
3771                         ig.Emit (OpCodes.Stloc, array);
3772
3773                         int top = arguments.Count;
3774                         for (int j = idx; j < top; j++){
3775                                 a = (Argument) arguments [j];
3776                                 
3777                                 ig.Emit (OpCodes.Ldloc, array);
3778                                 IntConstant.EmitInt (ig, j - idx);
3779                                 a.Emit (ec);
3780                                 
3781                                 ArrayAccess.EmitStoreOpcode (ig, t);
3782                         }
3783                         ig.Emit (OpCodes.Ldloc, array);
3784                 }
3785                 
3786                 /// <summary>
3787                 ///   Emits a list of resolved Arguments that are in the arguments
3788                 ///   ArrayList.
3789                 /// 
3790                 ///   The MethodBase argument might be null if the
3791                 ///   emission of the arguments is known not to contain
3792                 ///   a `params' field (for example in constructors or other routines
3793                 ///   that keep their arguments in this structure
3794                 /// </summary>
3795                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
3796                 {
3797                         ParameterData pd;
3798                         if (mb != null)
3799                                 pd = GetParameterData (mb);
3800                         else
3801                                 pd = null;
3802
3803                         //
3804                         // If we are calling a params method with no arguments, special case it
3805                         //
3806                         if (arguments == null){
3807                                 if (pd != null && pd.Count > 0 &&
3808                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
3809                                         ILGenerator ig = ec.ig;
3810
3811                                         IntConstant.EmitInt (ig, 0);
3812                                         ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
3813                                 }
3814
3815                                 return;
3816                         }
3817
3818                         int top = arguments.Count;
3819
3820                         for (int i = 0; i < top; i++){
3821                                 Argument a = (Argument) arguments [i];
3822
3823                                 if (pd != null){
3824                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
3825                                                 //
3826                                                 // Special case if we are passing the same data as the
3827                                                 // params argument, do not put it in an array.
3828                                                 //
3829                                                 if (pd.ParameterType (i) == a.Type)
3830                                                         a.Emit (ec);
3831                                                 else
3832                                                         EmitParams (ec, i, arguments);
3833                                                 return;
3834                                         }
3835                                 }
3836                                             
3837                                 a.Emit (ec);
3838                         }
3839                 }
3840
3841                 /// <remarks>
3842                 ///   is_base tells whether we want to force the use of the `call'
3843                 ///   opcode instead of using callvirt.  Call is required to call
3844                 ///   a specific method, while callvirt will always use the most
3845                 ///   recent method in the vtable.
3846                 ///
3847                 ///   is_static tells whether this is an invocation on a static method
3848                 ///
3849                 ///   instance_expr is an expression that represents the instance
3850                 ///   it must be non-null if is_static is false.
3851                 ///
3852                 ///   method is the method to invoke.
3853                 ///
3854                 ///   Arguments is the list of arguments to pass to the method or constructor.
3855                 /// </remarks>
3856                 public static void EmitCall (EmitContext ec, bool is_base,
3857                                              bool is_static, Expression instance_expr,
3858                                              MethodBase method, ArrayList Arguments, Location loc)
3859                 {
3860                         ILGenerator ig = ec.ig;
3861                         bool struct_call = false;
3862
3863                         Type decl_type = method.DeclaringType;
3864
3865                         //
3866                         // This checks the `ConditionalAttribute' on the method, and the
3867                         // ObsoleteAttribute
3868                         //
3869                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method);
3870                         if ((flags & TypeManager.MethodFlags.IsObsolete) != 0){
3871                                 Report.Warning (
3872                                         612, loc, "`" + TypeManager.CSharpSignature (method)+
3873                                         "' is obsolete");
3874                         }
3875                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
3876                                 return;
3877                         
3878                         if (!is_static){
3879                                 if (decl_type.IsValueType)
3880                                         struct_call = true;
3881                                 //
3882                                 // If this is ourselves, push "this"
3883                                 //
3884                                 if (instance_expr == null){
3885                                         ig.Emit (OpCodes.Ldarg_0);
3886                                 } else {
3887                                         //
3888                                         // Push the instance expression
3889                                         //
3890                                         if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
3891                                                 //
3892                                                 // Special case: calls to a function declared in a 
3893                                                 // reference-type with a value-type argument need
3894                                                 // to have their value boxed.  
3895
3896                                                 struct_call = true;
3897                                                 if (decl_type.IsValueType){
3898                                                         //
3899                                                         // If the expression implements IMemoryLocation, then
3900                                                         // we can optimize and use AddressOf on the
3901                                                         // return.
3902                                                         //
3903                                                         // If not we have to use some temporary storage for
3904                                                         // it.
3905                                                         if (instance_expr is IMemoryLocation){
3906                                                                 ((IMemoryLocation)instance_expr).
3907                                                                         AddressOf (ec, AddressOp.LoadStore);
3908                                                         }
3909                                                         else {
3910                                                                 Type t = instance_expr.Type;
3911                                                                 
3912                                                                 instance_expr.Emit (ec);
3913                                                                 LocalBuilder temp = ig.DeclareLocal (t);
3914                                                                 ig.Emit (OpCodes.Stloc, temp);
3915                                                                 ig.Emit (OpCodes.Ldloca, temp);
3916                                                         }
3917                                                 } else {
3918                                                         instance_expr.Emit (ec);
3919                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
3920                                                 } 
3921                                         } else
3922                                                 instance_expr.Emit (ec);
3923                                 }
3924                         }
3925
3926                         EmitArguments (ec, method, Arguments);
3927
3928                         if (is_static || struct_call || is_base){
3929                                 if (method is MethodInfo)
3930                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3931                                 else
3932                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3933                         } else {
3934                                 if (method is MethodInfo)
3935                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3936                                 else
3937                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3938                         }
3939                 }
3940                 
3941                 public override void Emit (EmitContext ec)
3942                 {
3943                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3944
3945                         EmitCall (
3946                                 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
3947                 }
3948                 
3949                 public override void EmitStatement (EmitContext ec)
3950                 {
3951                         Emit (ec);
3952
3953                         // 
3954                         // Pop the return value if there is one
3955                         //
3956                         if (method is MethodInfo){
3957                                 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3958                                         ec.ig.Emit (OpCodes.Pop);
3959                         }
3960                 }
3961         }
3962
3963         //
3964         // This class is used to "disable" the code generation for the
3965         // temporary variable when initializing value types.
3966         //
3967         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
3968                 public void AddressOf (EmitContext ec, AddressOp Mode)
3969                 {
3970                         // nothing
3971                 }
3972         }
3973         
3974         /// <summary>
3975         ///    Implements the new expression 
3976         /// </summary>
3977         public class New : ExpressionStatement {
3978                 public readonly ArrayList Arguments;
3979                 public readonly string    RequestedType;
3980
3981                 Location loc;
3982                 MethodBase method = null;
3983
3984                 //
3985                 // If set, the new expression is for a value_target, and
3986                 // we will not leave anything on the stack.
3987                 //
3988                 Expression value_target;
3989                 
3990                 public New (string requested_type, ArrayList arguments, Location l)
3991                 {
3992                         RequestedType = requested_type;
3993                         Arguments = arguments;
3994                         loc = l;
3995                 }
3996
3997                 public Expression ValueTypeVariable {
3998                         get {
3999                                 return value_target;
4000                         }
4001
4002                         set {
4003                                 value_target = value;
4004                         }
4005                 }
4006
4007                 //
4008                 // This function is used to disable the following code sequence for
4009                 // value type initialization:
4010                 //
4011                 // AddressOf (temporary)
4012                 // Construct/Init
4013                 // LoadTemporary
4014                 //
4015                 // Instead the provide will have provided us with the address on the
4016                 // stack to store the results.
4017                 //
4018                 static Expression MyEmptyExpression;
4019                 
4020                 public void DisableTemporaryValueType ()
4021                 {
4022                         if (MyEmptyExpression == null)
4023                                 MyEmptyExpression = new EmptyAddressOf ();
4024
4025                         //
4026                         // To enable this, look into:
4027                         // test-34 and test-89 and self bootstrapping.
4028                         //
4029                         // For instance, we can avoid a copy by using `newobj'
4030                         // instead of Call + Push-temp on value types.
4031 //                      value_target = MyEmptyExpression;
4032                 }
4033                 
4034                 public override Expression DoResolve (EmitContext ec)
4035                 {
4036                         type = RootContext.LookupType (ec.DeclSpace, RequestedType, false, loc);
4037                         
4038                         if (type == null)
4039                                 return null;
4040                         
4041                         bool IsDelegate = TypeManager.IsDelegateType (type);
4042                         
4043                         if (IsDelegate)
4044                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4045
4046                         if (type.IsInterface || type.IsAbstract){
4047                                 Report.Error (
4048                                         144, loc, "It is not possible to create instances of interfaces " +
4049                                         "or abstract classes");
4050                                 return null;
4051                         }
4052                         
4053                         bool is_struct = false;
4054                         is_struct = type.IsSubclassOf (TypeManager.value_type);
4055                         eclass = ExprClass.Value;
4056
4057                         //
4058                         // SRE returns a match for .ctor () on structs (the object constructor), 
4059                         // so we have to manually ignore it.
4060                         //
4061                         if (is_struct && Arguments == null)
4062                                 return this;
4063                         
4064                         Expression ml;
4065                         ml = MemberLookupFinal (ec, type, ".ctor",
4066                                                 MemberTypes.Constructor,
4067                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4068
4069                         if (ml == null)
4070                                 return null;
4071                         
4072                         if (! (ml is MethodGroupExpr)){
4073                                 if (!is_struct){
4074                                         report118 (loc, ml, "method group");
4075                                         return null;
4076                                 }
4077                         }
4078
4079                         if (ml != null) {
4080                                 if (Arguments != null){
4081                                         foreach (Argument a in Arguments){
4082                                                 if (!a.Resolve (ec, loc))
4083                                                         return null;
4084                                         }
4085                                 }
4086
4087                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
4088                                                                      Arguments, loc);
4089                                 
4090                         }
4091                         
4092                         if (method == null && !is_struct) {
4093                                 Error (1501, loc,
4094                                        "New invocation: Can not find a constructor for " +
4095                                        "this argument list");
4096                                 return null;
4097                         }
4098                         return this;
4099                 }
4100
4101                 //
4102                 // This DoEmit can be invoked in two contexts:
4103                 //    * As a mechanism that will leave a value on the stack (new object)
4104                 //    * As one that wont (init struct)
4105                 //
4106                 // You can control whether a value is required on the stack by passing
4107                 // need_value_on_stack.  The code *might* leave a value on the stack
4108                 // so it must be popped manually
4109                 //
4110                 // If we are dealing with a ValueType, we have a few
4111                 // situations to deal with:
4112                 //
4113                 //    * The target is a ValueType, and we have been provided
4114                 //      the instance (this is easy, we are being assigned).
4115                 //
4116                 //    * The target of New is being passed as an argument,
4117                 //      to a boxing operation or a function that takes a
4118                 //      ValueType.
4119                 //
4120                 //      In this case, we need to create a temporary variable
4121                 //      that is the argument of New.
4122                 //
4123                 // Returns whether a value is left on the stack
4124                 //
4125                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
4126                 {
4127                         bool is_value_type = type.IsSubclassOf (TypeManager.value_type);
4128                         ILGenerator ig = ec.ig;
4129
4130                         if (is_value_type){
4131                                 IMemoryLocation ml;
4132
4133                                 if (value_target == null)
4134                                         value_target = new LocalTemporary (ec, type);
4135                                         
4136                                 ml = (IMemoryLocation) value_target;
4137                                 ml.AddressOf (ec, AddressOp.Store);
4138                         }
4139
4140                         if (method != null)
4141                                 Invocation.EmitArguments (ec, method, Arguments);
4142
4143                         if (is_value_type){
4144                                 if (method == null)
4145                                         ig.Emit (OpCodes.Initobj, type);
4146                                 else 
4147                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4148                                 if (need_value_on_stack){
4149                                         value_target.Emit (ec);
4150                                         return true;
4151                                 }
4152                                 return false;
4153                         } else {
4154                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4155                                 return true;
4156                         }
4157                 }
4158
4159                 public override void Emit (EmitContext ec)
4160                 {
4161                         DoEmit (ec, true);
4162                 }
4163                 
4164                 public override void EmitStatement (EmitContext ec)
4165                 {
4166                         if (DoEmit (ec, false))
4167                                 ec.ig.Emit (OpCodes.Pop);
4168                 }
4169         }
4170
4171         /// <summary>
4172         ///   14.5.10.2: Represents an array creation expression.
4173         /// </summary>
4174         ///
4175         /// <remarks>
4176         ///   There are two possible scenarios here: one is an array creation
4177         ///   expression that specifies the dimensions and optionally the
4178         ///   initialization data and the other which does not need dimensions
4179         ///   specified but where initialization data is mandatory.
4180         /// </remarks>
4181         public class ArrayCreation : ExpressionStatement {
4182                 string requested_type, rank;
4183                 ArrayList initializers;
4184                 Location loc;
4185
4186                 //
4187                 // The list of Argument types.
4188                 // This is used to construct the `newarray' or constructor signature
4189                 //
4190                 ArrayList arguments;
4191
4192                 //
4193                 // Method used to create the array object.
4194                 //
4195                 MethodBase new_method = null;
4196                 
4197                 Type array_element_type;
4198                 Type underlying_type;
4199                 bool is_one_dimensional = false;
4200                 bool is_builtin_type = false;
4201                 bool expect_initializers = false;
4202                 int dimensions = 0;
4203
4204                 ArrayList array_data;
4205
4206                 Hashtable bounds;
4207
4208                 //
4209                 // The number of array initializers that we can handle
4210                 // via the InitializeArray method - through EmitStaticInitializers
4211                 //
4212                 int num_automatic_initializers;
4213                 
4214                 public ArrayCreation (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
4215                 {
4216                         this.requested_type = requested_type;
4217                         this.initializers = initializers;
4218                         this.rank = rank;
4219                         loc = l;
4220
4221                         arguments = new ArrayList ();
4222
4223                         foreach (Expression e in exprs)
4224                                 arguments.Add (new Argument (e, Argument.AType.Expression));
4225                 }
4226
4227                 public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)
4228                 {
4229                         this.requested_type = requested_type;
4230                         this.initializers = initializers;
4231                         loc = l;
4232
4233                         this.rank = rank.Substring (0, rank.LastIndexOf ("["));
4234
4235                         string tmp = rank.Substring (rank.LastIndexOf ("["));
4236
4237                         dimensions = tmp.Length - 1;
4238                         expect_initializers = true;
4239                 }
4240
4241                 public static string FormArrayType (string base_type, int idx_count, string rank)
4242                 {
4243                         StringBuilder sb = new StringBuilder (base_type);
4244
4245                         sb.Append (rank);
4246                         
4247                         sb.Append ("[");
4248                         for (int i = 1; i < idx_count; i++)
4249                                 sb.Append (",");
4250                         
4251                         sb.Append ("]");
4252
4253                         return sb.ToString ();
4254                 }
4255
4256                 public static string FormElementType (string base_type, int idx_count, string rank)
4257                 {
4258                         StringBuilder sb = new StringBuilder (base_type);
4259                         
4260                         sb.Append ("[");
4261                         for (int i = 1; i < idx_count; i++)
4262                                 sb.Append (",");
4263                         
4264                         sb.Append ("]");
4265                         
4266                         sb.Append (rank);
4267
4268                         string val = sb.ToString ();
4269
4270                         return val.Substring (0, val.LastIndexOf ("["));
4271                 }
4272
4273                 void error178 ()
4274                 {
4275                         Report.Error (178, loc, "Incorrectly structured array initializer");
4276                 }
4277                 
4278                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
4279                 {
4280                         if (specified_dims) { 
4281                                 Argument a = (Argument) arguments [idx];
4282                                 
4283                                 if (!a.Resolve (ec, loc))
4284                                         return false;
4285                                 
4286                                 if (!(a.Expr is Constant)) {
4287                                         Report.Error (150, loc, "A constant value is expected");
4288                                         return false;
4289                                 }
4290                                 
4291                                 int value = (int) ((Constant) a.Expr).GetValue ();
4292                                 
4293                                 if (value != probe.Count) {
4294                                         error178 ();
4295                                         return false;
4296                                 }
4297                                 
4298                                 bounds [idx] = value;
4299                         }
4300                         
4301                         foreach (object o in probe) {
4302                                 if (o is ArrayList) {
4303                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
4304                                         if (!ret)
4305                                                 return false;
4306                                 } else {
4307                                         Expression tmp = (Expression) o;
4308                                         tmp = tmp.Resolve (ec);
4309                                         if (tmp == null)
4310                                                 continue;
4311
4312                                         // Console.WriteLine ("I got: " + tmp);
4313                                         // Handle initialization from vars, fields etc.
4314
4315                                         Expression conv = ConvertImplicitRequired (
4316                                                 ec, tmp, underlying_type, loc);
4317                                         
4318                                         if (conv == null) 
4319                                                 return false;
4320
4321                                         if (conv is StringConstant)
4322                                                 array_data.Add (conv);
4323                                         else if (conv is Constant) {
4324                                                 array_data.Add (conv);
4325                                                 num_automatic_initializers++;
4326                                         } else
4327                                                 array_data.Add (conv);
4328                                 }
4329                         }
4330
4331                         return true;
4332                 }
4333                 
4334                 public void UpdateIndices (EmitContext ec)
4335                 {
4336                         int i = 0;
4337                         for (ArrayList probe = initializers; probe != null;) {
4338                                 if (probe.Count > 0 && probe [0] is ArrayList) {
4339                                         Expression e = new IntConstant (probe.Count);
4340                                         arguments.Add (new Argument (e, Argument.AType.Expression));
4341
4342                                         bounds [i++] =  probe.Count;
4343                                         
4344                                         probe = (ArrayList) probe [0];
4345                                         
4346                                 } else {
4347                                         Expression e = new IntConstant (probe.Count);
4348                                         arguments.Add (new Argument (e, Argument.AType.Expression));
4349
4350                                         bounds [i++] = probe.Count;
4351                                         probe = null;
4352                                 }
4353                         }
4354
4355                 }
4356                 
4357                 public bool ValidateInitializers (EmitContext ec)
4358                 {
4359                         if (initializers == null) {
4360                                 if (expect_initializers)
4361                                         return false;
4362                                 else
4363                                         return true;
4364                         }
4365                         
4366                         underlying_type = RootContext.LookupType (
4367                                 ec.DeclSpace, requested_type, false, loc);
4368
4369                         if (underlying_type == null)
4370                                 return false;
4371                         
4372                         //
4373                         // We use this to store all the date values in the order in which we
4374                         // will need to store them in the byte blob later
4375                         //
4376                         array_data = new ArrayList ();
4377                         bounds = new Hashtable ();
4378                         
4379                         bool ret;
4380
4381                         if (arguments != null) {
4382                                 ret = CheckIndices (ec, initializers, 0, true);
4383                                 return ret;
4384                         } else {
4385                                 arguments = new ArrayList ();
4386
4387                                 ret = CheckIndices (ec, initializers, 0, false);
4388                                 
4389                                 if (!ret)
4390                                         return false;
4391                                 
4392                                 UpdateIndices (ec);
4393                                 
4394                                 if (arguments.Count != dimensions) {
4395                                         error178 ();
4396                                         return false;
4397                                 }
4398
4399                                 return ret;
4400                         }
4401                 }
4402
4403                 void Error_NegativeArrayIndex ()
4404                 {
4405                         Report.Error (284, loc, "Can not create array with a negative size");
4406                 }
4407                 
4408                 //
4409                 // Converts `source' to an int, uint, long or ulong.
4410                 //
4411                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
4412                 {
4413                         Expression target;
4414                         
4415                         bool old_checked = ec.CheckState;
4416                         ec.CheckState = true;
4417                         
4418                         target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
4419                         if (target == null){
4420                                 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
4421                                 if (target == null){
4422                                         target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
4423                                         if (target == null){
4424                                                 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
4425                                                 if (target == null)
4426                                                         Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
4427                                         }
4428                                 }
4429                         } 
4430                         ec.CheckState = old_checked;
4431
4432                         //
4433                         // Only positive constants are allowed at compile time
4434                         //
4435                         if (target is Constant){
4436                                 if (target is IntConstant){
4437                                         if (((IntConstant) target).Value < 0){
4438                                                 Error_NegativeArrayIndex ();
4439                                                 return null;
4440                                         }
4441                                 }
4442
4443                                 if (target is LongConstant){
4444                                         if (((LongConstant) target).Value < 0){
4445                                                 Error_NegativeArrayIndex ();
4446                                                 return null;
4447                                         }
4448                                 }
4449                                 
4450                         }
4451
4452                         return target;
4453                 }
4454                 
4455                 public override Expression DoResolve (EmitContext ec)
4456                 {
4457                         int arg_count;
4458
4459                         //
4460                         // First step is to validate the initializers and fill
4461                         // in any missing bits
4462                         //
4463                         if (!ValidateInitializers (ec))
4464                                 return null;
4465
4466                         if (arguments == null)
4467                                 arg_count = 0;
4468                         else {
4469                                 arg_count = arguments.Count;
4470                                 foreach (Argument a in arguments){
4471                                         if (!a.Resolve (ec, loc))
4472                                                 return null;
4473
4474                                         Expression real_arg = ExpressionToArrayArgument (ec, a.expr);
4475                                         if (real_arg == null)
4476                                                 return null;
4477
4478                                         a.expr = real_arg;
4479                                 }
4480                         }
4481                         
4482                         string array_type = FormArrayType (requested_type, arg_count, rank);
4483                         string element_type = FormElementType (requested_type, arg_count, rank);
4484
4485                         type = RootContext.LookupType (ec.DeclSpace, array_type, false, loc);
4486                         
4487                         array_element_type = RootContext.LookupType (
4488                                 ec.DeclSpace, element_type, false, loc);
4489                         
4490                         if (type == null)
4491                                 return null;
4492                         
4493                         if (arg_count == 1) {
4494                                 is_one_dimensional = true;
4495                                 eclass = ExprClass.Value;
4496                                 return this;
4497                         }
4498
4499                         is_builtin_type = TypeManager.IsBuiltinType (type);
4500                         
4501                         if (is_builtin_type) {
4502                                 Expression ml;
4503                                 
4504                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
4505                                                    AllBindingFlags, loc);
4506                                 
4507                                 if (!(ml is MethodGroupExpr)) {
4508                                         report118 (loc, ml, "method group");
4509                                         return null;
4510                                 }
4511                                 
4512                                 if (ml == null) {
4513                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4514                                                       "this argument list");
4515                                         return null;
4516                                 }
4517                                 
4518                                 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
4519
4520                                 if (new_method == null) {
4521                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4522                                                       "this argument list");
4523                                         return null;
4524                                 }
4525                                 
4526                                 eclass = ExprClass.Value;
4527                                 return this;
4528                         } else {
4529                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
4530                                 ArrayList args = new ArrayList ();
4531                                 
4532                                 if (arguments != null) {
4533                                         for (int i = 0; i < arg_count; i++)
4534                                                 args.Add (TypeManager.int32_type);
4535                                 }
4536                                 
4537                                 Type [] arg_types = null;
4538
4539                                 if (args.Count > 0)
4540                                         arg_types = new Type [args.Count];
4541                                 
4542                                 args.CopyTo (arg_types, 0);
4543                                 
4544                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
4545                                                             arg_types);
4546
4547                                 if (new_method == null) {
4548                                         Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4549                                                       "this argument list");
4550                                         return null;
4551                                 }
4552                                 
4553                                 eclass = ExprClass.Value;
4554                                 return this;
4555                         }
4556                 }
4557
4558                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
4559                 {
4560                         int factor;
4561                         byte [] data;
4562                         byte [] element;
4563                         int count = array_data.Count;
4564
4565                         factor = GetTypeSize (underlying_type);
4566                         if (factor == 0)
4567                                 return null;
4568
4569                         data = new byte [(count * factor + 4) & ~3];
4570                         int idx = 0;
4571                         
4572                         for (int i = 0; i < count; ++i) {
4573                                 object v = array_data [i];
4574
4575                                 if (v is EnumConstant)
4576                                         v = ((EnumConstant) v).Child;
4577                                 
4578                                 if (v is Constant && !(v is StringConstant))
4579                                         v = ((Constant) v).GetValue ();
4580                                 else {
4581                                         idx += factor;
4582                                         continue;
4583                                 }
4584                                 
4585                                 if (underlying_type == TypeManager.int64_type){
4586                                         if (!(v is Expression)){
4587                                                 long val = (long) v;
4588                                                 
4589                                                 for (int j = 0; j < factor; ++j) {
4590                                                         data [idx + j] = (byte) (val & 0xFF);
4591                                                         val = (val >> 8);
4592                                                 }
4593                                         }
4594                                 } else if (underlying_type == TypeManager.uint64_type){
4595                                         if (!(v is Expression)){
4596                                                 ulong val = (ulong) v;
4597
4598                                                 for (int j = 0; j < factor; ++j) {
4599                                                         data [idx + j] = (byte) (val & 0xFF);
4600                                                         val = (val >> 8);
4601                                                 }
4602                                         }
4603                                 } else if (underlying_type == TypeManager.float_type) {
4604                                         if (!(v is Expression)){
4605                                                 element = BitConverter.GetBytes ((float) v);
4606                                                         
4607                                                 for (int j = 0; j < factor; ++j)
4608                                                         data [idx + j] = element [j];
4609                                         }
4610                                 } else if (underlying_type == TypeManager.double_type) {
4611                                         if (!(v is Expression)){
4612                                                 element = BitConverter.GetBytes ((double) v);
4613
4614                                                 for (int j = 0; j < factor; ++j)
4615                                                         data [idx + j] = element [j];
4616                                         }
4617                                 } else if (underlying_type == TypeManager.char_type){
4618                                         if (!(v is Expression)){
4619                                                 int val = (int) ((char) v);
4620                                                 
4621                                                 data [idx] = (byte) (val & 0xff);
4622                                                 data [idx+1] = (byte) (val >> 8);
4623                                         }
4624                                 } else if (underlying_type == TypeManager.short_type){
4625                                         if (!(v is Expression)){
4626                                                 int val = (int) ((short) v);
4627                                         
4628                                                 data [idx] = (byte) (val & 0xff);
4629                                                 data [idx+1] = (byte) (val >> 8);
4630                                         }
4631                                 } else if (underlying_type == TypeManager.ushort_type){
4632                                         if (!(v is Expression)){
4633                                                 int val = (int) ((ushort) v);
4634                                         
4635                                                 data [idx] = (byte) (val & 0xff);
4636                                                 data [idx+1] = (byte) (val >> 8);
4637                                         }
4638                                 } else if (underlying_type == TypeManager.int32_type) {
4639                                         if (!(v is Expression)){
4640                                                 int val = (int) v;
4641                                         
4642                                                 data [idx]   = (byte) (val & 0xff);
4643                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4644                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4645                                                 data [idx+3] = (byte) (val >> 24);
4646                                         }
4647                                 } else if (underlying_type == TypeManager.uint32_type) {
4648                                         if (!(v is Expression)){
4649                                                 uint val = (uint) v;
4650                                         
4651                                                 data [idx]   = (byte) (val & 0xff);
4652                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4653                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4654                                                 data [idx+3] = (byte) (val >> 24);
4655                                         }
4656                                 } else if (underlying_type == TypeManager.sbyte_type) {
4657                                         if (!(v is Expression)){
4658                                                 sbyte val = (sbyte) v;
4659                                                 data [idx] = (byte) val;
4660                                         }
4661                                 } else if (underlying_type == TypeManager.byte_type) {
4662                                         if (!(v is Expression)){
4663                                                 byte val = (byte) v;
4664                                                 data [idx] = (byte) val;
4665                                         }
4666                                 } else if (underlying_type == TypeManager.bool_type) {
4667                                         if (!(v is Expression)){
4668                                                 bool val = (bool) v;
4669                                                 data [idx] = (byte) (val ? 1 : 0);
4670                                         }
4671                                 } else
4672                                         throw new Exception ("Unrecognized type in MakeByteBlob");
4673
4674                                 idx += factor;
4675                         }
4676
4677                         return data;
4678                 }
4679
4680                 //
4681                 // Emits the initializers for the array
4682                 //
4683                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
4684                 {
4685                         //
4686                         // First, the static data
4687                         //
4688                         FieldBuilder fb;
4689                         ILGenerator ig = ec.ig;
4690                         
4691                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
4692                         
4693                         if (data != null) {
4694                                 fb = RootContext.MakeStaticData (data);
4695
4696                                 if (is_expression)
4697                                         ig.Emit (OpCodes.Dup);
4698                                 ig.Emit (OpCodes.Ldtoken, fb);
4699                                 ig.Emit (OpCodes.Call,
4700                                          TypeManager.void_initializearray_array_fieldhandle);
4701                         }
4702                 }
4703                 
4704                 //
4705                 // Emits pieces of the array that can not be computed at compile
4706                 // time (variables and string locations).
4707                 //
4708                 // This always expect the top value on the stack to be the array
4709                 //
4710                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
4711                 {
4712                         ILGenerator ig = ec.ig;
4713                         int dims = bounds.Count;
4714                         int [] current_pos = new int [dims];
4715                         int top = array_data.Count;
4716                         LocalBuilder temp = ig.DeclareLocal (type);
4717
4718                         ig.Emit (OpCodes.Stloc, temp);
4719
4720                         MethodInfo set = null;
4721
4722                         if (dims != 1){
4723                                 Type [] args;
4724                                 ModuleBuilder mb = null;
4725                                 mb = CodeGen.ModuleBuilder;
4726                                 args = new Type [dims + 1];
4727
4728                                 int j;
4729                                 for (j = 0; j < dims; j++)
4730                                         args [j] = TypeManager.int32_type;
4731
4732                                 args [j] = array_element_type;
4733                                 
4734                                 set = mb.GetArrayMethod (
4735                                         type, "Set",
4736                                         CallingConventions.HasThis | CallingConventions.Standard,
4737                                         TypeManager.void_type, args);
4738                         }
4739                         
4740                         for (int i = 0; i < top; i++){
4741
4742                                 Expression e = null;
4743
4744                                 if (array_data [i] is Expression)
4745                                         e = (Expression) array_data [i];
4746
4747                                 if (e != null) {
4748                                         //
4749                                         // Basically we do this for string literals and
4750                                         // other non-literal expressions
4751                                         //
4752                                         if (e is StringConstant || !(e is Constant) ||
4753                                             num_automatic_initializers <= 2) {
4754                                                 Type etype = e.Type;
4755                                                 
4756                                                 ig.Emit (OpCodes.Ldloc, temp);
4757
4758                                                 for (int idx = dims; idx > 0; ) {
4759                                                         idx--;
4760                                                         IntConstant.EmitInt (ig, current_pos [idx]);
4761                                                 }
4762
4763                                                 //
4764                                                 // If we are dealing with a struct, get the
4765                                                 // address of it, so we can store it.
4766                                                 //
4767                                                 if (etype.IsSubclassOf (TypeManager.value_type) &&
4768                                                     !TypeManager.IsBuiltinType (etype)){
4769                                                         if (e is New){
4770                                                                 New n = (New) e;
4771
4772                                                                 //
4773                                                                 // Let new know that we are providing
4774                                                                 // the address where to store the results
4775                                                                 //
4776                                                                 n.DisableTemporaryValueType ();
4777                                                         }
4778                                                                              
4779                                                         ig.Emit (OpCodes.Ldelema, etype);
4780                                                 }
4781                                                     
4782                                                 e.Emit (ec);
4783                                                 
4784                                                 if (dims == 1)
4785                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
4786                                                 else 
4787                                                         ig.Emit (OpCodes.Call, set);
4788                                         }
4789                                 }
4790                                 
4791                                 //
4792                                 // Advance counter
4793                                 //
4794                                 for (int j = 0; j < dims; j++){
4795                                         current_pos [j]++;
4796                                         if (current_pos [j] < (int) bounds [j])
4797                                                 break;
4798                                         current_pos [j] = 0;
4799                                 }
4800                         }
4801
4802                         if (is_expression)
4803                                 ig.Emit (OpCodes.Ldloc, temp);
4804                 }
4805
4806                 void EmitArrayArguments (EmitContext ec)
4807                 {
4808                         foreach (Argument a in arguments)
4809                                 a.Emit (ec);
4810                 }
4811                 
4812                 void DoEmit (EmitContext ec, bool is_statement)
4813                 {
4814                         ILGenerator ig = ec.ig;
4815                         
4816                         EmitArrayArguments (ec);
4817                         if (is_one_dimensional)
4818                                 ig.Emit (OpCodes.Newarr, array_element_type);
4819                         else {
4820                                 if (is_builtin_type) 
4821                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
4822                                 else 
4823                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
4824                         }
4825                         
4826                         if (initializers != null){
4827                                 //
4828                                 // FIXME: Set this variable correctly.
4829                                 // 
4830                                 bool dynamic_initializers = true;
4831
4832                                 if (underlying_type != TypeManager.string_type &&
4833                                     underlying_type != TypeManager.object_type) {
4834                                         if (num_automatic_initializers > 2)
4835                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
4836                                 }
4837                                 
4838                                 if (dynamic_initializers)
4839                                         EmitDynamicInitializers (ec, !is_statement);
4840                         }
4841                 }
4842                 
4843                 public override void Emit (EmitContext ec)
4844                 {
4845                         DoEmit (ec, false);
4846                 }
4847
4848                 public override void EmitStatement (EmitContext ec)
4849                 {
4850                         DoEmit (ec, true);
4851                 }
4852                 
4853         }
4854         
4855         /// <summary>
4856         ///   Represents the `this' construct
4857         /// </summary>
4858         public class This : Expression, IAssignMethod, IMemoryLocation {
4859                 Location loc;
4860                 
4861                 public This (Location loc)
4862                 {
4863                         this.loc = loc;
4864                 }
4865
4866                 public override Expression DoResolve (EmitContext ec)
4867                 {
4868                         eclass = ExprClass.Variable;
4869                         type = ec.ContainerType;
4870
4871                         if (ec.IsStatic){
4872                                 Report.Error (26, loc,
4873                                               "Keyword this not valid in static code");
4874                                 return null;
4875                         }
4876                         
4877                         return this;
4878                 }
4879
4880                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4881                 {
4882                         DoResolve (ec);
4883                         
4884                         if (ec.TypeContainer is Class){
4885                                 Report.Error (1604, loc, "Cannot assign to `this'");
4886                                 return null;
4887                         }
4888
4889                         return this;
4890                 }
4891
4892                 public override void Emit (EmitContext ec)
4893                 {
4894                         ec.ig.Emit (OpCodes.Ldarg_0);
4895                 }
4896
4897                 public void EmitAssign (EmitContext ec, Expression source)
4898                 {
4899                         source.Emit (ec);
4900                         ec.ig.Emit (OpCodes.Starg, 0);
4901                 }
4902
4903                 public void AddressOf (EmitContext ec, AddressOp mode)
4904                 {
4905                         ec.ig.Emit (OpCodes.Ldarg_0);
4906
4907                         // FIMXE
4908                         // FIGURE OUT WHY LDARG_S does not work
4909                         //
4910                         // consider: struct X { int val; int P { set { val = value; }}}
4911                         //
4912                         // Yes, this looks very bad. Look at `NOTAS' for
4913                         // an explanation.
4914                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4915                 }
4916         }
4917
4918         /// <summary>
4919         ///   Implements the typeof operator
4920         /// </summary>
4921         public class TypeOf : Expression {
4922                 public readonly string QueriedType;
4923                 Type typearg;
4924                 Location loc;
4925                 
4926                 public TypeOf (string queried_type, Location l)
4927                 {
4928                         QueriedType = queried_type;
4929                         loc = l;
4930                 }
4931
4932                 public override Expression DoResolve (EmitContext ec)
4933                 {
4934                         typearg = RootContext.LookupType (
4935                                 ec.DeclSpace, QueriedType, false, loc);
4936
4937                         if (typearg == null)
4938                                 return null;
4939
4940                         type = TypeManager.type_type;
4941                         eclass = ExprClass.Type;
4942                         return this;
4943                 }
4944
4945                 public override void Emit (EmitContext ec)
4946                 {
4947                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
4948                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4949                 }
4950
4951                 public Type TypeArg { 
4952                         get { return typearg; }
4953                 }
4954         }
4955
4956         /// <summary>
4957         ///   Implements the sizeof expression
4958         /// </summary>
4959         public class SizeOf : Expression {
4960                 public readonly string QueriedType;
4961                 Type type_queried;
4962                 Location loc;
4963                 
4964                 public SizeOf (string queried_type, Location l)
4965                 {
4966                         this.QueriedType = queried_type;
4967                         loc = l;
4968                 }
4969
4970                 public override Expression DoResolve (EmitContext ec)
4971                 {
4972                         type_queried = RootContext.LookupType (
4973                                 ec.DeclSpace, QueriedType, false, loc);
4974                         if (type_queried == null)
4975                                 return null;
4976
4977                         type = TypeManager.int32_type;
4978                         eclass = ExprClass.Value;
4979                         return this;
4980                 }
4981
4982                 public override void Emit (EmitContext ec)
4983                 {
4984                         int size = GetTypeSize (type_queried);
4985
4986                         if (size == 0)
4987                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
4988                         else
4989                                 IntConstant.EmitInt (ec.ig, size);
4990                 }
4991         }
4992
4993         /// <summary>
4994         ///   Implements the member access expression
4995         /// </summary>
4996         public class MemberAccess : Expression {
4997                 public readonly string Identifier;
4998                 Expression expr;
4999                 Expression member_lookup;
5000                 Location loc;
5001                 
5002                 public MemberAccess (Expression expr, string id, Location l)
5003                 {
5004                         this.expr = expr;
5005                         Identifier = id;
5006                         loc = l;
5007                 }
5008
5009                 public Expression Expr {
5010                         get {
5011                                 return expr;
5012                         }
5013                 }
5014
5015                 static void error176 (Location loc, string name)
5016                 {
5017                         Report.Error (176, loc, "Static member `" +
5018                                       name + "' cannot be accessed " +
5019                                       "with an instance reference, qualify with a " +
5020                                       "type name instead");
5021                 }
5022
5023                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
5024                 {
5025                         if (left_original == null)
5026                                 return false;
5027
5028                         if (!(left_original is SimpleName))
5029                                 return false;
5030
5031                         SimpleName sn = (SimpleName) left_original;
5032
5033                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
5034                         if (t != null)
5035                                 return true;
5036
5037                         return false;
5038                 }
5039                 
5040                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
5041                                                               Expression left, Location loc,
5042                                                               Expression left_original)
5043                 {
5044                         //
5045                         // Method Groups
5046                         //
5047                         if (member_lookup is MethodGroupExpr){
5048                                 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
5049
5050                                 //
5051                                 // Type.MethodGroup
5052                                 //
5053                                 if (left is TypeExpr){
5054                                         if (!mg.RemoveInstanceMethods ()){
5055                                                 SimpleName.Error120 (loc, mg.Methods [0].Name); 
5056                                                 return null;
5057                                         }
5058
5059                                         return member_lookup;
5060                                 }
5061
5062                                 //
5063                                 // Instance.MethodGroup
5064                                 //
5065                                 if (IdenticalNameAndTypeName (ec, left_original, loc)){
5066                                         if (mg.RemoveInstanceMethods ())
5067                                                 return member_lookup;
5068                                 }
5069                                 
5070                                 if (!mg.RemoveStaticMethods ()){
5071                                         error176 (loc, mg.Methods [0].Name);
5072                                         return null;
5073                                 } 
5074                                 
5075                                 mg.InstanceExpression = left;
5076                                 return member_lookup;
5077 #if ORIGINAL
5078                                 if (!mg.RemoveStaticMethods ()){
5079                                         if (IdenticalNameAndTypeName (ec, left_original, loc)){
5080                                                 if (!mg.RemoveInstanceMethods ()){
5081                                                         SimpleName.Error120 (loc, mg.Methods [0].Name);
5082                                                         return null;
5083                                                 }
5084                                                 return member_lookup;
5085                                         }
5086                                         
5087                                         error176 (loc, mg.Methods [0].Name);
5088                                         return null;
5089                                 }
5090                                 
5091                                 mg.InstanceExpression = left;
5092                                         
5093                                 return member_lookup;
5094 #endif
5095                         }
5096
5097                         if (member_lookup is FieldExpr){
5098                                 FieldExpr fe = (FieldExpr) member_lookup;
5099                                 FieldInfo fi = fe.FieldInfo;
5100                                 Type decl_type = fi.DeclaringType;
5101                                 
5102                                 if (fi is FieldBuilder) {
5103                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
5104                                         
5105                                         if (c != null) {
5106                                                 object o = c.LookupConstantValue (ec);
5107                                                 object real_value = ((Constant) c.Expr).GetValue ();
5108
5109                                                 return Constantify (real_value, fi.FieldType);
5110                                         }
5111                                 }
5112
5113                                 if (fi.IsLiteral) {
5114                                         Type t = fi.FieldType;
5115                                         
5116                                         object o;
5117
5118                                         if (fi is FieldBuilder)
5119                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
5120                                         else
5121                                                 o = fi.GetValue (fi);
5122                                         
5123                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
5124                                                 Expression enum_member = MemberLookup (
5125                                                         ec, decl_type, "value__", MemberTypes.Field,
5126                                                         AllBindingFlags, loc); 
5127
5128                                                 Enum en = TypeManager.LookupEnum (decl_type);
5129
5130                                                 Constant c;
5131                                                 if (en != null)
5132                                                         c = Constantify (o, en.UnderlyingType);
5133                                                 else 
5134                                                         c = Constantify (o, enum_member.Type);
5135                                                 
5136                                                 return new EnumConstant (c, decl_type);
5137                                         }
5138                                         
5139                                         Expression exp = Constantify (o, t);
5140
5141                                         if (!(left is TypeExpr)) {
5142                                                 error176 (loc, fe.FieldInfo.Name);
5143                                                 return null;
5144                                         }
5145                                         
5146                                         return exp;
5147                                 }
5148
5149                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
5150                                         UnsafeError (loc);
5151                                         return null;
5152                                 }
5153                                 
5154                                 if (left is TypeExpr){
5155                                         // and refers to a type name or an 
5156                                         if (!fe.FieldInfo.IsStatic){
5157                                                 error176 (loc, fe.FieldInfo.Name);
5158                                                 return null;
5159                                         }
5160                                         return member_lookup;
5161                                 } else {
5162                                         if (fe.FieldInfo.IsStatic){
5163                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5164                                                         return member_lookup;
5165
5166                                                 error176 (loc, fe.FieldInfo.Name);
5167                                                 return null;
5168                                         }
5169                                         fe.InstanceExpression = left;
5170
5171                                         return fe;
5172                                 }
5173                         }
5174
5175                         if (member_lookup is PropertyExpr){
5176                                 PropertyExpr pe = (PropertyExpr) member_lookup;
5177
5178                                 if (left is TypeExpr){
5179                                         if (!pe.IsStatic){
5180                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
5181                                                 return null;
5182                                         }
5183                                         return pe;
5184                                 } else {
5185                                         if (pe.IsStatic){
5186                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5187                                                         return member_lookup;
5188                                                 error176 (loc, pe.PropertyInfo.Name);
5189                                                 return null;
5190                                         }
5191                                         pe.InstanceExpression = left;
5192                                         
5193                                         return pe;
5194                                 }
5195                         }
5196
5197                         if (member_lookup is EventExpr) {
5198
5199                                 EventExpr ee = (EventExpr) member_lookup;
5200                                 
5201                                 //
5202                                 // If the event is local to this class, we transform ourselves into
5203                                 // a FieldExpr
5204                                 //
5205
5206                                 Expression ml = MemberLookup (
5207                                         ec, ec.ContainerType,
5208                                         ee.EventInfo.Name, MemberTypes.Event, AllBindingFlags, loc);
5209
5210                                 if (ml != null) {
5211                                         MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
5212
5213                                         if (mi == null) {
5214                                                 //
5215                                                 // If this happens, then we have an event with its own
5216                                                 // accessors and private field etc so there's no need
5217                                                 // to transform ourselves : we should instead flag an error
5218                                                 //
5219                                                 Assign.error70 (ee.EventInfo, loc);
5220                                                 return null;
5221                                         }
5222
5223                                         ml = ExprClassFromMemberInfo (ec, mi, loc);
5224                                         
5225                                         if (ml == null) {
5226                                                 Report.Error (-200, loc, "Internal error!!");
5227                                                 return null;
5228                                         }
5229                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
5230                                 }
5231
5232                                 if (left is TypeExpr) {
5233                                         if (!ee.IsStatic) {
5234                                                 SimpleName.Error120 (loc, ee.EventInfo.Name);
5235                                                 return null;
5236                                         }
5237
5238                                         return ee;
5239
5240                                 } else {
5241                                         if (ee.IsStatic) {
5242                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5243                                                         return ee;
5244                                                     
5245                                                 error176 (loc, ee.EventInfo.Name);
5246                                                 return null;
5247                                         }
5248
5249                                         ee.InstanceExpression = left;
5250
5251                                         return ee;
5252                                 }
5253                         }
5254
5255                         if (member_lookup is TypeExpr){
5256                                 member_lookup.Resolve (ec);
5257                                 return member_lookup;
5258                         }
5259                         
5260                         Console.WriteLine ("Left is: " + left);
5261                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
5262                         Environment.Exit (0);
5263                         return null;
5264                 }
5265                 
5266                 public override Expression DoResolve (EmitContext ec)
5267                 {
5268                         //
5269                         // We are the sole users of ResolveWithSimpleName (ie, the only
5270                         // ones that can cope with it
5271                         //
5272                         Expression original = expr;
5273                         expr = expr.ResolveWithSimpleName (ec);
5274
5275                         if (expr == null)
5276                                 return null;
5277
5278                         if (expr is SimpleName){
5279                                 SimpleName child_expr = (SimpleName) expr;
5280                                 
5281                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
5282
5283                                 return expr.ResolveWithSimpleName (ec);
5284                         }
5285                                         
5286                         //
5287                         // TODO: I mailed Ravi about this, and apparently we can get rid
5288                         // of this and put it in the right place.
5289                         // 
5290                         // Handle enums here when they are in transit.
5291                         // Note that we cannot afford to hit MemberLookup in this case because
5292                         // it will fail to find any members at all
5293                         //
5294
5295                         Type expr_type = expr.Type;
5296                         if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
5297                                 
5298                                 Enum en = TypeManager.LookupEnum (expr_type);
5299                                 
5300                                 if (en != null) {
5301                                         object value = en.LookupEnumValue (ec, Identifier, loc);
5302
5303                                         if (value != null){
5304                                                 Constant c = Constantify (value, en.UnderlyingType);
5305                                                 return new EnumConstant (c, expr_type);
5306                                         }
5307                                 }
5308                         }
5309
5310                         if (expr_type.IsPointer){
5311                                 Report.Error (23, loc,
5312                                               "The `.' operator can not be applied to pointer operands (" +
5313                                               TypeManager.CSharpName (expr_type) + ")");
5314                                 return null;
5315                         }
5316                         
5317                         member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
5318
5319                         if (member_lookup == null){
5320                                 //
5321                                 // Try looking the member up from the same type, if we find
5322                                 // it, we know that the error was due to limited visibility
5323                                 //
5324                                 object lookup = TypeManager.MemberLookup (
5325                                         expr_type, expr_type, AllMemberTypes, AllBindingFlags, Identifier);
5326                                 if (lookup == null)
5327                                         Report.Error (117, loc, "`" + expr_type + "' does not contain a " +
5328                                                       "definition for `" + Identifier + "'");
5329                                 else
5330                                         Report.Error (122, loc, "`" + expr_type + "." + Identifier + "' " +
5331                                                       "is inaccessible because of its protection level");
5332                                               
5333                                 return null;
5334                         }
5335
5336                         return ResolveMemberAccess (ec, member_lookup, expr, loc, original);
5337                 }
5338
5339                 public override void Emit (EmitContext ec)
5340                 {
5341                         throw new Exception ("Should not happen");
5342                 }
5343         }
5344
5345         /// <summary>
5346         ///   Implements checked expressions
5347         /// </summary>
5348         public class CheckedExpr : Expression {
5349
5350                 public Expression Expr;
5351
5352                 public CheckedExpr (Expression e)
5353                 {
5354                         Expr = e;
5355                 }
5356
5357                 public override Expression DoResolve (EmitContext ec)
5358                 {
5359                         bool last_const_check = ec.ConstantCheckState;
5360
5361                         ec.ConstantCheckState = true;
5362                         Expr = Expr.Resolve (ec);
5363                         ec.ConstantCheckState = last_const_check;
5364                         
5365                         if (Expr == null)
5366                                 return null;
5367
5368                         eclass = Expr.eclass;
5369                         type = Expr.Type;
5370                         return this;
5371                 }
5372
5373                 public override void Emit (EmitContext ec)
5374                 {
5375                         bool last_check = ec.CheckState;
5376                         bool last_const_check = ec.ConstantCheckState;
5377                         
5378                         ec.CheckState = true;
5379                         ec.ConstantCheckState = true;
5380                         Expr.Emit (ec);
5381                         ec.CheckState = last_check;
5382                         ec.ConstantCheckState = last_const_check;
5383                 }
5384                 
5385         }
5386
5387         /// <summary>
5388         ///   Implements the unchecked expression
5389         /// </summary>
5390         public class UnCheckedExpr : Expression {
5391
5392                 public Expression Expr;
5393
5394                 public UnCheckedExpr (Expression e)
5395                 {
5396                         Expr = e;
5397                 }
5398
5399                 public override Expression DoResolve (EmitContext ec)
5400                 {
5401                         bool last_const_check = ec.ConstantCheckState;
5402
5403                         ec.ConstantCheckState = false;
5404                         Expr = Expr.Resolve (ec);
5405                         ec.ConstantCheckState = last_const_check;
5406
5407                         if (Expr == null)
5408                                 return null;
5409
5410                         eclass = Expr.eclass;
5411                         type = Expr.Type;
5412                         return this;
5413                 }
5414
5415                 public override void Emit (EmitContext ec)
5416                 {
5417                         bool last_check = ec.CheckState;
5418                         bool last_const_check = ec.ConstantCheckState;
5419                         
5420                         ec.CheckState = false;
5421                         ec.ConstantCheckState = false;
5422                         Expr.Emit (ec);
5423                         ec.CheckState = last_check;
5424                         ec.ConstantCheckState = last_const_check;
5425                 }
5426                 
5427         }
5428
5429         /// <summary>
5430         ///   An Element Access expression.
5431         ///
5432         ///   During semantic analysis these are transformed into 
5433         ///   IndexerAccess or ArrayAccess 
5434         /// </summary>
5435         public class ElementAccess : Expression {
5436                 public ArrayList  Arguments;
5437                 public Expression Expr;
5438                 public Location   loc;
5439                 
5440                 public ElementAccess (Expression e, ArrayList e_list, Location l)
5441                 {
5442                         Expr = e;
5443
5444                         loc  = l;
5445                         
5446                         if (e_list == null)
5447                                 return;
5448                         
5449                         Arguments = new ArrayList ();
5450                         foreach (Expression tmp in e_list)
5451                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
5452                         
5453                 }
5454
5455                 bool CommonResolve (EmitContext ec)
5456                 {
5457                         Expr = Expr.Resolve (ec);
5458
5459                         if (Expr == null) 
5460                                 return false;
5461
5462                         if (Arguments == null)
5463                                 return false;
5464
5465                         foreach (Argument a in Arguments){
5466                                 if (!a.Resolve (ec, loc))
5467                                         return false;
5468                         }
5469
5470                         return true;
5471                 }
5472
5473                 Expression MakePointerAccess ()
5474                 {
5475                         Type t = Expr.Type;
5476
5477                         if (t == TypeManager.void_ptr_type){
5478                                 Report.Error (
5479                                         242, loc,
5480                                         "The array index operation is not valid for void pointers");
5481                                 return null;
5482                         }
5483                         if (Arguments.Count != 1){
5484                                 Report.Error (
5485                                         196, loc,
5486                                         "A pointer must be indexed by a single value");
5487                                 return null;
5488                         }
5489                         Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t);
5490                         return new Indirection (p);
5491                 }
5492                 
5493                 public override Expression DoResolve (EmitContext ec)
5494                 {
5495                         if (!CommonResolve (ec))
5496                                 return null;
5497
5498                         //
5499                         // We perform some simple tests, and then to "split" the emit and store
5500                         // code we create an instance of a different class, and return that.
5501                         //
5502                         // I am experimenting with this pattern.
5503                         //
5504                         Type t = Expr.Type;
5505
5506                         if (t.IsArray)
5507                                 return (new ArrayAccess (this)).Resolve (ec);
5508                         else if (t.IsPointer)
5509                                 return MakePointerAccess ();
5510                         else
5511                                 return (new IndexerAccess (this)).Resolve (ec);
5512                 }
5513
5514                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5515                 {
5516                         if (!CommonResolve (ec))
5517                                 return null;
5518
5519                         Type t = Expr.Type;
5520                         if (t.IsArray)
5521                                 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
5522                         else if (t.IsPointer)
5523                                 return MakePointerAccess ();
5524                         else
5525                                 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
5526                 }
5527                 
5528                 public override void Emit (EmitContext ec)
5529                 {
5530                         throw new Exception ("Should never be reached");
5531                 }
5532         }
5533
5534         /// <summary>
5535         ///   Implements array access 
5536         /// </summary>
5537         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
5538                 //
5539                 // Points to our "data" repository
5540                 //
5541                 ElementAccess ea;
5542
5543                 LocalTemporary [] cached_locations;
5544                 
5545                 public ArrayAccess (ElementAccess ea_data)
5546                 {
5547                         ea = ea_data;
5548                         eclass = ExprClass.Variable;
5549                 }
5550
5551                 public override Expression DoResolve (EmitContext ec)
5552                 {
5553                         ExprClass eclass = ea.Expr.eclass;
5554
5555 #if false
5556                         // As long as the type is valid
5557                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
5558                               eclass == ExprClass.Value)) {
5559                                 report118 (ea.loc, ea.Expr, "variable or value");
5560                                 return null;
5561                         }
5562 #endif
5563
5564                         Type t = ea.Expr.Type;
5565                         if (t.GetArrayRank () != ea.Arguments.Count){
5566                                 Report.Error (22, ea.loc,
5567                                               "Incorrect number of indexes for array " +
5568                                               " expected: " + t.GetArrayRank () + " got: " +
5569                                               ea.Arguments.Count);
5570                                 return null;
5571                         }
5572                         type = TypeManager.TypeToCoreType (t.GetElementType ());
5573                         if (type.IsPointer && !ec.InUnsafe){
5574                                 UnsafeError (ea.loc);
5575                                 return null;
5576                         }
5577                         
5578                         eclass = ExprClass.Variable;
5579
5580                         return this;
5581                 }
5582
5583                 /// <summary>
5584                 ///    Emits the right opcode to load an object of Type `t'
5585                 ///    from an array of T
5586                 /// </summary>
5587                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
5588                 {
5589                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
5590                                 ig.Emit (OpCodes.Ldelem_I1);
5591                         else if (type == TypeManager.sbyte_type)
5592                                 ig.Emit (OpCodes.Ldelem_U1);
5593                         else if (type == TypeManager.short_type)
5594                                 ig.Emit (OpCodes.Ldelem_I2);
5595                         else if (type == TypeManager.ushort_type)
5596                                 ig.Emit (OpCodes.Ldelem_U2);
5597                         else if (type == TypeManager.int32_type)
5598                                 ig.Emit (OpCodes.Ldelem_I4);
5599                         else if (type == TypeManager.uint32_type)
5600                                 ig.Emit (OpCodes.Ldelem_U4);
5601                         else if (type == TypeManager.uint64_type)
5602                                 ig.Emit (OpCodes.Ldelem_I8);
5603                         else if (type == TypeManager.int64_type)
5604                                 ig.Emit (OpCodes.Ldelem_I8);
5605                         else if (type == TypeManager.float_type)
5606                                 ig.Emit (OpCodes.Ldelem_R4);
5607                         else if (type == TypeManager.double_type)
5608                                 ig.Emit (OpCodes.Ldelem_R8);
5609                         else if (type == TypeManager.intptr_type)
5610                                 ig.Emit (OpCodes.Ldelem_I);
5611                         else if (type.IsValueType){
5612                                 ig.Emit (OpCodes.Ldelema, type);
5613                                 ig.Emit (OpCodes.Ldobj, type);
5614                         } else 
5615                                 ig.Emit (OpCodes.Ldelem_Ref);
5616                 }
5617
5618                 /// <summary>
5619                 ///    Emits the right opcode to store an object of Type `t'
5620                 ///    from an array of T.  
5621                 /// </summary>
5622                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
5623                 {
5624                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
5625                             t == TypeManager.bool_type)
5626                                 ig.Emit (OpCodes.Stelem_I1);
5627                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
5628                                 ig.Emit (OpCodes.Stelem_I2);
5629                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
5630                                 ig.Emit (OpCodes.Stelem_I4);
5631                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
5632                                 ig.Emit (OpCodes.Stelem_I8);
5633                         else if (t == TypeManager.float_type)
5634                                 ig.Emit (OpCodes.Stelem_R4);
5635                         else if (t == TypeManager.double_type)
5636                                 ig.Emit (OpCodes.Stelem_R8);
5637                         else if (t == TypeManager.intptr_type)
5638                                 ig.Emit (OpCodes.Stelem_I);
5639                         else if (t.IsValueType)
5640                                 ig.Emit (OpCodes.Stobj, t);
5641                         else
5642                                 ig.Emit (OpCodes.Stelem_Ref);
5643                 }
5644
5645                 MethodInfo FetchGetMethod ()
5646                 {
5647                         ModuleBuilder mb = CodeGen.ModuleBuilder;
5648                         int arg_count = ea.Arguments.Count;
5649                         Type [] args = new Type [arg_count];
5650                         MethodInfo get;
5651                         
5652                         for (int i = 0; i < arg_count; i++){
5653                                 //args [i++] = a.Type;
5654                                 args [i] = TypeManager.int32_type;
5655                         }
5656                         
5657                         get = mb.GetArrayMethod (
5658                                 ea.Expr.Type, "Get",
5659                                 CallingConventions.HasThis |
5660                                 CallingConventions.Standard,
5661                                 type, args);
5662                         return get;
5663                 }
5664                                 
5665
5666                 MethodInfo FetchAddressMethod ()
5667                 {
5668                         ModuleBuilder mb = CodeGen.ModuleBuilder;
5669                         int arg_count = ea.Arguments.Count;
5670                         Type [] args = new Type [arg_count];
5671                         MethodInfo address;
5672                         string ptr_type_name;
5673                         Type ret_type;
5674                         
5675                         ptr_type_name = type.FullName + "&";
5676                         ret_type = Type.GetType (ptr_type_name);
5677                         
5678                         //
5679                         // It is a type defined by the source code we are compiling
5680                         //
5681                         if (ret_type == null){
5682                                 ret_type = mb.GetType (ptr_type_name);
5683                         }
5684
5685                         for (int i = 0; i < arg_count; i++){
5686                                 //args [i++] = a.Type;
5687                                 args [i] = TypeManager.int32_type;
5688                         }
5689                         
5690                         address = mb.GetArrayMethod (
5691                                 ea.Expr.Type, "Address",
5692                                 CallingConventions.HasThis |
5693                                 CallingConventions.Standard,
5694                                 ret_type, args);
5695
5696                         return address;
5697                 }
5698
5699                 //
5700                 // Load the array arguments into the stack.
5701                 //
5702                 // If we have been requested to cache the values (cached_locations array
5703                 // initialized), then load the arguments the first time and store them
5704                 // in locals.  otherwise load from local variables.
5705                 //
5706                 void LoadArrayAndArguments (EmitContext ec)
5707                 {
5708                         if (cached_locations == null){
5709                                 ea.Expr.Emit (ec);
5710                                 foreach (Argument a in ea.Arguments)
5711                                         a.Expr.Emit (ec);
5712                                 return;
5713                         }
5714
5715                         ILGenerator ig = ec.ig;
5716                         
5717                         if (cached_locations [0] == null){
5718                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
5719                                 ea.Expr.Emit (ec);
5720                                 ig.Emit (OpCodes.Dup);
5721                                 cached_locations [0].Store (ec);
5722                                 
5723                                 int j = 1;
5724                                 
5725                                 foreach (Argument a in ea.Arguments){
5726                                         cached_locations [j] = new LocalTemporary (ec, a.Expr.Type);
5727                                         a.Expr.Emit (ec);
5728                                         ig.Emit (OpCodes.Dup);
5729                                         cached_locations [j].Store (ec);
5730                                         j++;
5731                                 }
5732                                 return;
5733                         }
5734
5735                         foreach (LocalTemporary lt in cached_locations)
5736                                 lt.Emit (ec);
5737                 }
5738
5739                 public new void CacheTemporaries (EmitContext ec)
5740                 {
5741                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
5742                 }
5743                 
5744                 public override void Emit (EmitContext ec)
5745                 {
5746                         int rank = ea.Expr.Type.GetArrayRank ();
5747                         ILGenerator ig = ec.ig;
5748
5749                         LoadArrayAndArguments (ec);
5750                         
5751                         if (rank == 1)
5752                                 EmitLoadOpcode (ig, type);
5753                         else {
5754                                 MethodInfo method;
5755                                 
5756                                 method = FetchGetMethod ();
5757                                 ig.Emit (OpCodes.Call, method);
5758                         }
5759                 }
5760
5761                 public void EmitAssign (EmitContext ec, Expression source)
5762                 {
5763                         int rank = ea.Expr.Type.GetArrayRank ();
5764                         ILGenerator ig = ec.ig;
5765                         Type t = source.Type;
5766
5767                         LoadArrayAndArguments (ec);
5768
5769                         //
5770                         // The stobj opcode used by value types will need
5771                         // an address on the stack, not really an array/array
5772                         // pair
5773                         //
5774                         if (rank == 1){
5775                                 if (t.IsValueType && !TypeManager.IsBuiltinType (t))
5776                                         ig.Emit (OpCodes.Ldelema, t);
5777                         }
5778                         
5779                         source.Emit (ec);
5780
5781                         if (rank == 1)
5782                                 EmitStoreOpcode (ig, t);
5783                         else {
5784                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5785                                 int arg_count = ea.Arguments.Count;
5786                                 Type [] args = new Type [arg_count + 1];
5787                                 MethodInfo set;
5788                                 
5789                                 for (int i = 0; i < arg_count; i++){
5790                                         //args [i++] = a.Type;
5791                                         args [i] = TypeManager.int32_type;
5792                                 }
5793
5794                                 args [arg_count] = type;
5795                                 
5796                                 set = mb.GetArrayMethod (
5797                                         ea.Expr.Type, "Set",
5798                                         CallingConventions.HasThis |
5799                                         CallingConventions.Standard,
5800                                         TypeManager.void_type, args);
5801                                 
5802                                 ig.Emit (OpCodes.Call, set);
5803                         }
5804                 }
5805
5806                 public void AddressOf (EmitContext ec, AddressOp mode)
5807                 {
5808                         int rank = ea.Expr.Type.GetArrayRank ();
5809                         ILGenerator ig = ec.ig;
5810
5811                         LoadArrayAndArguments (ec);
5812
5813                         if (rank == 1){
5814                                 ig.Emit (OpCodes.Ldelema, type);
5815                         } else {
5816                                 MethodInfo address = FetchAddressMethod ();
5817                                 ig.Emit (OpCodes.Call, address);
5818                         }
5819                 }
5820         }
5821
5822         
5823         class Indexers {
5824                 public ArrayList getters, setters;
5825                 static Hashtable map;
5826
5827                 static Indexers ()
5828                 {
5829                         map = new Hashtable ();
5830                 }
5831
5832                 Indexers (MemberInfo [] mi)
5833                 {
5834                         foreach (PropertyInfo property in mi){
5835                                 MethodInfo get, set;
5836                                 
5837                                 get = property.GetGetMethod (true);
5838                                 if (get != null){
5839                                         if (getters == null)
5840                                                 getters = new ArrayList ();
5841
5842                                         getters.Add (get);
5843                                 }
5844                                 
5845                                 set = property.GetSetMethod (true);
5846                                 if (set != null){
5847                                         if (setters == null)
5848                                                 setters = new ArrayList ();
5849                                         setters.Add (set);
5850                                 }
5851                         }
5852                 }
5853
5854                 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
5855                 {
5856                         Indexers ix = (Indexers) map [lookup_type];
5857                         
5858                         if (ix != null)
5859                                 return ix;
5860
5861                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
5862
5863                         MemberInfo [] mi = TypeManager.MemberLookup (
5864                                 caller_type, lookup_type, MemberTypes.Property,
5865                                 BindingFlags.Public | BindingFlags.Instance, p_name);
5866
5867                         if (mi == null || mi.Length == 0)
5868                                 return null;
5869
5870                         ix = new Indexers (mi);
5871                         map [lookup_type] = ix;
5872
5873                         return ix;
5874                 }
5875                 
5876                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
5877                 {
5878                         Indexers ix = (Indexers) map [lookup_type];
5879                         
5880                         if (ix != null)
5881                                 return ix;
5882
5883                         ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
5884                         if (ix != null)
5885                                 return ix;
5886
5887                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
5888                         if (ifaces != null) {
5889                                 foreach (Type itype in ifaces) {
5890                                         ix = GetIndexersForTypeOrInterface (caller_type, itype);
5891                                         if (ix != null)
5892                                                 return ix;
5893                                 }
5894                         }
5895
5896                         Report.Error (21, loc,
5897                                       "Type `" + TypeManager.CSharpName (lookup_type) +
5898                                       "' does not have any indexers defined");
5899                         return null;
5900                 }
5901         }
5902
5903         /// <summary>
5904         ///   Expressions that represent an indexer call.
5905         /// </summary>
5906         public class IndexerAccess : Expression, IAssignMethod {
5907                 //
5908                 // Points to our "data" repository
5909                 //
5910                 ElementAccess ea;
5911                 MethodInfo get, set;
5912                 Indexers ilist;
5913                 ArrayList set_arguments;
5914                 
5915                 public IndexerAccess (ElementAccess ea_data)
5916                 {
5917                         ea = ea_data;
5918                         eclass = ExprClass.Value;
5919                 }
5920
5921                 public override Expression DoResolve (EmitContext ec)
5922                 {
5923                         Type indexer_type = ea.Expr.Type;
5924                         
5925                         //
5926                         // Step 1: Query for all `Item' *properties*.  Notice
5927                         // that the actual methods are pointed from here.
5928                         //
5929                         // This is a group of properties, piles of them.  
5930
5931                         if (ilist == null)
5932                                 ilist = Indexers.GetIndexersForType (
5933                                         ec.ContainerType, indexer_type, ea.loc);
5934
5935
5936                         //
5937                         // Step 2: find the proper match
5938                         //
5939                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0){
5940                                 Location loc = ea.loc;
5941                                 
5942                                 get = (MethodInfo) Invocation.OverloadResolve (
5943                                         ec, new MethodGroupExpr (ilist.getters, loc), ea.Arguments, loc);
5944                         }
5945
5946                         if (get == null){
5947                                 Report.Error (154, ea.loc,
5948                                               "indexer can not be used in this context, because " +
5949                                               "it lacks a `get' accessor");
5950                                 return null;
5951                         }
5952
5953                         type = get.ReturnType;
5954                         if (type.IsPointer && !ec.InUnsafe){
5955                                 UnsafeError (ea.loc);
5956                                 return null;
5957                         }
5958                         
5959                         eclass = ExprClass.IndexerAccess;
5960                         return this;
5961                 }
5962
5963                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5964                 {
5965                         Type indexer_type = ea.Expr.Type;
5966                         Type right_type = right_side.Type;
5967
5968                         if (ilist == null)
5969                                 ilist = Indexers.GetIndexersForType (
5970                                         ec.ContainerType, indexer_type, ea.loc);
5971
5972                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
5973                                 Location loc = ea.loc;
5974                                 
5975                                 set_arguments = (ArrayList) ea.Arguments.Clone ();
5976                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
5977
5978                                 set = (MethodInfo) Invocation.OverloadResolve (
5979                                         ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
5980                         }
5981                         
5982                         if (set == null){
5983                                 Report.Error (200, ea.loc,
5984                                               "indexer X.this [" + TypeManager.CSharpName (right_type) +
5985                                               "] lacks a `set' accessor");
5986                                         return null;
5987                         }
5988
5989                         type = TypeManager.void_type;
5990                         eclass = ExprClass.IndexerAccess;
5991                         return this;
5992                 }
5993                 
5994                 public override void Emit (EmitContext ec)
5995                 {
5996                         Invocation.EmitCall (ec, false, false, ea.Expr, get, ea.Arguments, ea.loc);
5997                 }
5998
5999                 //
6000                 // source is ignored, because we already have a copy of it from the
6001                 // LValue resolution and we have already constructed a pre-cached
6002                 // version of the arguments (ea.set_arguments);
6003                 //
6004                 public void EmitAssign (EmitContext ec, Expression source)
6005                 {
6006                         Invocation.EmitCall (ec, false, false, ea.Expr, set, set_arguments, ea.loc);
6007                 }
6008         }
6009
6010         /// <summary>
6011         ///   The base operator for method names
6012         /// </summary>
6013         public class BaseAccess : Expression {
6014                 string member;
6015                 Location loc;
6016                 
6017                 public BaseAccess (string member, Location l)
6018                 {
6019                         this.member = member;
6020                         loc = l;
6021                 }
6022
6023                 public override Expression DoResolve (EmitContext ec)
6024                 {
6025                         Expression member_lookup;
6026                         Type current_type = ec.ContainerType;
6027                         Type base_type = current_type.BaseType;
6028                         Expression e;
6029
6030                         if (ec.IsStatic){
6031                                 Report.Error (1511, loc,
6032                                               "Keyword base is not allowed in static method");
6033                                 return null;
6034                         }
6035                         
6036                         member_lookup = MemberLookup (ec, base_type, member, loc);
6037                         if (member_lookup == null)
6038                                 return null;
6039
6040                         Expression left;
6041                         
6042                         if (ec.IsStatic)
6043                                 left = new TypeExpr (base_type);
6044                         else
6045                                 left = ec.This;
6046                         
6047                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
6048                         if (e is PropertyExpr){
6049                                 PropertyExpr pe = (PropertyExpr) e;
6050
6051                                 pe.IsBase = true;
6052                         }
6053
6054                         return e;
6055                 }
6056
6057                 public override void Emit (EmitContext ec)
6058                 {
6059                         throw new Exception ("Should never be called"); 
6060                 }
6061         }
6062
6063         /// <summary>
6064         ///   The base indexer operator
6065         /// </summary>
6066         public class BaseIndexerAccess : Expression {
6067                 ArrayList Arguments;
6068                 Location loc;
6069                 
6070                 public BaseIndexerAccess (ArrayList args, Location l)
6071                 {
6072                         Arguments = args;
6073                         loc = l;
6074                 }
6075
6076                 public override Expression DoResolve (EmitContext ec)
6077                 {
6078                         Type current_type = ec.ContainerType;
6079                         Type base_type = current_type.BaseType;
6080                         Expression member_lookup;
6081
6082                         if (ec.IsStatic){
6083                                 Report.Error (1511, loc,
6084                                               "Keyword base is not allowed in static method");
6085                                 return null;
6086                         }
6087                         
6088                         member_lookup = MemberLookup (ec, base_type, "get_Item", MemberTypes.Method, AllBindingFlags, loc);
6089                         if (member_lookup == null)
6090                                 return null;
6091
6092                         return MemberAccess.ResolveMemberAccess (ec, member_lookup, ec.This, loc, null);
6093                 }
6094
6095                 public override void Emit (EmitContext ec)
6096                 {
6097                         throw new Exception ("Should never be called");
6098                 }
6099         }
6100         
6101         /// <summary>
6102         ///   This class exists solely to pass the Type around and to be a dummy
6103         ///   that can be passed to the conversion functions (this is used by
6104         ///   foreach implementation to typecast the object return value from
6105         ///   get_Current into the proper type.  All code has been generated and
6106         ///   we only care about the side effect conversions to be performed
6107         ///
6108         ///   This is also now used as a placeholder where a no-action expression
6109         ///   is needed (the `New' class).
6110         /// </summary>
6111         public class EmptyExpression : Expression {
6112                 public EmptyExpression ()
6113                 {
6114                         type = TypeManager.object_type;
6115                         eclass = ExprClass.Value;
6116                 }
6117
6118                 public EmptyExpression (Type t)
6119                 {
6120                         type = t;
6121                         eclass = ExprClass.Value;
6122                 }
6123                 
6124                 public override Expression DoResolve (EmitContext ec)
6125                 {
6126                         return this;
6127                 }
6128
6129                 public override void Emit (EmitContext ec)
6130                 {
6131                         // nothing, as we only exist to not do anything.
6132                 }
6133
6134                 //
6135                 // This is just because we might want to reuse this bad boy
6136                 // instead of creating gazillions of EmptyExpressions.
6137                 // (CanConvertImplicit uses it)
6138                 //
6139                 public void SetType (Type t)
6140                 {
6141                         type = t;
6142                 }
6143         }
6144
6145         public class UserCast : Expression {
6146                 MethodBase method;
6147                 Expression source;
6148                 
6149                 public UserCast (MethodInfo method, Expression source)
6150                 {
6151                         this.method = method;
6152                         this.source = source;
6153                         type = method.ReturnType;
6154                         eclass = ExprClass.Value;
6155                 }
6156
6157                 public override Expression DoResolve (EmitContext ec)
6158                 {
6159                         //
6160                         // We are born fully resolved
6161                         //
6162                         return this;
6163                 }
6164
6165                 public override void Emit (EmitContext ec)
6166                 {
6167                         ILGenerator ig = ec.ig;
6168
6169                         source.Emit (ec);
6170                         
6171                         if (method is MethodInfo)
6172                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
6173                         else
6174                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6175
6176                 }
6177         }
6178
6179         // <summary>
6180         //   This class is used to "construct" the type during a typecast
6181         //   operation.  Since the Type.GetType class in .NET can parse
6182         //   the type specification, we just use this to construct the type
6183         //   one bit at a time.
6184         // </summary>
6185         public class ComposedCast : Expression {
6186                 Expression left;
6187                 string dim;
6188                 Location loc;
6189                 
6190                 public ComposedCast (Expression left, string dim, Location l)
6191                 {
6192                         this.left = left;
6193                         this.dim = dim;
6194                         loc = l;
6195                 }
6196
6197                 public override Expression DoResolve (EmitContext ec)
6198                 {
6199                         left = left.Resolve (ec);
6200                         if (left == null)
6201                                 return null;
6202
6203                         if (left.eclass != ExprClass.Type){
6204                                 report118 (loc, left, "type");
6205                                 return null;
6206                         }
6207                         
6208                         type = RootContext.LookupType (
6209                                 ec.DeclSpace, left.Type.FullName + dim, false, loc);
6210                         if (type == null)
6211                                 return null;
6212
6213                         if (!ec.InUnsafe && type.IsPointer){
6214                                 UnsafeError (loc);
6215                                 return null;
6216                         }
6217                         
6218                         eclass = ExprClass.Type;
6219                         return this;
6220                 }
6221
6222                 public override void Emit (EmitContext ec)
6223                 {
6224                         throw new Exception ("This should never be called");
6225                 }
6226         }
6227
6228         //
6229         // This class is used to represent the address of an array, used
6230         // only by the Fixed statement, this is like the C "&a [0]" construct.
6231         //
6232         public class ArrayPtr : Expression {
6233                 Expression array;
6234                 
6235                 public ArrayPtr (Expression array)
6236                 {
6237                         Type array_type = array.Type.GetElementType ();
6238
6239                         this.array = array;
6240                         
6241                         string array_ptr_type_name = array_type.FullName + "*";
6242                         
6243                         type = Type.GetType (array_ptr_type_name);
6244                         if (type == null){
6245                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6246                                 
6247                                 type = mb.GetType (array_ptr_type_name);
6248                         }
6249
6250                         eclass = ExprClass.Value;
6251                 }
6252
6253                 public override void Emit (EmitContext ec)
6254                 {
6255                         ILGenerator ig = ec.ig;
6256                         
6257                         array.Emit (ec);
6258                         IntLiteral.EmitInt (ig, 0);
6259                         ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
6260                 }
6261
6262                 public override Expression DoResolve (EmitContext ec)
6263                 {
6264                         //
6265                         // We are born fully resolved
6266                         //
6267                         return this;
6268                 }
6269         }
6270
6271         //
6272         // Used by the fixed statement
6273         //
6274         public class StringPtr : Expression {
6275                 LocalBuilder b;
6276                 
6277                 public StringPtr (LocalBuilder b)
6278                 {
6279                         this.b = b;
6280                         eclass = ExprClass.Value;
6281                         type = TypeManager.char_ptr_type;
6282                 }
6283
6284                 public override Expression DoResolve (EmitContext ec)
6285                 {
6286                         // This should never be invoked, we are born in fully
6287                         // initialized state.
6288
6289                         return this;
6290                 }
6291
6292                 public override void Emit (EmitContext ec)
6293                 {
6294                         ILGenerator ig = ec.ig;
6295
6296                         ig.Emit (OpCodes.Ldloc, b);
6297                         ig.Emit (OpCodes.Conv_I);
6298                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
6299                         ig.Emit (OpCodes.Add);
6300                 }
6301         }
6302         
6303         //
6304         // Implements the `stackalloc' keyword
6305         //
6306         public class StackAlloc : Expression {
6307                 Type otype;
6308                 string t;
6309                 Expression count;
6310                 Location loc;
6311                 
6312                 public StackAlloc (string type, Expression count, Location l)
6313                 {
6314                         t = type;
6315                         this.count = count;
6316                         loc = l;
6317                 }
6318
6319                 public override Expression DoResolve (EmitContext ec)
6320                 {
6321                         count = count.Resolve (ec);
6322                         if (count == null)
6323                                 return null;
6324                         
6325                         if (count.Type != TypeManager.int32_type){
6326                                 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
6327                                 if (count == null)
6328                                         return null;
6329                         }
6330
6331                         if (ec.InCatch || ec.InFinally){
6332                                 Report.Error (255, loc,
6333                                               "stackalloc can not be used in a catch or finally block");
6334                                 return null;
6335                         }
6336                         
6337                         otype = RootContext.LookupType (ec.DeclSpace, t, false, loc);
6338
6339                         if (otype == null)
6340                                 return null;
6341
6342                         if (!TypeManager.VerifyUnManaged (otype, loc))
6343                                 return null;
6344
6345                         string ptr_name = otype.FullName + "*";
6346                         type = Type.GetType (ptr_name);
6347                         if (type == null){
6348                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6349                                 
6350                                 type = mb.GetType (ptr_name);
6351                         }
6352                         eclass = ExprClass.Value;
6353
6354                         return this;
6355                 }
6356
6357                 public override void Emit (EmitContext ec)
6358                 {
6359                         int size = GetTypeSize (otype);
6360                         ILGenerator ig = ec.ig;
6361                                 
6362                         if (size == 0)
6363                                 ig.Emit (OpCodes.Sizeof, otype);
6364                         else
6365                                 IntConstant.EmitInt (ig, size);
6366                         count.Emit (ec);
6367                         ig.Emit (OpCodes.Mul);
6368                         ig.Emit (OpCodes.Localloc);
6369                 }
6370         }
6371 }