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