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