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