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