2004-02-03 Marek Safar <marek.safar@seznam.cz>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
9 //
10 #define USE_OLD
11
12 namespace Mono.CSharp {
13         using System;
14         using System.Collections;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Text;
18
19         /// <summary>
20         ///   This is just a helper class, it is generated by Unary, UnaryMutator
21         ///   when an overloaded method has been found.  It just emits the code for a
22         ///   static call.
23         /// </summary>
24         public class StaticCallExpr : ExpressionStatement {
25                 ArrayList args;
26                 MethodInfo mi;
27
28                 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
29                 {
30                         mi = m;
31                         args = a;
32
33                         type = m.ReturnType;
34                         eclass = ExprClass.Value;
35                         loc = l;
36                 }
37
38                 public override Expression DoResolve (EmitContext ec)
39                 {
40                         //
41                         // We are born fully resolved
42                         //
43                         return this;
44                 }
45
46                 public override void Emit (EmitContext ec)
47                 {
48                         if (args != null) 
49                                 Invocation.EmitArguments (ec, mi, args);
50
51                         ec.ig.Emit (OpCodes.Call, mi);
52                         return;
53                 }
54                 
55                 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56                                                          Expression e, Location loc)
57                 {
58                         ArrayList args;
59                         MethodBase method;
60                         
61                         args = new ArrayList (1);
62                         Argument a = new Argument (e, Argument.AType.Expression);
63
64                         // We need to resolve the arguments before sending them in !
65                         if (!a.Resolve (ec, loc))
66                                 return null;
67
68                         args.Add (a);
69                         method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
70
71                         if (method == null)
72                                 return null;
73
74                         return new StaticCallExpr ((MethodInfo) method, args, loc);
75                 }
76
77                 public override void EmitStatement (EmitContext ec)
78                 {
79                         Emit (ec);
80                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
81                                 ec.ig.Emit (OpCodes.Pop);
82                 }
83         }
84
85         public class ParenthesizedExpression : Expression
86         {
87                 public Expression Expr;
88
89                 public ParenthesizedExpression (Expression expr, Location loc)
90                 {
91                         this.Expr = expr;
92                         this.loc = loc;
93                 }
94
95                 public override Expression DoResolve (EmitContext ec)
96                 {
97                         Expr = Expr.Resolve (ec);
98                         return Expr;
99                 }
100
101                 public override void Emit (EmitContext ec)
102                 {
103                         throw new Exception ("Should not happen");
104                 }
105         }
106         
107         /// <summary>
108         ///   Unary expressions.  
109         /// </summary>
110         ///
111         /// <remarks>
112         ///   Unary implements unary expressions.   It derives from
113         ///   ExpressionStatement becuase the pre/post increment/decrement
114         ///   operators can be used in a statement context.
115         /// </remarks>
116         public class Unary : Expression {
117                 public enum Operator : byte {
118                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
119                         Indirection, AddressOf,  TOP
120                 }
121
122                 public Operator Oper;
123                 public Expression Expr;
124                 
125                 public Unary (Operator op, Expression expr, Location loc)
126                 {
127                         this.Oper = op;
128                         this.Expr = expr;
129                         this.loc = loc;
130                 }
131
132                 /// <summary>
133                 ///   Returns a stringified representation of the Operator
134                 /// </summary>
135                 static public string OperName (Operator oper)
136                 {
137                         switch (oper){
138                         case Operator.UnaryPlus:
139                                 return "+";
140                         case Operator.UnaryNegation:
141                                 return "-";
142                         case Operator.LogicalNot:
143                                 return "!";
144                         case Operator.OnesComplement:
145                                 return "~";
146                         case Operator.AddressOf:
147                                 return "&";
148                         case Operator.Indirection:
149                                 return "*";
150                         }
151
152                         return oper.ToString ();
153                 }
154
155                 public static readonly string [] oper_names;
156
157                 static Unary ()
158                 {
159                         oper_names = new string [(int)Operator.TOP];
160
161                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
162                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
163                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
164                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
165                         oper_names [(int) Operator.Indirection] = "op_Indirection";
166                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
167                 }
168
169                 void Error23 (Type t)
170                 {
171                         Error (
172                                 23, "Operator " + OperName (Oper) +
173                                 " cannot be applied to operand of type `" +
174                                 TypeManager.CSharpName (t) + "'");
175                 }
176
177                 /// <remarks>
178                 ///   The result has been already resolved:
179                 ///
180                 ///   FIXME: a minus constant -128 sbyte cant be turned into a
181                 ///   constant byte.
182                 /// </remarks>
183                 static Expression TryReduceNegative (Constant expr)
184                 {
185                         Expression e = null;
186
187                         if (expr is IntConstant)
188                                 e = new IntConstant (-((IntConstant) expr).Value);
189                         else if (expr is UIntConstant){
190                                 uint value = ((UIntConstant) expr).Value;
191
192                                 if (value < 2147483649)
193                                         return new IntConstant (-(int)value);
194                                 else
195                                         e = new LongConstant (-value);
196                         }
197                         else if (expr is LongConstant)
198                                 e = new LongConstant (-((LongConstant) expr).Value);
199                         else if (expr is ULongConstant){
200                                 ulong value = ((ULongConstant) expr).Value;
201
202                                 if (value < 9223372036854775809)
203                                         return new LongConstant(-(long)value);
204                         }
205                         else if (expr is FloatConstant)
206                                 e = new FloatConstant (-((FloatConstant) expr).Value);
207                         else if (expr is DoubleConstant)
208                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);
209                         else if (expr is DecimalConstant)
210                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);
211                         else if (expr is ShortConstant)
212                                 e = new IntConstant (-((ShortConstant) expr).Value);
213                         else if (expr is UShortConstant)
214                                 e = new IntConstant (-((UShortConstant) expr).Value);
215                         return e;
216                 }
217
218                 // <summary>
219                 //   This routine will attempt to simplify the unary expression when the
220                 //   argument is a constant.  The result is returned in `result' and the
221                 //   function returns true or false depending on whether a reduction
222                 //   was performed or not
223                 // </summary>
224                 bool Reduce (EmitContext ec, Constant e, out Expression result)
225                 {
226                         Type expr_type = e.Type;
227                         
228                         switch (Oper){
229                         case Operator.UnaryPlus:
230                                 result = e;
231                                 return true;
232                                 
233                         case Operator.UnaryNegation:
234                                 result = TryReduceNegative (e);
235                                 return true;
236                                 
237                         case Operator.LogicalNot:
238                                 if (expr_type != TypeManager.bool_type) {
239                                         result = null;
240                                         Error23 (expr_type);
241                                         return false;
242                                 }
243                                 
244                                 BoolConstant b = (BoolConstant) e;
245                                 result = new BoolConstant (!(b.Value));
246                                 return true;
247                                 
248                         case Operator.OnesComplement:
249                                 if (!((expr_type == TypeManager.int32_type) ||
250                                       (expr_type == TypeManager.uint32_type) ||
251                                       (expr_type == TypeManager.int64_type) ||
252                                       (expr_type == TypeManager.uint64_type) ||
253                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
254
255                                         result = null;
256                                         if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
257                                                 result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
258                                                 result = result.Resolve (ec);
259                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
260                                                 result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
261                                                 result = result.Resolve (ec);
262                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
263                                                 result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
264                                                 result = result.Resolve (ec);
265                                         } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
266                                                 result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
267                                                 result = result.Resolve (ec);
268                                         }
269
270                                         if (result == null || !(result is Constant)){
271                                                 result = null;
272                                                 Error23 (expr_type);
273                                                 return false;
274                                         }
275
276                                         expr_type = result.Type;
277                                         e = (Constant) result;
278                                 }
279
280                                 if (e is EnumConstant){
281                                         EnumConstant enum_constant = (EnumConstant) e;
282                                         Expression reduced;
283                                         
284                                         if (Reduce (ec, enum_constant.Child, out reduced)){
285                                                 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
286                                                 return true;
287                                         } else {
288                                                 result = null;
289                                                 return false;
290                                         }
291                                 }
292
293                                 if (expr_type == TypeManager.int32_type){
294                                         result = new IntConstant (~ ((IntConstant) e).Value);
295                                 } else if (expr_type == TypeManager.uint32_type){
296                                         result = new UIntConstant (~ ((UIntConstant) e).Value);
297                                 } else if (expr_type == TypeManager.int64_type){
298                                         result = new LongConstant (~ ((LongConstant) e).Value);
299                                 } else if (expr_type == TypeManager.uint64_type){
300                                         result = new ULongConstant (~ ((ULongConstant) e).Value);
301                                 } else {
302                                         result = null;
303                                         Error23 (expr_type);
304                                         return false;
305                                 }
306                                 return true;
307
308                         case Operator.AddressOf:
309                                 result = this;
310                                 return false;
311
312                         case Operator.Indirection:
313                                 result = this;
314                                 return false;
315                         }
316                         throw new Exception ("Can not constant fold: " + Oper.ToString());
317                 }
318
319                 Expression ResolveOperator (EmitContext ec)
320                 {
321                         Type expr_type = Expr.Type;
322
323                         //
324                         // Step 1: Perform Operator Overload location
325                         //
326                         Expression mg;
327                         string op_name;
328                         
329                         op_name = oper_names [(int) Oper];
330
331                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
332                         
333                         if (mg != null) {
334                                 Expression e = StaticCallExpr.MakeSimpleCall (
335                                         ec, (MethodGroupExpr) mg, Expr, loc);
336
337                                 if (e == null){
338                                         Error23 (expr_type);
339                                         return null;
340                                 }
341                                 
342                                 return e;
343                         }
344
345                         // Only perform numeric promotions on:
346                         // +, - 
347
348                         if (expr_type == null)
349                                 return null;
350                         
351                         //
352                         // Step 2: Default operations on CLI native types.
353                         //
354
355                         // Attempt to use a constant folding operation.
356                         if (Expr is Constant){
357                                 Expression result;
358                                 
359                                 if (Reduce (ec, (Constant) Expr, out result))
360                                         return result;
361                         }
362
363                         switch (Oper){
364                         case Operator.LogicalNot:
365                                 if (expr_type != TypeManager.bool_type) {
366                                         Expr = ResolveBoolean (ec, Expr, loc);
367                                         if (Expr == null){
368                                                 Error23 (expr_type);
369                                                 return null;
370                                         }
371                                 }
372                                 
373                                 type = TypeManager.bool_type;
374                                 return this;
375
376                         case Operator.OnesComplement:
377                                 if (!((expr_type == TypeManager.int32_type) ||
378                                       (expr_type == TypeManager.uint32_type) ||
379                                       (expr_type == TypeManager.int64_type) ||
380                                       (expr_type == TypeManager.uint64_type) ||
381                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
382                                         Expression e;
383
384                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
385                                         if (e != null){
386                                                 type = TypeManager.int32_type;
387                                                 return this;
388                                         }
389                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
390                                         if (e != null){
391                                                 type = TypeManager.uint32_type;
392                                                 return this;
393                                         }
394                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
395                                         if (e != null){
396                                                 type = TypeManager.int64_type;
397                                                 return this;
398                                         }
399                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
400                                         if (e != null){
401                                                 type = TypeManager.uint64_type;
402                                                 return this;
403                                         }
404                                         Error23 (expr_type);
405                                         return null;
406                                 }
407                                 type = expr_type;
408                                 return this;
409
410                         case Operator.AddressOf:
411                                 if (Expr.eclass != ExprClass.Variable){
412                                         Error (211, "Cannot take the address of non-variables");
413                                         return null;
414                                 }
415                                 
416                                 if (!ec.InUnsafe) {
417                                         UnsafeError (loc); 
418                                         return null;
419                                 }
420                                 
421                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
422                                         return null;
423                                 }
424
425                                 IVariable variable = Expr as IVariable;
426                                 if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
427                                         Error (212, "You can only take the address of an unfixed expression inside " +
428                                                "of a fixed statement initializer");
429                                         return null;
430                                 }
431
432                                 // According to the specs, a variable is considered definitely assigned if you take
433                                 // its address.
434                                 if ((variable != null) && (variable.VariableInfo != null))
435                                         variable.VariableInfo.SetAssigned (ec);
436
437                                 type = TypeManager.GetPointerType (Expr.Type);
438                                 return this;
439
440                         case Operator.Indirection:
441                                 if (!ec.InUnsafe){
442                                         UnsafeError (loc);
443                                         return null;
444                                 }
445                                 
446                                 if (!expr_type.IsPointer){
447                                         Error (193, "The * or -> operator can only be applied to pointers");
448                                         return null;
449                                 }
450                                 
451                                 //
452                                 // We create an Indirection expression, because
453                                 // it can implement the IMemoryLocation.
454                                 // 
455                                 return new Indirection (Expr, loc);
456                         
457                         case Operator.UnaryPlus:
458                                 //
459                                 // A plus in front of something is just a no-op, so return the child.
460                                 //
461                                 return Expr;
462
463                         case Operator.UnaryNegation:
464                                 //
465                                 // Deals with -literals
466                                 // int     operator- (int x)
467                                 // long    operator- (long x)
468                                 // float   operator- (float f)
469                                 // double  operator- (double d)
470                                 // decimal operator- (decimal d)
471                                 //
472                                 Expression expr = null;
473
474                                 //
475                                 // transform - - expr into expr
476                                 //
477                                 if (Expr is Unary){
478                                         Unary unary = (Unary) Expr;
479                                         
480                                         if (unary.Oper == Operator.UnaryNegation)
481                                                 return unary.Expr;
482                                 }
483
484                                 //
485                                 // perform numeric promotions to int,
486                                 // long, double.
487                                 //
488                                 //
489                                 // The following is inneficient, because we call
490                                 // ImplicitConversion too many times.
491                                 //
492                                 // It is also not clear if we should convert to Float
493                                 // or Double initially.
494                                 //
495                                 if (expr_type == TypeManager.uint32_type){
496                                         //
497                                         // FIXME: handle exception to this rule that
498                                         // permits the int value -2147483648 (-2^31) to
499                                         // bt wrote as a decimal interger literal
500                                         //
501                                         type = TypeManager.int64_type;
502                                         Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
503                                         return this;
504                                 }
505
506                                 if (expr_type == TypeManager.uint64_type){
507                                         //
508                                         // FIXME: Handle exception of `long value'
509                                         // -92233720368547758087 (-2^63) to be wrote as
510                                         // decimal integer literal.
511                                         //
512                                         Error23 (expr_type);
513                                         return null;
514                                 }
515
516                                 if (expr_type == TypeManager.float_type){
517                                         type = expr_type;
518                                         return this;
519                                 }
520                                 
521                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
522                                 if (expr != null){
523                                         Expr = expr;
524                                         type = expr.Type;
525                                         return this;
526                                 } 
527
528                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
529                                 if (expr != null){
530                                         Expr = expr;
531                                         type = expr.Type;
532                                         return this;
533                                 }
534
535                                 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
536                                 if (expr != null){
537                                         Expr = expr;
538                                         type = expr.Type;
539                                         return this;
540                                 }
541                                 
542                                 Error23 (expr_type);
543                                 return null;
544                         }
545
546                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
547                                TypeManager.CSharpName (expr_type) + "'");
548                         return null;
549                 }
550
551                 public override Expression DoResolve (EmitContext ec)
552                 {
553                         if (Oper == Operator.AddressOf)
554                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
555                         else
556                                 Expr = Expr.Resolve (ec);
557                         
558                         if (Expr == null)
559                                 return null;
560
561                         eclass = ExprClass.Value;
562                         return ResolveOperator (ec);
563                 }
564
565                 public override void Emit (EmitContext ec)
566                 {
567                         ILGenerator ig = ec.ig;
568                         
569                         switch (Oper) {
570                         case Operator.UnaryPlus:
571                                 throw new Exception ("This should be caught by Resolve");
572                                 
573                         case Operator.UnaryNegation:
574                                 if (ec.CheckState) {
575                                         ig.Emit (OpCodes.Ldc_I4_0);
576                                         if (type == TypeManager.int64_type)
577                                                 ig.Emit (OpCodes.Conv_U8);
578                                         Expr.Emit (ec);
579                                         ig.Emit (OpCodes.Sub_Ovf);
580                                 } else {
581                                         Expr.Emit (ec);
582                                         ig.Emit (OpCodes.Neg);
583                                 }
584                                 
585                                 break;
586                                 
587                         case Operator.LogicalNot:
588                                 Expr.Emit (ec);
589                                 ig.Emit (OpCodes.Ldc_I4_0);
590                                 ig.Emit (OpCodes.Ceq);
591                                 break;
592                                 
593                         case Operator.OnesComplement:
594                                 Expr.Emit (ec);
595                                 ig.Emit (OpCodes.Not);
596                                 break;
597                                 
598                         case Operator.AddressOf:
599                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
600                                 break;
601                                 
602                         default:
603                                 throw new Exception ("This should not happen: Operator = "
604                                                      + Oper.ToString ());
605                         }
606                 }
607
608                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
609                 {
610                         if (Oper == Operator.LogicalNot)
611                                 Expr.EmitBranchable (ec, target, !onTrue);
612                         else
613                                 base.EmitBranchable (ec, target, onTrue);
614                 }
615
616                 public override string ToString ()
617                 {
618                         return "Unary (" + Oper + ", " + Expr + ")";
619                 }
620                 
621         }
622
623         //
624         // Unary operators are turned into Indirection expressions
625         // after semantic analysis (this is so we can take the address
626         // of an indirection).
627         //
628         public class Indirection : Expression, IMemoryLocation, IAssignMethod {
629                 Expression expr;
630                 LocalTemporary temporary;
631                 bool have_temporary;
632                 
633                 public Indirection (Expression expr, Location l)
634                 {
635                         this.expr = expr;
636                         this.type = TypeManager.GetElementType (expr.Type);
637                         eclass = ExprClass.Variable;
638                         loc = l;
639                 }
640
641                 void LoadExprValue (EmitContext ec)
642                 {
643                 }
644                 
645                 public override void Emit (EmitContext ec)
646                 {
647                         ILGenerator ig = ec.ig;
648
649                         if (temporary != null){
650                                 if (have_temporary) {
651                                         temporary.Emit (ec);
652                                 } else {
653                                         expr.Emit (ec);
654                                         ec.ig.Emit (OpCodes.Dup);
655                                         temporary.Store (ec);
656                                         have_temporary = true;
657                                 }
658                         } else
659                                 expr.Emit (ec);
660                         
661                         LoadFromPtr (ig, Type);
662                 }
663
664                 public void EmitAssign (EmitContext ec, Expression source)
665                 {
666                         if (temporary != null){
667                                 if (have_temporary)
668                                         temporary.Emit (ec);
669                                 else {
670                                         expr.Emit (ec);
671                                         ec.ig.Emit (OpCodes.Dup);
672                                         temporary.Store (ec);
673                                         have_temporary = true;
674                                 }
675                         } else 
676                                 expr.Emit (ec);
677
678                         source.Emit (ec);
679                         StoreFromPtr (ec.ig, type);
680                 }
681                 
682                 public void AddressOf (EmitContext ec, AddressOp Mode)
683                 {
684                         if (temporary != null){
685                                 if (have_temporary){
686                                         temporary.Emit (ec);
687                                         return;
688                                 }
689                                 expr.Emit (ec);
690                                 ec.ig.Emit (OpCodes.Dup);
691                                 temporary.Store (ec);
692                                 have_temporary = true;
693                         } else
694                                 expr.Emit (ec);
695                 }
696
697                 public override Expression DoResolve (EmitContext ec)
698                 {
699                         //
700                         // Born fully resolved
701                         //
702                         return this;
703                 }
704
705                 public new void CacheTemporaries (EmitContext ec)
706                 {
707                         temporary = new LocalTemporary (ec, expr.Type);
708                 }
709
710                 public override string ToString ()
711                 {
712                         return "*(" + expr + ")";
713                 }
714         }
715         
716         /// <summary>
717         ///   Unary Mutator expressions (pre and post ++ and --)
718         /// </summary>
719         ///
720         /// <remarks>
721         ///   UnaryMutator implements ++ and -- expressions.   It derives from
722         ///   ExpressionStatement becuase the pre/post increment/decrement
723         ///   operators can be used in a statement context.
724         ///
725         /// FIXME: Idea, we could split this up in two classes, one simpler
726         /// for the common case, and one with the extra fields for more complex
727         /// classes (indexers require temporary access;  overloaded require method)
728         ///
729         /// </remarks>
730         public class UnaryMutator : ExpressionStatement {
731                 [Flags]
732                 public enum Mode : byte {
733                         IsIncrement    = 0,
734                         IsDecrement    = 1,
735                         IsPre          = 0,
736                         IsPost         = 2,
737                         
738                         PreIncrement   = 0,
739                         PreDecrement   = IsDecrement,
740                         PostIncrement  = IsPost,
741                         PostDecrement  = IsPost | IsDecrement
742                 }
743                 
744                 Mode mode;
745                 Expression expr;
746                 LocalTemporary temp_storage;
747
748                 //
749                 // This is expensive for the simplest case.
750                 //
751                 Expression method;
752                         
753                 public UnaryMutator (Mode m, Expression e, Location l)
754                 {
755                         mode = m;
756                         loc = l;
757                         expr = e;
758                 }
759
760                 static string OperName (Mode mode)
761                 {
762                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
763                                 "++" : "--";
764                 }
765                 
766                 void Error23 (Type t)
767                 {
768                         Error (
769                                 23, "Operator " + OperName (mode) + 
770                                 " cannot be applied to operand of type `" +
771                                 TypeManager.CSharpName (t) + "'");
772                 }
773
774                 /// <summary>
775                 ///   Returns whether an object of type `t' can be incremented
776                 ///   or decremented with add/sub (ie, basically whether we can
777                 ///   use pre-post incr-decr operations on it, but it is not a
778                 ///   System.Decimal, which we require operator overloading to catch)
779                 /// </summary>
780                 static bool IsIncrementableNumber (Type t)
781                 {
782                         return (t == TypeManager.sbyte_type) ||
783                                 (t == TypeManager.byte_type) ||
784                                 (t == TypeManager.short_type) ||
785                                 (t == TypeManager.ushort_type) ||
786                                 (t == TypeManager.int32_type) ||
787                                 (t == TypeManager.uint32_type) ||
788                                 (t == TypeManager.int64_type) ||
789                                 (t == TypeManager.uint64_type) ||
790                                 (t == TypeManager.char_type) ||
791                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
792                                 (t == TypeManager.float_type) ||
793                                 (t == TypeManager.double_type) ||
794                                 (t.IsPointer && t != TypeManager.void_ptr_type);
795                 }
796
797                 Expression ResolveOperator (EmitContext ec)
798                 {
799                         Type expr_type = expr.Type;
800
801                         //
802                         // Step 1: Perform Operator Overload location
803                         //
804                         Expression mg;
805                         string op_name;
806                         
807                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
808                                 op_name = "op_Increment";
809                         else 
810                                 op_name = "op_Decrement";
811
812                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
813
814                         if (mg == null && expr_type.BaseType != null)
815                                 mg = MemberLookup (ec, expr_type.BaseType, op_name,
816                                                    MemberTypes.Method, AllBindingFlags, loc);
817                         
818                         if (mg != null) {
819                                 method = StaticCallExpr.MakeSimpleCall (
820                                         ec, (MethodGroupExpr) mg, expr, loc);
821
822                                 type = method.Type;
823                                 return this;
824                         }
825
826                         //
827                         // The operand of the prefix/postfix increment decrement operators
828                         // should be an expression that is classified as a variable,
829                         // a property access or an indexer access
830                         //
831                         type = expr_type;
832                         if (expr.eclass == ExprClass.Variable){
833                                 LocalVariableReference var = expr as LocalVariableReference;
834                                 if ((var != null) && var.IsReadOnly)
835                                         Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
836                                 if (IsIncrementableNumber (expr_type) ||
837                                     expr_type == TypeManager.decimal_type){
838                                         return this;
839                                 }
840                         } else if (expr.eclass == ExprClass.IndexerAccess){
841                                 IndexerAccess ia = (IndexerAccess) expr;
842                                 
843                                 temp_storage = new LocalTemporary (ec, expr.Type);
844                                 
845                                 expr = ia.ResolveLValue (ec, temp_storage);
846                                 if (expr == null)
847                                         return null;
848
849                                 return this;
850                         } else if (expr.eclass == ExprClass.PropertyAccess){
851                                 PropertyExpr pe = (PropertyExpr) expr;
852
853                                 if (pe.VerifyAssignable ())
854                                         return this;
855
856                                 return null;
857                         } else {
858                                 expr.Error_UnexpectedKind ("variable, indexer or property access");
859                                 return null;
860                         }
861
862                         Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
863                                TypeManager.CSharpName (expr_type) + "'");
864                         return null;
865                 }
866
867                 public override Expression DoResolve (EmitContext ec)
868                 {
869                         expr = expr.Resolve (ec);
870                         
871                         if (expr == null)
872                                 return null;
873
874                         eclass = ExprClass.Value;
875                         return ResolveOperator (ec);
876                 }
877
878                 static int PtrTypeSize (Type t)
879                 {
880                         return GetTypeSize (TypeManager.GetElementType (t));
881                 }
882
883                 //
884                 // Loads the proper "1" into the stack based on the type, then it emits the
885                 // opcode for the operation requested
886                 //
887                 void LoadOneAndEmitOp (EmitContext ec, Type t)
888                 {
889                         //
890                         // Measure if getting the typecode and using that is more/less efficient
891                         // that comparing types.  t.GetTypeCode() is an internal call.
892                         //
893                         ILGenerator ig = ec.ig;
894                                                      
895                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
896                                 LongConstant.EmitLong (ig, 1);
897                         else if (t == TypeManager.double_type)
898                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
899                         else if (t == TypeManager.float_type)
900                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
901                         else if (t.IsPointer){
902                                 int n = PtrTypeSize (t);
903                                 
904                                 if (n == 0)
905                                         ig.Emit (OpCodes.Sizeof, t);
906                                 else
907                                         IntConstant.EmitInt (ig, n);
908                         } else 
909                                 ig.Emit (OpCodes.Ldc_I4_1);
910
911                         //
912                         // Now emit the operation
913                         //
914                         if (ec.CheckState){
915                                 if (t == TypeManager.int32_type ||
916                                     t == TypeManager.int64_type){
917                                         if ((mode & Mode.IsDecrement) != 0)
918                                                 ig.Emit (OpCodes.Sub_Ovf);
919                                         else
920                                                 ig.Emit (OpCodes.Add_Ovf);
921                                 } else if (t == TypeManager.uint32_type ||
922                                            t == TypeManager.uint64_type){
923                                         if ((mode & Mode.IsDecrement) != 0)
924                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
925                                         else
926                                                 ig.Emit (OpCodes.Add_Ovf_Un);
927                                 } else {
928                                         if ((mode & Mode.IsDecrement) != 0)
929                                                 ig.Emit (OpCodes.Sub_Ovf);
930                                         else
931                                                 ig.Emit (OpCodes.Add_Ovf);
932                                 }
933                         } else {
934                                 if ((mode & Mode.IsDecrement) != 0)
935                                         ig.Emit (OpCodes.Sub);
936                                 else
937                                         ig.Emit (OpCodes.Add);
938                         }
939
940                         if (t == TypeManager.sbyte_type){
941                                 if (ec.CheckState)
942                                         ig.Emit (OpCodes.Conv_Ovf_I1);
943                                 else
944                                         ig.Emit (OpCodes.Conv_I1);
945                         } else if (t == TypeManager.byte_type){
946                                 if (ec.CheckState)
947                                         ig.Emit (OpCodes.Conv_Ovf_U1);
948                                 else
949                                         ig.Emit (OpCodes.Conv_U1);
950                         } else if (t == TypeManager.short_type){
951                                 if (ec.CheckState)
952                                         ig.Emit (OpCodes.Conv_Ovf_I2);
953                                 else
954                                         ig.Emit (OpCodes.Conv_I2);
955                         } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
956                                 if (ec.CheckState)
957                                         ig.Emit (OpCodes.Conv_Ovf_U2);
958                                 else
959                                         ig.Emit (OpCodes.Conv_U2);
960                         }
961                         
962                 }
963
964                 static EmptyExpression empty_expr;
965                 
966                 void EmitCode (EmitContext ec, bool is_expr)
967                 {
968                         ILGenerator ig = ec.ig;
969                         IAssignMethod ia = (IAssignMethod) expr;
970                         Type expr_type = expr.Type;
971
972                         ia.CacheTemporaries (ec);
973
974                         if (temp_storage == null){
975                                 //
976                                 // Temporary improvement: if we are dealing with something that does
977                                 // not require complicated instance setup, avoid using a temporary
978                                 //
979                                 // For now: only localvariables when not remapped
980                                 //
981
982                                 if (method == null &&
983                                     ((expr is LocalVariableReference) ||(expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic))){
984                                         if (empty_expr == null)
985                                                 empty_expr = new EmptyExpression ();
986                                         
987                                         switch (mode){
988                                         case Mode.PreIncrement:
989                                         case Mode.PreDecrement:
990                                                 expr.Emit (ec);
991                                         
992                                                 LoadOneAndEmitOp (ec, expr_type);
993                                                 if (is_expr)
994                                                         ig.Emit (OpCodes.Dup);
995                                                 ia.EmitAssign (ec, empty_expr);
996                                                 break;
997                                                 
998                                         case Mode.PostIncrement:
999                                         case Mode.PostDecrement:
1000                                                 expr.Emit (ec);
1001                                                 if (is_expr)
1002                                                         ig.Emit (OpCodes.Dup);
1003                                                 
1004                                                 LoadOneAndEmitOp (ec, expr_type);
1005                                                 ia.EmitAssign (ec, empty_expr);
1006                                                 break;
1007                                         }
1008                                         return;
1009                                 }
1010                                 temp_storage = new LocalTemporary (ec, expr_type);
1011                         }
1012                         
1013                         switch (mode){
1014                         case Mode.PreIncrement:
1015                         case Mode.PreDecrement:
1016                                 if (method == null){
1017                                         expr.Emit (ec);
1018                                         
1019                                         LoadOneAndEmitOp (ec, expr_type);
1020                                 } else 
1021                                         method.Emit (ec);
1022                                 
1023                                 temp_storage.Store (ec);
1024                                 ia.EmitAssign (ec, temp_storage);
1025                                 if (is_expr)
1026                                         temp_storage.Emit (ec);
1027                                 break;
1028                                 
1029                         case Mode.PostIncrement:
1030                         case Mode.PostDecrement:
1031                                 if (is_expr)
1032                                         expr.Emit (ec);
1033                                 
1034                                 if (method == null){
1035                                         if (!is_expr)
1036                                                 expr.Emit (ec);
1037                                         else
1038                                                 ig.Emit (OpCodes.Dup);
1039                                         
1040                                         LoadOneAndEmitOp (ec, expr_type);
1041                                 } else {
1042                                         method.Emit (ec);
1043                                 }
1044                                 
1045                                 temp_storage.Store (ec);
1046                                 ia.EmitAssign (ec, temp_storage);
1047                                 break;
1048                         }
1049
1050                         temp_storage.Release (ec);
1051                 }
1052
1053                 public override void Emit (EmitContext ec)
1054                 {
1055                         EmitCode (ec, true);
1056                         
1057                 }
1058                 
1059                 public override void EmitStatement (EmitContext ec)
1060                 {
1061                         EmitCode (ec, false);
1062                 }
1063
1064         }
1065
1066         /// <summary>
1067         ///   Base class for the `Is' and `As' classes. 
1068         /// </summary>
1069         ///
1070         /// <remarks>
1071         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
1072         ///   size. 
1073         /// </remarks>
1074         public abstract class Probe : Expression {
1075                 public readonly Expression ProbeType;
1076                 protected Expression expr;
1077                 protected Type probe_type;
1078                 
1079                 public Probe (Expression expr, Expression probe_type, Location l)
1080                 {
1081                         ProbeType = probe_type;
1082                         loc = l;
1083                         this.expr = expr;
1084                 }
1085
1086                 public Expression Expr {
1087                         get {
1088                                 return expr;
1089                         }
1090                 }
1091
1092                 public override Expression DoResolve (EmitContext ec)
1093                 {
1094                         probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1095
1096                         if (probe_type == null)
1097                                 return null;
1098
1099                         expr = expr.Resolve (ec);
1100                         if (expr == null)
1101                                 return null;
1102                         
1103                         return this;
1104                 }
1105         }
1106
1107         /// <summary>
1108         ///   Implementation of the `is' operator.
1109         /// </summary>
1110         public class Is : Probe {
1111                 public Is (Expression expr, Expression probe_type, Location l)
1112                         : base (expr, probe_type, l)
1113                 {
1114                 }
1115
1116                 enum Action {
1117                         AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1118                 }
1119
1120                 Action action;
1121                 
1122                 public override void Emit (EmitContext ec)
1123                 {
1124                         ILGenerator ig = ec.ig;
1125
1126                         expr.Emit (ec);
1127
1128                         switch (action){
1129                         case Action.AlwaysFalse:
1130                                 ig.Emit (OpCodes.Pop);
1131                                 IntConstant.EmitInt (ig, 0);
1132                                 return;
1133                         case Action.AlwaysTrue:
1134                                 ig.Emit (OpCodes.Pop);
1135                                 IntConstant.EmitInt (ig, 1);
1136                                 return;
1137                         case Action.LeaveOnStack:
1138                                 // the `e != null' rule.
1139                                 ig.Emit (OpCodes.Ldnull);
1140                                 ig.Emit (OpCodes.Ceq);
1141                                 ig.Emit (OpCodes.Ldc_I4_0);
1142                                 ig.Emit (OpCodes.Ceq);
1143                                 return;
1144                         case Action.Probe:
1145                                 ig.Emit (OpCodes.Isinst, probe_type);
1146                                 ig.Emit (OpCodes.Ldnull);
1147                                 ig.Emit (OpCodes.Cgt_Un);
1148                                 return;
1149                         }
1150                         throw new Exception ("never reached");
1151                 }
1152                 
1153                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1154                 {
1155                         ILGenerator ig = ec.ig;
1156
1157                         switch (action){
1158                         case Action.AlwaysFalse:
1159                                 if (! onTrue)
1160                                         ig.Emit (OpCodes.Br, target);
1161                                 
1162                                 return;
1163                         case Action.AlwaysTrue:
1164                                 if (onTrue)
1165                                         ig.Emit (OpCodes.Br, target);
1166                                 
1167                                 return;
1168                         case Action.LeaveOnStack:
1169                                 // the `e != null' rule.
1170                                 expr.Emit (ec);
1171                                 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1172                                 return;
1173                         case Action.Probe:
1174                                 expr.Emit (ec);
1175                                 ig.Emit (OpCodes.Isinst, probe_type);
1176                                 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1177                                 return;
1178                         }
1179                         throw new Exception ("never reached");
1180                 }
1181
1182                 public override Expression DoResolve (EmitContext ec)
1183                 {
1184                         Expression e = base.DoResolve (ec);
1185
1186                         if ((e == null) || (expr == null))
1187                                 return null;
1188
1189                         Type etype = expr.Type;
1190                         bool warning_always_matches = false;
1191                         bool warning_never_matches = false;
1192
1193                         type = TypeManager.bool_type;
1194                         eclass = ExprClass.Value;
1195
1196                         //
1197                         // First case, if at compile time, there is an implicit conversion
1198                         // then e != null (objects) or true (value types)
1199                         //
1200                         e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1201                         if (e != null){
1202                                 expr = e;
1203                                 if (etype.IsValueType)
1204                                         action = Action.AlwaysTrue;
1205                                 else
1206                                         action = Action.LeaveOnStack;
1207
1208                                 warning_always_matches = true;
1209                         } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1210                                 //
1211                                 // Second case: explicit reference convresion
1212                                 //
1213                                 if (expr is NullLiteral)
1214                                         action = Action.AlwaysFalse;
1215                                 else
1216                                         action = Action.Probe;
1217                         } else {
1218                                 action = Action.AlwaysFalse;
1219                                 warning_never_matches = true;
1220                         }
1221                         
1222                         if (RootContext.WarningLevel >= 1){
1223                                 if (warning_always_matches)
1224                                         Warning (183, "The expression is always of type `" +
1225                                                  TypeManager.CSharpName (probe_type) + "'");
1226                                 else if (warning_never_matches){
1227                                         if (!(probe_type.IsInterface || expr.Type.IsInterface))
1228                                                 Warning (184,
1229                                                          "The expression is never of type `" +
1230                                                          TypeManager.CSharpName (probe_type) + "'");
1231                                 }
1232                         }
1233
1234                         return this;
1235                 }                               
1236         }
1237
1238         /// <summary>
1239         ///   Implementation of the `as' operator.
1240         /// </summary>
1241         public class As : Probe {
1242                 public As (Expression expr, Expression probe_type, Location l)
1243                         : base (expr, probe_type, l)
1244                 {
1245                 }
1246
1247                 bool do_isinst = false;
1248                 
1249                 public override void Emit (EmitContext ec)
1250                 {
1251                         ILGenerator ig = ec.ig;
1252
1253                         expr.Emit (ec);
1254
1255                         if (do_isinst)
1256                                 ig.Emit (OpCodes.Isinst, probe_type);
1257                 }
1258
1259                 static void Error_CannotConvertType (Type source, Type target, Location loc)
1260                 {
1261                         Report.Error (
1262                                 39, loc, "as operator can not convert from `" +
1263                                 TypeManager.CSharpName (source) + "' to `" +
1264                                 TypeManager.CSharpName (target) + "'");
1265                 }
1266                 
1267                 public override Expression DoResolve (EmitContext ec)
1268                 {
1269                         Expression e = base.DoResolve (ec);
1270
1271                         if (e == null)
1272                                 return null;
1273
1274                         type = probe_type;
1275                         eclass = ExprClass.Value;
1276                         Type etype = expr.Type;
1277
1278                         if (TypeManager.IsValueType (probe_type)){
1279                                 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1280                                               TypeManager.CSharpName (probe_type) + " is a value type)");
1281                                 return null;
1282                         
1283                         }
1284                         
1285                         e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
1286                         if (e != null){
1287                                 expr = e;
1288                                 do_isinst = false;
1289                                 return this;
1290                         }
1291
1292                         if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1293                                 do_isinst = true;
1294                                 return this;
1295                         }
1296
1297                         Error_CannotConvertType (etype, probe_type, loc);
1298                         return null;
1299                 }                               
1300         }
1301         
1302         /// <summary>
1303         ///   This represents a typecast in the source language.
1304         ///
1305         ///   FIXME: Cast expressions have an unusual set of parsing
1306         ///   rules, we need to figure those out.
1307         /// </summary>
1308         public class Cast : Expression {
1309                 Expression target_type;
1310                 Expression expr;
1311                         
1312                 public Cast (Expression cast_type, Expression expr, Location loc)
1313                 {
1314                         this.target_type = cast_type;
1315                         this.expr = expr;
1316                         this.loc = loc;
1317                 }
1318
1319                 public Expression TargetType {
1320                         get {
1321                                 return target_type;
1322                         }
1323                 }
1324
1325                 public Expression Expr {
1326                         get {
1327                                 return expr;
1328                         }
1329                         set {
1330                                 expr = value;
1331                         }
1332                 }
1333
1334                 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1335                 {
1336                         if (!ec.ConstantCheckState)
1337                                 return true;
1338
1339                         if ((value < min) || (value > max)) {
1340                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1341                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1342                                        "syntax to override)");
1343                                 return false;
1344                         }
1345
1346                         return true;
1347                 }
1348
1349                 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1350                 {
1351                         if (!ec.ConstantCheckState)
1352                                 return true;
1353
1354                         if (value > max) {
1355                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1356                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1357                                        "syntax to override)");
1358                                 return false;
1359                         }
1360
1361                         return true;
1362                 }
1363
1364                 bool CheckUnsigned (EmitContext ec, long value, Type type)
1365                 {
1366                         if (!ec.ConstantCheckState)
1367                                 return true;
1368
1369                         if (value < 0) {
1370                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1371                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1372                                        "syntax to override)");
1373                                 return false;
1374                         }
1375
1376                         return true;
1377                 }
1378
1379                 /// <summary>
1380                 ///   Attempts to do a compile-time folding of a constant cast.
1381                 /// </summary>
1382                 Expression TryReduce (EmitContext ec, Type target_type)
1383                 {
1384                         Expression real_expr = expr;
1385                         if (real_expr is EnumConstant)
1386                                 real_expr = ((EnumConstant) real_expr).Child;
1387                                 
1388                         if (real_expr is ByteConstant){
1389                                 byte v = ((ByteConstant) real_expr).Value;
1390         
1391                                 if (target_type == TypeManager.sbyte_type) {
1392                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1393                                                 return null;
1394                                         return new SByteConstant ((sbyte) v);
1395                                 }
1396                                 if (target_type == TypeManager.short_type)
1397                                         return new ShortConstant ((short) v);
1398                                 if (target_type == TypeManager.ushort_type)
1399                                         return new UShortConstant ((ushort) v);
1400                                 if (target_type == TypeManager.int32_type)
1401                                         return new IntConstant ((int) v);
1402                                 if (target_type == TypeManager.uint32_type)
1403                                         return new UIntConstant ((uint) v);
1404                                 if (target_type == TypeManager.int64_type)
1405                                         return new LongConstant ((long) v);
1406                                 if (target_type == TypeManager.uint64_type)
1407                                         return new ULongConstant ((ulong) v);
1408                                 if (target_type == TypeManager.float_type)
1409                                         return new FloatConstant ((float) v);
1410                                 if (target_type == TypeManager.double_type)
1411                                         return new DoubleConstant ((double) v);
1412                                 if (target_type == TypeManager.char_type)
1413                                         return new CharConstant ((char) v);
1414                                 if (target_type == TypeManager.decimal_type)
1415                                         return new DecimalConstant ((decimal) v);
1416                         }
1417                         if (real_expr is SByteConstant){
1418                                 sbyte v = ((SByteConstant) real_expr).Value;
1419         
1420                                 if (target_type == TypeManager.byte_type) {
1421                                         if (!CheckUnsigned (ec, v, target_type))
1422                                                 return null;
1423                                         return new ByteConstant ((byte) v);
1424                                 }
1425                                 if (target_type == TypeManager.short_type)
1426                                         return new ShortConstant ((short) v);
1427                                 if (target_type == TypeManager.ushort_type) {
1428                                         if (!CheckUnsigned (ec, v, target_type))
1429                                                 return null;
1430                                         return new UShortConstant ((ushort) v);
1431                                 } if (target_type == TypeManager.int32_type)
1432                                         return new IntConstant ((int) v);
1433                                 if (target_type == TypeManager.uint32_type) {
1434                                         if (!CheckUnsigned (ec, v, target_type))
1435                                                 return null;
1436                                         return new UIntConstant ((uint) v);
1437                                 } if (target_type == TypeManager.int64_type)
1438                                         return new LongConstant ((long) v);
1439                                 if (target_type == TypeManager.uint64_type) {
1440                                         if (!CheckUnsigned (ec, v, target_type))
1441                                                 return null;
1442                                         return new ULongConstant ((ulong) v);
1443                                 }
1444                                 if (target_type == TypeManager.float_type)
1445                                         return new FloatConstant ((float) v);
1446                                 if (target_type == TypeManager.double_type)
1447                                         return new DoubleConstant ((double) v);
1448                                 if (target_type == TypeManager.char_type) {
1449                                         if (!CheckUnsigned (ec, v, target_type))
1450                                                 return null;
1451                                         return new CharConstant ((char) v);
1452                                 }
1453                                 if (target_type == TypeManager.decimal_type)
1454                                         return new DecimalConstant ((decimal) v);
1455                         }
1456                         if (real_expr is ShortConstant){
1457                                 short v = ((ShortConstant) real_expr).Value;
1458         
1459                                 if (target_type == TypeManager.byte_type) {
1460                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1461                                                 return null;
1462                                         return new ByteConstant ((byte) v);
1463                                 }
1464                                 if (target_type == TypeManager.sbyte_type) {
1465                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1466                                                 return null;
1467                                         return new SByteConstant ((sbyte) v);
1468                                 }
1469                                 if (target_type == TypeManager.ushort_type) {
1470                                         if (!CheckUnsigned (ec, v, target_type))
1471                                                 return null;
1472                                         return new UShortConstant ((ushort) v);
1473                                 }
1474                                 if (target_type == TypeManager.int32_type)
1475                                         return new IntConstant ((int) v);
1476                                 if (target_type == TypeManager.uint32_type) {
1477                                         if (!CheckUnsigned (ec, v, target_type))
1478                                                 return null;
1479                                         return new UIntConstant ((uint) v);
1480                                 }
1481                                 if (target_type == TypeManager.int64_type)
1482                                         return new LongConstant ((long) v);
1483                                 if (target_type == TypeManager.uint64_type) {
1484                                         if (!CheckUnsigned (ec, v, target_type))
1485                                                 return null;
1486                                         return new ULongConstant ((ulong) v);
1487                                 }
1488                                 if (target_type == TypeManager.float_type)
1489                                         return new FloatConstant ((float) v);
1490                                 if (target_type == TypeManager.double_type)
1491                                         return new DoubleConstant ((double) v);
1492                                 if (target_type == TypeManager.char_type) {
1493                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1494                                                 return null;
1495                                         return new CharConstant ((char) v);
1496                                 }
1497                                 if (target_type == TypeManager.decimal_type)
1498                                         return new DecimalConstant ((decimal) v);
1499                         }
1500                         if (real_expr is UShortConstant){
1501                                 ushort v = ((UShortConstant) real_expr).Value;
1502         
1503                                 if (target_type == TypeManager.byte_type) {
1504                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1505                                                 return null;
1506                                         return new ByteConstant ((byte) v);
1507                                 }
1508                                 if (target_type == TypeManager.sbyte_type) {
1509                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1510                                                 return null;
1511                                         return new SByteConstant ((sbyte) v);
1512                                 }
1513                                 if (target_type == TypeManager.short_type) {
1514                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1515                                                 return null;
1516                                         return new ShortConstant ((short) v);
1517                                 }
1518                                 if (target_type == TypeManager.int32_type)
1519                                         return new IntConstant ((int) v);
1520                                 if (target_type == TypeManager.uint32_type)
1521                                         return new UIntConstant ((uint) v);
1522                                 if (target_type == TypeManager.int64_type)
1523                                         return new LongConstant ((long) v);
1524                                 if (target_type == TypeManager.uint64_type)
1525                                         return new ULongConstant ((ulong) v);
1526                                 if (target_type == TypeManager.float_type)
1527                                         return new FloatConstant ((float) v);
1528                                 if (target_type == TypeManager.double_type)
1529                                         return new DoubleConstant ((double) v);
1530                                 if (target_type == TypeManager.char_type) {
1531                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1532                                                 return null;
1533                                         return new CharConstant ((char) v);
1534                                 }
1535                                 if (target_type == TypeManager.decimal_type)
1536                                         return new DecimalConstant ((decimal) v);
1537                         }
1538                         if (real_expr is IntConstant){
1539                                 int v = ((IntConstant) real_expr).Value;
1540         
1541                                 if (target_type == TypeManager.byte_type) {
1542                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1543                                                 return null;
1544                                         return new ByteConstant ((byte) v);
1545                                 }
1546                                 if (target_type == TypeManager.sbyte_type) {
1547                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1548                                                 return null;
1549                                         return new SByteConstant ((sbyte) v);
1550                                 }
1551                                 if (target_type == TypeManager.short_type) {
1552                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1553                                                 return null;
1554                                         return new ShortConstant ((short) v);
1555                                 }
1556                                 if (target_type == TypeManager.ushort_type) {
1557                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1558                                                 return null;
1559                                         return new UShortConstant ((ushort) v);
1560                                 }
1561                                 if (target_type == TypeManager.uint32_type) {
1562                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1563                                                 return null;
1564                                         return new UIntConstant ((uint) v);
1565                                 }
1566                                 if (target_type == TypeManager.int64_type)
1567                                         return new LongConstant ((long) v);
1568                                 if (target_type == TypeManager.uint64_type) {
1569                                         if (!CheckUnsigned (ec, v, target_type))
1570                                                 return null;
1571                                         return new ULongConstant ((ulong) v);
1572                                 }
1573                                 if (target_type == TypeManager.float_type)
1574                                         return new FloatConstant ((float) v);
1575                                 if (target_type == TypeManager.double_type)
1576                                         return new DoubleConstant ((double) v);
1577                                 if (target_type == TypeManager.char_type) {
1578                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1579                                                 return null;
1580                                         return new CharConstant ((char) v);
1581                                 }
1582                                 if (target_type == TypeManager.decimal_type)
1583                                         return new DecimalConstant ((decimal) v);
1584                         }
1585                         if (real_expr is UIntConstant){
1586                                 uint v = ((UIntConstant) real_expr).Value;
1587         
1588                                 if (target_type == TypeManager.byte_type) {
1589                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1590                                                 return null;
1591                                         return new ByteConstant ((byte) v);
1592                                 }
1593                                 if (target_type == TypeManager.sbyte_type) {
1594                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1595                                                 return null;
1596                                         return new SByteConstant ((sbyte) v);
1597                                 }
1598                                 if (target_type == TypeManager.short_type) {
1599                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1600                                                 return null;
1601                                         return new ShortConstant ((short) v);
1602                                 }
1603                                 if (target_type == TypeManager.ushort_type) {
1604                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1605                                                 return null;
1606                                         return new UShortConstant ((ushort) v);
1607                                 }
1608                                 if (target_type == TypeManager.int32_type) {
1609                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1610                                                 return null;
1611                                         return new IntConstant ((int) v);
1612                                 }
1613                                 if (target_type == TypeManager.int64_type)
1614                                         return new LongConstant ((long) v);
1615                                 if (target_type == TypeManager.uint64_type)
1616                                         return new ULongConstant ((ulong) v);
1617                                 if (target_type == TypeManager.float_type)
1618                                         return new FloatConstant ((float) v);
1619                                 if (target_type == TypeManager.double_type)
1620                                         return new DoubleConstant ((double) v);
1621                                 if (target_type == TypeManager.char_type) {
1622                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1623                                                 return null;
1624                                         return new CharConstant ((char) v);
1625                                 }
1626                                 if (target_type == TypeManager.decimal_type)
1627                                         return new DecimalConstant ((decimal) v);
1628                         }
1629                         if (real_expr is LongConstant){
1630                                 long v = ((LongConstant) real_expr).Value;
1631         
1632                                 if (target_type == TypeManager.byte_type) {
1633                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1634                                                 return null;
1635                                         return new ByteConstant ((byte) v);
1636                                 }
1637                                 if (target_type == TypeManager.sbyte_type) {
1638                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1639                                                 return null;
1640                                         return new SByteConstant ((sbyte) v);
1641                                 }
1642                                 if (target_type == TypeManager.short_type) {
1643                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1644                                                 return null;
1645                                         return new ShortConstant ((short) v);
1646                                 }
1647                                 if (target_type == TypeManager.ushort_type) {
1648                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1649                                                 return null;
1650                                         return new UShortConstant ((ushort) v);
1651                                 }
1652                                 if (target_type == TypeManager.int32_type) {
1653                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1654                                                 return null;
1655                                         return new IntConstant ((int) v);
1656                                 }
1657                                 if (target_type == TypeManager.uint32_type) {
1658                                         if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1659                                                 return null;
1660                                         return new UIntConstant ((uint) v);
1661                                 }
1662                                 if (target_type == TypeManager.uint64_type) {
1663                                         if (!CheckUnsigned (ec, v, target_type))
1664                                                 return null;
1665                                         return new ULongConstant ((ulong) v);
1666                                 }
1667                                 if (target_type == TypeManager.float_type)
1668                                         return new FloatConstant ((float) v);
1669                                 if (target_type == TypeManager.double_type)
1670                                         return new DoubleConstant ((double) v);
1671                                 if (target_type == TypeManager.char_type) {
1672                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1673                                                 return null;
1674                                         return new CharConstant ((char) v);
1675                                 }
1676                                 if (target_type == TypeManager.decimal_type)
1677                                         return new DecimalConstant ((decimal) v);
1678                         }
1679                         if (real_expr is ULongConstant){
1680                                 ulong v = ((ULongConstant) real_expr).Value;
1681         
1682                                 if (target_type == TypeManager.byte_type) {
1683                                         if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1684                                                 return null;
1685                                         return new ByteConstant ((byte) v);
1686                                 }
1687                                 if (target_type == TypeManager.sbyte_type) {
1688                                         if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1689                                                 return null;
1690                                         return new SByteConstant ((sbyte) v);
1691                                 }
1692                                 if (target_type == TypeManager.short_type) {
1693                                         if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1694                                                 return null;
1695                                         return new ShortConstant ((short) v);
1696                                 }
1697                                 if (target_type == TypeManager.ushort_type) {
1698                                         if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1699                                                 return null;
1700                                         return new UShortConstant ((ushort) v);
1701                                 }
1702                                 if (target_type == TypeManager.int32_type) {
1703                                         if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1704                                                 return null;
1705                                         return new IntConstant ((int) v);
1706                                 }
1707                                 if (target_type == TypeManager.uint32_type) {
1708                                         if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1709                                                 return null;
1710                                         return new UIntConstant ((uint) v);
1711                                 }
1712                                 if (target_type == TypeManager.int64_type) {
1713                                         if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1714                                                 return null;
1715                                         return new LongConstant ((long) v);
1716                                 }
1717                                 if (target_type == TypeManager.float_type)
1718                                         return new FloatConstant ((float) v);
1719                                 if (target_type == TypeManager.double_type)
1720                                         return new DoubleConstant ((double) v);
1721                                 if (target_type == TypeManager.char_type) {
1722                                         if (!CheckRange (ec, v, target_type, Char.MaxValue))
1723                                                 return null;
1724                                         return new CharConstant ((char) v);
1725                                 }
1726                                 if (target_type == TypeManager.decimal_type)
1727                                         return new DecimalConstant ((decimal) v);
1728                         }
1729                         if (real_expr is FloatConstant){
1730                                 float v = ((FloatConstant) real_expr).Value;
1731         
1732                                 if (target_type == TypeManager.byte_type)
1733                                         return new ByteConstant ((byte) v);
1734                                 if (target_type == TypeManager.sbyte_type)
1735                                         return new SByteConstant ((sbyte) v);
1736                                 if (target_type == TypeManager.short_type)
1737                                         return new ShortConstant ((short) v);
1738                                 if (target_type == TypeManager.ushort_type)
1739                                         return new UShortConstant ((ushort) v);
1740                                 if (target_type == TypeManager.int32_type)
1741                                         return new IntConstant ((int) v);
1742                                 if (target_type == TypeManager.uint32_type)
1743                                         return new UIntConstant ((uint) v);
1744                                 if (target_type == TypeManager.int64_type)
1745                                         return new LongConstant ((long) v);
1746                                 if (target_type == TypeManager.uint64_type)
1747                                         return new ULongConstant ((ulong) v);
1748                                 if (target_type == TypeManager.double_type)
1749                                         return new DoubleConstant ((double) v);
1750                                 if (target_type == TypeManager.char_type)
1751                                         return new CharConstant ((char) v);
1752                                 if (target_type == TypeManager.decimal_type)
1753                                         return new DecimalConstant ((decimal) v);
1754                         }
1755                         if (real_expr is DoubleConstant){
1756                                 double v = ((DoubleConstant) real_expr).Value;
1757         
1758                                 if (target_type == TypeManager.byte_type){
1759                                         return new ByteConstant ((byte) v);
1760                                 } if (target_type == TypeManager.sbyte_type)
1761                                         return new SByteConstant ((sbyte) v);
1762                                 if (target_type == TypeManager.short_type)
1763                                         return new ShortConstant ((short) v);
1764                                 if (target_type == TypeManager.ushort_type)
1765                                         return new UShortConstant ((ushort) v);
1766                                 if (target_type == TypeManager.int32_type)
1767                                         return new IntConstant ((int) v);
1768                                 if (target_type == TypeManager.uint32_type)
1769                                         return new UIntConstant ((uint) v);
1770                                 if (target_type == TypeManager.int64_type)
1771                                         return new LongConstant ((long) v);
1772                                 if (target_type == TypeManager.uint64_type)
1773                                         return new ULongConstant ((ulong) v);
1774                                 if (target_type == TypeManager.float_type)
1775                                         return new FloatConstant ((float) v);
1776                                 if (target_type == TypeManager.char_type)
1777                                         return new CharConstant ((char) v);
1778                                 if (target_type == TypeManager.decimal_type)
1779                                         return new DecimalConstant ((decimal) v);
1780                         }
1781
1782                         if (real_expr is CharConstant){
1783                                 char v = ((CharConstant) real_expr).Value;
1784                                 
1785                                 if (target_type == TypeManager.byte_type) {
1786                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1787                                                 return null;
1788                                         return new ByteConstant ((byte) v);
1789                                 }
1790                                 if (target_type == TypeManager.sbyte_type) {
1791                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1792                                                 return null;
1793                                         return new SByteConstant ((sbyte) v);
1794                                 }
1795                                 if (target_type == TypeManager.short_type) {
1796                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1797                                                 return null;
1798                                         return new ShortConstant ((short) v);
1799                                 }
1800                                 if (target_type == TypeManager.int32_type)
1801                                         return new IntConstant ((int) v);
1802                                 if (target_type == TypeManager.uint32_type)
1803                                         return new UIntConstant ((uint) v);
1804                                 if (target_type == TypeManager.int64_type)
1805                                         return new LongConstant ((long) v);
1806                                 if (target_type == TypeManager.uint64_type)
1807                                         return new ULongConstant ((ulong) v);
1808                                 if (target_type == TypeManager.float_type)
1809                                         return new FloatConstant ((float) v);
1810                                 if (target_type == TypeManager.double_type)
1811                                         return new DoubleConstant ((double) v);
1812                                 if (target_type == TypeManager.char_type) {
1813                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1814                                                 return null;
1815                                         return new CharConstant ((char) v);
1816                                 }
1817                                 if (target_type == TypeManager.decimal_type)
1818                                         return new DecimalConstant ((decimal) v);
1819                         }
1820
1821                         return null;
1822                 }
1823                 
1824                 public override Expression DoResolve (EmitContext ec)
1825                 {
1826                         expr = expr.Resolve (ec);
1827                         if (expr == null)
1828                                 return null;
1829
1830                         type = ec.DeclSpace.ResolveType (target_type, false, Location);
1831                         
1832                         if (type == null)
1833                                 return null;
1834
1835                         eclass = ExprClass.Value;
1836
1837                         if (expr is Constant){
1838                                 Expression e = TryReduce (ec, type);
1839
1840                                 if (e != null)
1841                                         return e;
1842                         }
1843
1844                         expr = Convert.ExplicitConversion (ec, expr, type, loc);
1845                         return expr;
1846                 }
1847
1848                 public override void Emit (EmitContext ec)
1849                 {
1850                         //
1851                         // This one will never happen
1852                         //
1853                         throw new Exception ("Should not happen");
1854                 }
1855         }
1856
1857         /// <summary>
1858         ///   Binary operators
1859         /// </summary>
1860         public class Binary : Expression {
1861                 public enum Operator : byte {
1862                         Multiply, Division, Modulus,
1863                         Addition, Subtraction,
1864                         LeftShift, RightShift,
1865                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1866                         Equality, Inequality,
1867                         BitwiseAnd,
1868                         ExclusiveOr,
1869                         BitwiseOr,
1870                         LogicalAnd,
1871                         LogicalOr,
1872                         TOP
1873                 }
1874
1875                 Operator oper;
1876                 Expression left, right;
1877
1878                 // This must be kept in sync with Operator!!!
1879                 public static readonly string [] oper_names;
1880                 
1881                 static Binary ()
1882                 {
1883                         oper_names = new string [(int) Operator.TOP];
1884
1885                         oper_names [(int) Operator.Multiply] = "op_Multiply";
1886                         oper_names [(int) Operator.Division] = "op_Division";
1887                         oper_names [(int) Operator.Modulus] = "op_Modulus";
1888                         oper_names [(int) Operator.Addition] = "op_Addition";
1889                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1890                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1891                         oper_names [(int) Operator.RightShift] = "op_RightShift";
1892                         oper_names [(int) Operator.LessThan] = "op_LessThan";
1893                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1894                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1895                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1896                         oper_names [(int) Operator.Equality] = "op_Equality";
1897                         oper_names [(int) Operator.Inequality] = "op_Inequality";
1898                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1899                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1900                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1901                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1902                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1903                 }
1904
1905                 public Binary (Operator oper, Expression left, Expression right, Location loc)
1906                 {
1907                         this.oper = oper;
1908                         this.left = left;
1909                         this.right = right;
1910                         this.loc = loc;
1911                 }
1912
1913                 public Operator Oper {
1914                         get {
1915                                 return oper;
1916                         }
1917                         set {
1918                                 oper = value;
1919                         }
1920                 }
1921                 
1922                 public Expression Left {
1923                         get {
1924                                 return left;
1925                         }
1926                         set {
1927                                 left = value;
1928                         }
1929                 }
1930
1931                 public Expression Right {
1932                         get {
1933                                 return right;
1934                         }
1935                         set {
1936                                 right = value;
1937                         }
1938                 }
1939
1940
1941                 /// <summary>
1942                 ///   Returns a stringified representation of the Operator
1943                 /// </summary>
1944                 static string OperName (Operator oper)
1945                 {
1946                         switch (oper){
1947                         case Operator.Multiply:
1948                                 return "*";
1949                         case Operator.Division:
1950                                 return "/";
1951                         case Operator.Modulus:
1952                                 return "%";
1953                         case Operator.Addition:
1954                                 return "+";
1955                         case Operator.Subtraction:
1956                                 return "-";
1957                         case Operator.LeftShift:
1958                                 return "<<";
1959                         case Operator.RightShift:
1960                                 return ">>";
1961                         case Operator.LessThan:
1962                                 return "<";
1963                         case Operator.GreaterThan:
1964                                 return ">";
1965                         case Operator.LessThanOrEqual:
1966                                 return "<=";
1967                         case Operator.GreaterThanOrEqual:
1968                                 return ">=";
1969                         case Operator.Equality:
1970                                 return "==";
1971                         case Operator.Inequality:
1972                                 return "!=";
1973                         case Operator.BitwiseAnd:
1974                                 return "&";
1975                         case Operator.BitwiseOr:
1976                                 return "|";
1977                         case Operator.ExclusiveOr:
1978                                 return "^";
1979                         case Operator.LogicalOr:
1980                                 return "||";
1981                         case Operator.LogicalAnd:
1982                                 return "&&";
1983                         }
1984
1985                         return oper.ToString ();
1986                 }
1987
1988                 public override string ToString ()
1989                 {
1990                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1991                                 right.ToString () + ")";
1992                 }
1993                 
1994                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1995                 {
1996                         if (expr.Type == target_type)
1997                                 return expr;
1998
1999                         return Convert.ImplicitConversion (ec, expr, target_type, loc);
2000                 }
2001
2002                 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
2003                 {
2004                         Report.Error (
2005                                 34, loc, "Operator `" + OperName (oper) 
2006                                 + "' is ambiguous on operands of type `"
2007                                 + TypeManager.CSharpName (l) + "' "
2008                                 + "and `" + TypeManager.CSharpName (r)
2009                                 + "'");
2010                 }
2011
2012                 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
2013                 {
2014                         if ((l == t) || (r == t))
2015                                 return true;
2016
2017                         if (!check_user_conversions)
2018                                 return false;
2019
2020                         if (Convert.ImplicitUserConversionExists (ec, l, t))
2021                                 return true;
2022                         else if (Convert.ImplicitUserConversionExists (ec, r, t))
2023                                 return true;
2024                         else
2025                                 return false;
2026                 }
2027
2028                 //
2029                 // Note that handling the case l == Decimal || r == Decimal
2030                 // is taken care of by the Step 1 Operator Overload resolution.
2031                 //
2032                 // If `check_user_conv' is true, we also check whether a user-defined conversion
2033                 // exists.  Note that we only need to do this if both arguments are of a user-defined
2034                 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
2035                 // so we don't explicitly check for performance reasons.
2036                 //
2037                 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
2038                 {
2039                         if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
2040                                 //
2041                                 // If either operand is of type double, the other operand is
2042                                 // conveted to type double.
2043                                 //
2044                                 if (r != TypeManager.double_type)
2045                                         right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
2046                                 if (l != TypeManager.double_type)
2047                                         left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
2048                                 
2049                                 type = TypeManager.double_type;
2050                         } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
2051                                 //
2052                                 // if either operand is of type float, the other operand is
2053                                 // converted to type float.
2054                                 //
2055                                 if (r != TypeManager.double_type)
2056                                         right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
2057                                 if (l != TypeManager.double_type)
2058                                         left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
2059                                 type = TypeManager.float_type;
2060                         } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2061                                 Expression e;
2062                                 Type other;
2063                                 //
2064                                 // If either operand is of type ulong, the other operand is
2065                                 // converted to type ulong.  or an error ocurrs if the other
2066                                 // operand is of type sbyte, short, int or long
2067                                 //
2068                                 if (l == TypeManager.uint64_type){
2069                                         if (r != TypeManager.uint64_type){
2070                                                 if (right is IntConstant){
2071                                                         IntConstant ic = (IntConstant) right;
2072                                                         
2073                                                         e = Convert.TryImplicitIntConversion (l, ic);
2074                                                         if (e != null)
2075                                                                 right = e;
2076                                                 } else if (right is LongConstant){
2077                                                         long ll = ((LongConstant) right).Value;
2078
2079                                                         if (ll > 0)
2080                                                                 right = new ULongConstant ((ulong) ll);
2081                                                 } else {
2082                                                         e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2083                                                         if (e != null)
2084                                                                 right = e;
2085                                                 }
2086                                         }
2087                                         other = right.Type;
2088                                 } else {
2089                                         if (left is IntConstant){
2090                                                 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2091                                                 if (e != null)
2092                                                         left = e;
2093                                         } else if (left is LongConstant){
2094                                                 long ll = ((LongConstant) left).Value;
2095                                                 
2096                                                 if (ll > 0)
2097                                                         left = new ULongConstant ((ulong) ll);
2098                                         } else {
2099                                                 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2100                                                 if (e != null)
2101                                                         left = e;
2102                                         }
2103                                         other = left.Type;
2104                                 }
2105
2106                                 if ((other == TypeManager.sbyte_type) ||
2107                                     (other == TypeManager.short_type) ||
2108                                     (other == TypeManager.int32_type) ||
2109                                     (other == TypeManager.int64_type))
2110                                         Error_OperatorAmbiguous (loc, oper, l, r);
2111                                 type = TypeManager.uint64_type;
2112                         } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2113                                 //
2114                                 // If either operand is of type long, the other operand is converted
2115                                 // to type long.
2116                                 //
2117                                 if (l != TypeManager.int64_type)
2118                                         left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2119                                 if (r != TypeManager.int64_type)
2120                                         right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2121                                 
2122                                 type = TypeManager.int64_type;
2123                         } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2124                                 //
2125                                 // If either operand is of type uint, and the other
2126                                 // operand is of type sbyte, short or int, othe operands are
2127                                 // converted to type long (unless we have an int constant).
2128                                 //
2129                                 Type other = null;
2130                                 
2131                                 if (l == TypeManager.uint32_type){
2132                                         if (right is IntConstant){
2133                                                 IntConstant ic = (IntConstant) right;
2134                                                 int val = ic.Value;
2135                                                 
2136                                                 if (val >= 0){
2137                                                         right = new UIntConstant ((uint) val);
2138                                                         type = l;
2139                                                         
2140                                                         return true;
2141                                                 }
2142                                         }
2143                                         other = r;
2144                                 } else if (r == TypeManager.uint32_type){
2145                                         if (left is IntConstant){
2146                                                 IntConstant ic = (IntConstant) left;
2147                                                 int val = ic.Value;
2148                                                 
2149                                                 if (val >= 0){
2150                                                         left = new UIntConstant ((uint) val);
2151                                                         type = r;
2152                                                         return true;
2153                                                 }
2154                                         }
2155                                         
2156                                         other = l;
2157                                 }
2158
2159                                 if ((other == TypeManager.sbyte_type) ||
2160                                     (other == TypeManager.short_type) ||
2161                                     (other == TypeManager.int32_type)){
2162                                         left = ForceConversion (ec, left, TypeManager.int64_type);
2163                                         right = ForceConversion (ec, right, TypeManager.int64_type);
2164                                         type = TypeManager.int64_type;
2165                                 } else {
2166                                         //
2167                                         // if either operand is of type uint, the other
2168                                         // operand is converd to type uint
2169                                         //
2170                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
2171                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
2172                                         type = TypeManager.uint32_type;
2173                                 } 
2174                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2175                                 if (l != TypeManager.decimal_type)
2176                                         left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2177
2178                                 if (r != TypeManager.decimal_type)
2179                                         right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2180                                 type = TypeManager.decimal_type;
2181                         } else {
2182                                 left = ForceConversion (ec, left, TypeManager.int32_type);
2183                                 right = ForceConversion (ec, right, TypeManager.int32_type);
2184
2185                                 type = TypeManager.int32_type;
2186                         }
2187
2188                         return (left != null) && (right != null);
2189                 }
2190
2191                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2192                 {
2193                         Report.Error (19, loc,
2194                                "Operator " + name + " cannot be applied to operands of type `" +
2195                                TypeManager.CSharpName (l) + "' and `" +
2196                                TypeManager.CSharpName (r) + "'");
2197                 }
2198                 
2199                 void Error_OperatorCannotBeApplied ()
2200                 {
2201                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2202                 }
2203
2204                 static bool is_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                         //
4600                         // Now we actually find the best method
4601                         //
4602                         int candidate_top = candidates.Count;
4603                         for (int ix = 0; ix < candidate_top; ix++){
4604                                 MethodBase candidate = (MethodBase) candidates [ix];
4605
4606                                 bool cand_params = (bool) candidate_to_form [candidate];
4607                                 bool method_params = false;
4608
4609                                 if (method != null)
4610                                         method_params = (bool) candidate_to_form [method];
4611                                 
4612                                 int x = BetterFunction (ec, Arguments,
4613                                                         candidate, cand_params,
4614                                                         method, method_params,
4615                                                         loc);
4616                                 
4617                                 if (x == 0)
4618                                         continue;
4619                                 
4620                                 method = candidate;
4621                         }
4622
4623                         if (Arguments == null)
4624                                 argument_count = 0;
4625                         else
4626                                 argument_count = Arguments.Count;
4627                         
4628
4629                         if (method == null) {
4630                                 //
4631                                 // Okay so we have failed to find anything so we
4632                                 // return by providing info about the closest match
4633                                 //
4634                                 for (int i = 0; i < me.Methods.Length; ++i) {
4635
4636                                         MethodBase c = (MethodBase) me.Methods [i];
4637                                         ParameterData pd = GetParameterData (c);
4638
4639                                         if (pd.Count != argument_count)
4640                                                 continue;
4641
4642                                         VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4643                                                                null, loc);
4644                                         break;
4645                                 }
4646
4647                                 if (!Location.IsNull (loc)) {
4648                                         string report_name = me.Name;
4649                                         if (report_name == ".ctor")
4650                                                 report_name = me.DeclaringType.ToString ();
4651                                         
4652                                         Error_WrongNumArguments (loc, report_name, argument_count);
4653                                 }
4654                                 
4655                                 return null;
4656                         }
4657
4658                         //
4659                         // Now check that there are no ambiguities i.e the selected method
4660                         // should be better than all the others
4661                         //
4662                         bool best_params = (bool) candidate_to_form [method];
4663
4664                         for (int ix = 0; ix < candidate_top; ix++){
4665                                 MethodBase candidate = (MethodBase) candidates [ix];
4666
4667                                 if (candidate == method)
4668                                         continue;
4669                                                
4670                                 //
4671                                 // If a normal method is applicable in
4672                                 // the sense that it has the same
4673                                 // number of arguments, then the
4674                                 // expanded params method is never
4675                                 // applicable so we debar the params
4676                                 // method.
4677                                 //
4678                                 if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
4679                                      IsApplicable (ec, Arguments, method)))
4680                                         continue;
4681                                 
4682                                 bool cand_params = (bool) candidate_to_form [candidate];
4683                                 int x = BetterFunction (ec, Arguments,
4684                                                         method, best_params,
4685                                                         candidate, cand_params,
4686                                                         loc);
4687
4688                                 if (x != 1) {
4689                                         Report.Error (
4690                                                 121, loc,
4691                                                 "Ambiguous call when selecting function due to implicit casts");
4692                                         return null;
4693                                 }
4694                         }
4695
4696                         //
4697                         // And now check if the arguments are all
4698                         // compatible, perform conversions if
4699                         // necessary etc. and return if everything is
4700                         // all right
4701                         //
4702                         if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4703                                                     best_params, null, loc))
4704                                 return null;
4705
4706                         return method;
4707                 }
4708
4709                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4710                 {
4711                         Report.Error (1501, loc,
4712                                       "No overload for method `" + name + "' takes `" +
4713                                       arg_count + "' arguments");
4714                 }
4715
4716                 static void Error_InvokeOnDelegate (Location loc)
4717                 {
4718                         Report.Error (1533, loc,
4719                                       "Invoke cannot be called directly on a delegate");
4720                 }
4721                         
4722                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4723                                                     Type delegate_type, string arg_sig, string par_desc)
4724                 {
4725                         if (delegate_type == null) 
4726                                 Report.Error (1502, loc,
4727                                               "The best overloaded match for method '" +
4728                                               FullMethodDesc (method) +
4729                                               "' has some invalid arguments");
4730                         else
4731                                 Report.Error (1594, loc,
4732                                               "Delegate '" + delegate_type.ToString () +
4733                                               "' has some invalid arguments.");
4734                         Report.Error (1503, loc,
4735                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4736                                                      idx, arg_sig, par_desc));
4737                 }
4738                 
4739                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4740                                                           int argument_count,
4741                                                           MethodBase method, 
4742                                                           bool chose_params_expanded,
4743                                                           Type delegate_type,
4744                                                           Location loc)
4745                 {
4746                         ParameterData pd = GetParameterData (method);
4747                         int pd_count = pd.Count;
4748                         
4749                         for (int j = 0; j < argument_count; j++) {
4750                                 Argument a = (Argument) Arguments [j];
4751                                 Expression a_expr = a.Expr;
4752                                 Type parameter_type = pd.ParameterType (j);
4753                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4754                                 
4755                                 if (pm == Parameter.Modifier.PARAMS){
4756                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4757                                                 if (!Location.IsNull (loc))
4758                                                         Error_InvalidArguments (
4759                                                                 loc, j, method, delegate_type,
4760                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4761                                                 return false;
4762                                         }
4763
4764                                         if (chose_params_expanded)
4765                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4766                                 } else {
4767                                         //
4768                                         // Check modifiers
4769                                         //
4770                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4771                                                 if (!Location.IsNull (loc))
4772                                                         Error_InvalidArguments (
4773                                                                 loc, j, method, delegate_type,
4774                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4775                                                 return false;
4776                                         }
4777                                 }
4778
4779                                 //
4780                                 // Check Type
4781                                 //
4782                                 if (a.Type != parameter_type){
4783                                         Expression conv;
4784                                         
4785                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
4786
4787                                         if (conv == null) {
4788                                                 if (!Location.IsNull (loc)) 
4789                                                         Error_InvalidArguments (
4790                                                                 loc, j, method, delegate_type,
4791                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4792                                                 return false;
4793                                         }
4794                                         
4795                                         //
4796                                         // Update the argument with the implicit conversion
4797                                         //
4798                                         if (a_expr != conv)
4799                                                 a.Expr = conv;
4800                                 }
4801
4802                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4803                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4804                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4805                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4806                                 
4807                                 if (a_mod != p_mod &&
4808                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4809                                         if (!Location.IsNull (loc)) {
4810                                                 Report.Error (1502, loc,
4811                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
4812                                                        "' has some invalid arguments");
4813                                                 Report.Error (1503, loc,
4814                                                        "Argument " + (j+1) +
4815                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
4816                                                        + "' to '" + pd.ParameterDesc (j) + "'");
4817                                         }
4818                                         
4819                                         return false;
4820                                 }
4821                         }
4822
4823                         return true;
4824                 }
4825
4826                 public override Expression DoResolve (EmitContext ec)
4827                 {
4828                         //
4829                         // First, resolve the expression that is used to
4830                         // trigger the invocation
4831                         //
4832                         if (expr is BaseAccess)
4833                                 is_base = true;
4834
4835                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4836                         if (expr == null)
4837                                 return null;
4838
4839                         if (!(expr is MethodGroupExpr)) {
4840                                 Type expr_type = expr.Type;
4841
4842                                 if (expr_type != null){
4843                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4844                                         if (IsDelegate)
4845                                                 return (new DelegateInvocation (
4846                                                         this.expr, Arguments, loc)).Resolve (ec);
4847                                 }
4848                         }
4849
4850                         if (!(expr is MethodGroupExpr)){
4851                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
4852                                 return null;
4853                         }
4854
4855                         //
4856                         // Next, evaluate all the expressions in the argument list
4857                         //
4858                         if (Arguments != null){
4859                                 foreach (Argument a in Arguments){
4860                                         if (!a.Resolve (ec, loc))
4861                                                 return null;
4862                                 }
4863                         }
4864
4865                         MethodGroupExpr mg = (MethodGroupExpr) expr;
4866                         method = OverloadResolve (ec, mg, Arguments, loc);
4867
4868                         if (method == null){
4869                                 Error (-6,
4870                                        "Could not find any applicable function for this argument list");
4871                                 return null;
4872                         }
4873
4874                         MethodInfo mi = method as MethodInfo;
4875                         if (mi != null) {
4876                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
4877                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4878                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4879                         }
4880
4881                         if (type.IsPointer){
4882                                 if (!ec.InUnsafe){
4883                                         UnsafeError (loc);
4884                                         return null;
4885                                 }
4886                         }
4887                         
4888                         //
4889                         // Only base will allow this invocation to happen.
4890                         //
4891                         if (is_base && method.IsAbstract){
4892                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
4893                                               FullMethodDesc (method));
4894                                 return null;
4895                         }
4896
4897                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
4898                                 if (TypeManager.IsSpecialMethod (method))
4899                                         Report.Error (571, loc, method.Name + ": can not call operator or accessor");
4900                         }
4901                         
4902                         eclass = ExprClass.Value;
4903                         return this;
4904                 }
4905
4906                 // <summary>
4907                 //   Emits the list of arguments as an array
4908                 // </summary>
4909                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4910                 {
4911                         ILGenerator ig = ec.ig;
4912                         int count = arguments.Count - idx;
4913                         Argument a = (Argument) arguments [idx];
4914                         Type t = a.Expr.Type;
4915                         string array_type = t.FullName + "[]";
4916                         LocalBuilder array;
4917
4918                         array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4919                         IntConstant.EmitInt (ig, count);
4920                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4921                         ig.Emit (OpCodes.Stloc, array);
4922
4923                         int top = arguments.Count;
4924                         for (int j = idx; j < top; j++){
4925                                 a = (Argument) arguments [j];
4926                                 
4927                                 ig.Emit (OpCodes.Ldloc, array);
4928                                 IntConstant.EmitInt (ig, j - idx);
4929
4930                                 bool is_stobj;
4931                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
4932                                 if (is_stobj)
4933                                         ig.Emit (OpCodes.Ldelema, t);
4934
4935                                 a.Emit (ec);
4936
4937                                 if (is_stobj)
4938                                         ig.Emit (OpCodes.Stobj, t);
4939                                 else
4940                                         ig.Emit (op);
4941                         }
4942                         ig.Emit (OpCodes.Ldloc, array);
4943                 }
4944                 
4945                 /// <summary>
4946                 ///   Emits a list of resolved Arguments that are in the arguments
4947                 ///   ArrayList.
4948                 /// 
4949                 ///   The MethodBase argument might be null if the
4950                 ///   emission of the arguments is known not to contain
4951                 ///   a `params' field (for example in constructors or other routines
4952                 ///   that keep their arguments in this structure)
4953                 /// </summary>
4954                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4955                 {
4956                         ParameterData pd;
4957                         if (mb != null)
4958                                 pd = GetParameterData (mb);
4959                         else
4960                                 pd = null;
4961
4962                         //
4963                         // If we are calling a params method with no arguments, special case it
4964                         //
4965                         if (arguments == null){
4966                                 if (pd != null && pd.Count > 0 &&
4967                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4968                                         ILGenerator ig = ec.ig;
4969
4970                                         IntConstant.EmitInt (ig, 0);
4971                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
4972                                 }
4973
4974                                 return;
4975                         }
4976
4977                         int top = arguments.Count;
4978
4979                         for (int i = 0; i < top; i++){
4980                                 Argument a = (Argument) arguments [i];
4981
4982                                 if (pd != null){
4983                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4984                                                 //
4985                                                 // Special case if we are passing the same data as the
4986                                                 // params argument, do not put it in an array.
4987                                                 //
4988                                                 if (pd.ParameterType (i) == a.Type)
4989                                                         a.Emit (ec);
4990                                                 else
4991                                                         EmitParams (ec, i, arguments);
4992                                                 return;
4993                                         }
4994                                 }
4995                                             
4996                                 a.Emit (ec);
4997                         }
4998
4999                         if (pd != null && pd.Count > top &&
5000                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5001                                 ILGenerator ig = ec.ig;
5002
5003                                 IntConstant.EmitInt (ig, 0);
5004                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5005                         }
5006                 }
5007
5008                 /// <remarks>
5009                 ///   is_base tells whether we want to force the use of the `call'
5010                 ///   opcode instead of using callvirt.  Call is required to call
5011                 ///   a specific method, while callvirt will always use the most
5012                 ///   recent method in the vtable.
5013                 ///
5014                 ///   is_static tells whether this is an invocation on a static method
5015                 ///
5016                 ///   instance_expr is an expression that represents the instance
5017                 ///   it must be non-null if is_static is false.
5018                 ///
5019                 ///   method is the method to invoke.
5020                 ///
5021                 ///   Arguments is the list of arguments to pass to the method or constructor.
5022                 /// </remarks>
5023                 public static void EmitCall (EmitContext ec, bool is_base,
5024                                              bool is_static, Expression instance_expr,
5025                                              MethodBase method, ArrayList Arguments, Location loc)
5026                 {
5027                         ILGenerator ig = ec.ig;
5028                         bool struct_call = false;
5029
5030                         Type decl_type = method.DeclaringType;
5031
5032                         if (!RootContext.StdLib) {
5033                                 // Replace any calls to the system's System.Array type with calls to
5034                                 // the newly created one.
5035                                 if (method == TypeManager.system_int_array_get_length)
5036                                         method = TypeManager.int_array_get_length;
5037                                 else if (method == TypeManager.system_int_array_get_rank)
5038                                         method = TypeManager.int_array_get_rank;
5039                                 else if (method == TypeManager.system_object_array_clone)
5040                                         method = TypeManager.object_array_clone;
5041                                 else if (method == TypeManager.system_int_array_get_length_int)
5042                                         method = TypeManager.int_array_get_length_int;
5043                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5044                                         method = TypeManager.int_array_get_lower_bound_int;
5045                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5046                                         method = TypeManager.int_array_get_upper_bound_int;
5047                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5048                                         method = TypeManager.void_array_copyto_array_int;
5049                         }
5050
5051                         //
5052                         // This checks the `ConditionalAttribute' on the method, and the
5053                         // ObsoleteAttribute
5054                         //
5055                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
5056                         if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
5057                                 return;
5058                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
5059                                 return;
5060                         
5061                         if (!is_static){
5062                                 if (decl_type.IsValueType)
5063                                         struct_call = true;
5064                                 //
5065                                 // If this is ourselves, push "this"
5066                                 //
5067                                 if (instance_expr == null){
5068                                         ig.Emit (OpCodes.Ldarg_0);
5069                                 } else {
5070                                         //
5071                                         // Push the instance expression
5072                                         //
5073                                         if (instance_expr.Type.IsValueType){
5074                                                 //
5075                                                 // Special case: calls to a function declared in a 
5076                                                 // reference-type with a value-type argument need
5077                                                 // to have their value boxed.  
5078
5079                                                 struct_call = true;
5080                                                 if (decl_type.IsValueType){
5081                                                         //
5082                                                         // If the expression implements IMemoryLocation, then
5083                                                         // we can optimize and use AddressOf on the
5084                                                         // return.
5085                                                         //
5086                                                         // If not we have to use some temporary storage for
5087                                                         // it.
5088                                                         if (instance_expr is IMemoryLocation){
5089                                                                 ((IMemoryLocation)instance_expr).
5090                                                                         AddressOf (ec, AddressOp.LoadStore);
5091                                                         }
5092                                                         else {
5093                                                                 Type t = instance_expr.Type;
5094                                                                 
5095                                                                 instance_expr.Emit (ec);
5096                                                                 LocalBuilder temp = ig.DeclareLocal (t);
5097                                                                 ig.Emit (OpCodes.Stloc, temp);
5098                                                                 ig.Emit (OpCodes.Ldloca, temp);
5099                                                         }
5100                                                 } else {
5101                                                         instance_expr.Emit (ec);
5102                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5103                                                 } 
5104                                         } else
5105                                                 instance_expr.Emit (ec);
5106                                 }
5107                         }
5108
5109                         EmitArguments (ec, method, Arguments);
5110
5111                         if (is_static || struct_call || is_base){
5112                                 if (method is MethodInfo) {
5113                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
5114                                 } else
5115                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5116                         } else {
5117                                 if (method is MethodInfo)
5118                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
5119                                 else
5120                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
5121                         }
5122                 }
5123                 
5124                 public override void Emit (EmitContext ec)
5125                 {
5126                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5127
5128                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5129                 }
5130                 
5131                 public override void EmitStatement (EmitContext ec)
5132                 {
5133                         Emit (ec);
5134
5135                         // 
5136                         // Pop the return value if there is one
5137                         //
5138                         if (method is MethodInfo){
5139                                 Type ret = ((MethodInfo)method).ReturnType;
5140                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5141                                         ec.ig.Emit (OpCodes.Pop);
5142                         }
5143                 }
5144         }
5145
5146         public class InvocationOrCast : ExpressionStatement
5147         {
5148                 Expression expr;
5149                 Expression argument;
5150
5151                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5152                 {
5153                         this.expr = expr;
5154                         this.argument = argument;
5155                         this.loc = loc;
5156                 }
5157
5158                 public override Expression DoResolve (EmitContext ec)
5159                 {
5160                         //
5161                         // First try to resolve it as a cast.
5162                         //
5163                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5164                         if (type != null) {
5165                                 Cast cast = new Cast (new TypeExpression (type, loc), argument, loc);
5166                                 return cast.Resolve (ec);
5167                         }
5168
5169                         //
5170                         // This can either be a type or a delegate invocation.
5171                         // Let's just resolve it and see what we'll get.
5172                         //
5173                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5174                         if (expr == null)
5175                                 return null;
5176
5177                         //
5178                         // Ok, so it's a Cast.
5179                         //
5180                         if (expr.eclass == ExprClass.Type) {
5181                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5182                                 return cast.Resolve (ec);
5183                         }
5184
5185                         //
5186                         // It's a delegate invocation.
5187                         //
5188                         if (!TypeManager.IsDelegateType (expr.Type)) {
5189                                 Error (149, "Method name expected");
5190                                 return null;
5191                         }
5192
5193                         ArrayList args = new ArrayList ();
5194                         args.Add (new Argument (argument, Argument.AType.Expression));
5195                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5196                         return invocation.Resolve (ec);
5197                 }
5198
5199                 void error201 ()
5200                 {
5201                         Error (201, "Only assignment, call, increment, decrement and new object " +
5202                                "expressions can be used as a statement");
5203                 }
5204
5205                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5206                 {
5207                         //
5208                         // First try to resolve it as a cast.
5209                         //
5210                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5211                         if (type != null) {
5212                                 error201 ();
5213                                 return null;
5214                         }
5215
5216                         //
5217                         // This can either be a type or a delegate invocation.
5218                         // Let's just resolve it and see what we'll get.
5219                         //
5220                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5221                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5222                                 error201 ();
5223                                 return null;
5224                         }
5225
5226                         //
5227                         // It's a delegate invocation.
5228                         //
5229                         if (!TypeManager.IsDelegateType (expr.Type)) {
5230                                 Error (149, "Method name expected");
5231                                 return null;
5232                         }
5233
5234                         ArrayList args = new ArrayList ();
5235                         args.Add (new Argument (argument, Argument.AType.Expression));
5236                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5237                         return invocation.ResolveStatement (ec);
5238                 }
5239
5240                 public override void Emit (EmitContext ec)
5241                 {
5242                         throw new Exception ("Cannot happen");
5243                 }
5244
5245                 public override void EmitStatement (EmitContext ec)
5246                 {
5247                         throw new Exception ("Cannot happen");
5248                 }
5249         }
5250
5251         //
5252         // This class is used to "disable" the code generation for the
5253         // temporary variable when initializing value types.
5254         //
5255         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5256                 public void AddressOf (EmitContext ec, AddressOp Mode)
5257                 {
5258                         // nothing
5259                 }
5260         }
5261         
5262         /// <summary>
5263         ///    Implements the new expression 
5264         /// </summary>
5265         public class New : ExpressionStatement, IMemoryLocation {
5266                 public readonly ArrayList Arguments;
5267
5268                 //
5269                 // During bootstrap, it contains the RequestedType,
5270                 // but if `type' is not null, it *might* contain a NewDelegate
5271                 // (because of field multi-initialization)
5272                 //
5273                 public Expression RequestedType;
5274
5275                 MethodBase method = null;
5276
5277                 //
5278                 // If set, the new expression is for a value_target, and
5279                 // we will not leave anything on the stack.
5280                 //
5281                 Expression value_target;
5282                 bool value_target_set = false;
5283                 
5284                 public New (Expression requested_type, ArrayList arguments, Location l)
5285                 {
5286                         RequestedType = requested_type;
5287                         Arguments = arguments;
5288                         loc = l;
5289                 }
5290
5291                 public bool SetValueTypeVariable (Expression value)
5292                 {
5293                         value_target = value;
5294                         value_target_set = true;
5295                         if (!(value_target is IMemoryLocation)){
5296                                 Error_UnexpectedKind ("variable");
5297                                 return false;
5298                         }
5299                         return true;
5300                 }
5301
5302                 //
5303                 // This function is used to disable the following code sequence for
5304                 // value type initialization:
5305                 //
5306                 // AddressOf (temporary)
5307                 // Construct/Init
5308                 // LoadTemporary
5309                 //
5310                 // Instead the provide will have provided us with the address on the
5311                 // stack to store the results.
5312                 //
5313                 static Expression MyEmptyExpression;
5314                 
5315                 public void DisableTemporaryValueType ()
5316                 {
5317                         if (MyEmptyExpression == null)
5318                                 MyEmptyExpression = new EmptyAddressOf ();
5319
5320                         //
5321                         // To enable this, look into:
5322                         // test-34 and test-89 and self bootstrapping.
5323                         //
5324                         // For instance, we can avoid a copy by using `newobj'
5325                         // instead of Call + Push-temp on value types.
5326 //                      value_target = MyEmptyExpression;
5327                 }
5328
5329                 public override Expression DoResolve (EmitContext ec)
5330                 {
5331                         //
5332                         // The New DoResolve might be called twice when initializing field
5333                         // expressions (see EmitFieldInitializers, the call to
5334                         // GetInitializerExpression will perform a resolve on the expression,
5335                         // and later the assign will trigger another resolution
5336                         //
5337                         // This leads to bugs (#37014)
5338                         //
5339                         if (type != null){
5340                                 if (RequestedType is NewDelegate)
5341                                         return RequestedType;
5342                                 return this;
5343                         }
5344                         
5345                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5346                         
5347                         if (type == null)
5348                                 return null;
5349                         
5350                         bool IsDelegate = TypeManager.IsDelegateType (type);
5351                         
5352                         if (IsDelegate){
5353                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5354                                 if (RequestedType != null)
5355                                         if (!(RequestedType is NewDelegate))
5356                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5357                                 return RequestedType;
5358                         }
5359
5360                         if (type.IsInterface || type.IsAbstract){
5361                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5362                                 return null;
5363                         }
5364                         
5365                         bool is_struct = type.IsValueType;
5366                         eclass = ExprClass.Value;
5367
5368                         //
5369                         // SRE returns a match for .ctor () on structs (the object constructor), 
5370                         // so we have to manually ignore it.
5371                         //
5372                         if (is_struct && Arguments == null)
5373                                 return this;
5374                         
5375                         Expression ml;
5376                         ml = MemberLookupFinal (ec, null, type, ".ctor",
5377                                                 MemberTypes.Constructor,
5378                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5379
5380                         if (ml == null)
5381                                 return null;
5382                         
5383                         if (! (ml is MethodGroupExpr)){
5384                                 if (!is_struct){
5385                                         ml.Error_UnexpectedKind ("method group");
5386                                         return null;
5387                                 }
5388                         }
5389
5390                         if (ml != null) {
5391                                 if (Arguments != null){
5392                                         foreach (Argument a in Arguments){
5393                                                 if (!a.Resolve (ec, loc))
5394                                                         return null;
5395                                         }
5396                                 }
5397
5398                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
5399                                 
5400                         }
5401
5402                         if (method == null) { 
5403                                 if (!is_struct || Arguments.Count > 0) {
5404                                         Error (1501, String.Format (
5405                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5406                                             TypeManager.CSharpName (type)));
5407                                         return null;
5408                                 }
5409                         }
5410
5411                         return this;
5412                 }
5413
5414                 //
5415                 // This DoEmit can be invoked in two contexts:
5416                 //    * As a mechanism that will leave a value on the stack (new object)
5417                 //    * As one that wont (init struct)
5418                 //
5419                 // You can control whether a value is required on the stack by passing
5420                 // need_value_on_stack.  The code *might* leave a value on the stack
5421                 // so it must be popped manually
5422                 //
5423                 // If we are dealing with a ValueType, we have a few
5424                 // situations to deal with:
5425                 //
5426                 //    * The target is a ValueType, and we have been provided
5427                 //      the instance (this is easy, we are being assigned).
5428                 //
5429                 //    * The target of New is being passed as an argument,
5430                 //      to a boxing operation or a function that takes a
5431                 //      ValueType.
5432                 //
5433                 //      In this case, we need to create a temporary variable
5434                 //      that is the argument of New.
5435                 //
5436                 // Returns whether a value is left on the stack
5437                 //
5438                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5439                 {
5440                         bool is_value_type = type.IsValueType;
5441                         ILGenerator ig = ec.ig;
5442
5443                         if (is_value_type){
5444                                 IMemoryLocation ml;
5445
5446                                 // Allow DoEmit() to be called multiple times.
5447                                 // We need to create a new LocalTemporary each time since
5448                                 // you can't share LocalBuilders among ILGeneators.
5449                                 if (!value_target_set)
5450                                         value_target = new LocalTemporary (ec, type);
5451
5452                                 ml = (IMemoryLocation) value_target;
5453                                 ml.AddressOf (ec, AddressOp.Store);
5454                         }
5455
5456                         if (method != null)
5457                                 Invocation.EmitArguments (ec, method, Arguments);
5458
5459                         if (is_value_type){
5460                                 if (method == null)
5461                                         ig.Emit (OpCodes.Initobj, type);
5462                                 else 
5463                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5464                                 if (need_value_on_stack){
5465                                         value_target.Emit (ec);
5466                                         return true;
5467                                 }
5468                                 return false;
5469                         } else {
5470                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5471                                 return true;
5472                         }
5473                 }
5474
5475                 public override void Emit (EmitContext ec)
5476                 {
5477                         DoEmit (ec, true);
5478                 }
5479                 
5480                 public override void EmitStatement (EmitContext ec)
5481                 {
5482                         if (DoEmit (ec, false))
5483                                 ec.ig.Emit (OpCodes.Pop);
5484                 }
5485
5486                 public void AddressOf (EmitContext ec, AddressOp Mode)
5487                 {
5488                         if (!type.IsValueType){
5489                                 //
5490                                 // We throw an exception.  So far, I believe we only need to support
5491                                 // value types:
5492                                 // foreach (int j in new StructType ())
5493                                 // see bug 42390
5494                                 //
5495                                 throw new Exception ("AddressOf should not be used for classes");
5496                         }
5497
5498                         if (!value_target_set)
5499                                 value_target = new LocalTemporary (ec, type);
5500                                         
5501                         IMemoryLocation ml = (IMemoryLocation) value_target;
5502                         ml.AddressOf (ec, AddressOp.Store);
5503                         if (method != null)
5504                                 Invocation.EmitArguments (ec, method, Arguments);
5505
5506                         if (method == null)
5507                                 ec.ig.Emit (OpCodes.Initobj, type);
5508                         else 
5509                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5510                         
5511                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5512                 }
5513         }
5514
5515         /// <summary>
5516         ///   14.5.10.2: Represents an array creation expression.
5517         /// </summary>
5518         ///
5519         /// <remarks>
5520         ///   There are two possible scenarios here: one is an array creation
5521         ///   expression that specifies the dimensions and optionally the
5522         ///   initialization data and the other which does not need dimensions
5523         ///   specified but where initialization data is mandatory.
5524         /// </remarks>
5525         public class ArrayCreation : ExpressionStatement {
5526                 Expression requested_base_type;
5527                 ArrayList initializers;
5528
5529                 //
5530                 // The list of Argument types.
5531                 // This is used to construct the `newarray' or constructor signature
5532                 //
5533                 ArrayList arguments;
5534
5535                 //
5536                 // Method used to create the array object.
5537                 //
5538                 MethodBase new_method = null;
5539                 
5540                 Type array_element_type;
5541                 Type underlying_type;
5542                 bool is_one_dimensional = false;
5543                 bool is_builtin_type = false;
5544                 bool expect_initializers = false;
5545                 int num_arguments = 0;
5546                 int dimensions = 0;
5547                 string rank;
5548
5549                 ArrayList array_data;
5550
5551                 Hashtable bounds;
5552
5553                 //
5554                 // The number of array initializers that we can handle
5555                 // via the InitializeArray method - through EmitStaticInitializers
5556                 //
5557                 int num_automatic_initializers;
5558
5559                 const int max_automatic_initializers = 6;
5560                 
5561                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5562                 {
5563                         this.requested_base_type = requested_base_type;
5564                         this.initializers = initializers;
5565                         this.rank = rank;
5566                         loc = l;
5567
5568                         arguments = new ArrayList ();
5569
5570                         foreach (Expression e in exprs) {
5571                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5572                                 num_arguments++;
5573                         }
5574                 }
5575
5576                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5577                 {
5578                         this.requested_base_type = requested_base_type;
5579                         this.initializers = initializers;
5580                         this.rank = rank;
5581                         loc = l;
5582
5583                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5584                         //
5585                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5586                         //
5587                         //dimensions = tmp.Length - 1;
5588                         expect_initializers = true;
5589                 }
5590
5591                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5592                 {
5593                         StringBuilder sb = new StringBuilder (rank);
5594                         
5595                         sb.Append ("[");
5596                         for (int i = 1; i < idx_count; i++)
5597                                 sb.Append (",");
5598                         
5599                         sb.Append ("]");
5600
5601                         return new ComposedCast (base_type, sb.ToString (), loc);
5602                 }
5603
5604                 void Error_IncorrectArrayInitializer ()
5605                 {
5606                         Error (178, "Incorrectly structured array initializer");
5607                 }
5608                 
5609                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5610                 {
5611                         if (specified_dims) { 
5612                                 Argument a = (Argument) arguments [idx];
5613                                 
5614                                 if (!a.Resolve (ec, loc))
5615                                         return false;
5616                                 
5617                                 if (!(a.Expr is Constant)) {
5618                                         Error (150, "A constant value is expected");
5619                                         return false;
5620                                 }
5621                                 
5622                                 int value = (int) ((Constant) a.Expr).GetValue ();
5623                                 
5624                                 if (value != probe.Count) {
5625                                         Error_IncorrectArrayInitializer ();
5626                                         return false;
5627                                 }
5628                                 
5629                                 bounds [idx] = value;
5630                         }
5631
5632                         int child_bounds = -1;
5633                         foreach (object o in probe) {
5634                                 if (o is ArrayList) {
5635                                         int current_bounds = ((ArrayList) o).Count;
5636                                         
5637                                         if (child_bounds == -1) 
5638                                                 child_bounds = current_bounds;
5639
5640                                         else if (child_bounds != current_bounds){
5641                                                 Error_IncorrectArrayInitializer ();
5642                                                 return false;
5643                                         }
5644                                         if (specified_dims && (idx + 1 >= arguments.Count)){
5645                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5646                                                 return false;
5647                                         }
5648                                         
5649                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5650                                         if (!ret)
5651                                                 return false;
5652                                 } else {
5653                                         if (child_bounds != -1){
5654                                                 Error_IncorrectArrayInitializer ();
5655                                                 return false;
5656                                         }
5657                                         
5658                                         Expression tmp = (Expression) o;
5659                                         tmp = tmp.Resolve (ec);
5660                                         if (tmp == null)
5661                                                 continue;
5662
5663                                         // Console.WriteLine ("I got: " + tmp);
5664                                         // Handle initialization from vars, fields etc.
5665
5666                                         Expression conv = Convert.ImplicitConversionRequired (
5667                                                 ec, tmp, underlying_type, loc);
5668                                         
5669                                         if (conv == null) 
5670                                                 return false;
5671
5672                                         if (conv is StringConstant)
5673                                                 array_data.Add (conv);
5674                                         else if (conv is Constant) {
5675                                                 array_data.Add (conv);
5676                                                 num_automatic_initializers++;
5677                                         } else
5678                                                 array_data.Add (conv);
5679                                 }
5680                         }
5681
5682                         return true;
5683                 }
5684                 
5685                 public void UpdateIndices (EmitContext ec)
5686                 {
5687                         int i = 0;
5688                         for (ArrayList probe = initializers; probe != null;) {
5689                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5690                                         Expression e = new IntConstant (probe.Count);
5691                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5692
5693                                         bounds [i++] =  probe.Count;
5694                                         
5695                                         probe = (ArrayList) probe [0];
5696                                         
5697                                 } else {
5698                                         Expression e = new IntConstant (probe.Count);
5699                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5700
5701                                         bounds [i++] = probe.Count;
5702                                         probe = null;
5703                                 }
5704                         }
5705
5706                 }
5707                 
5708                 public bool ValidateInitializers (EmitContext ec, Type array_type)
5709                 {
5710                         if (initializers == null) {
5711                                 if (expect_initializers)
5712                                         return false;
5713                                 else
5714                                         return true;
5715                         }
5716                         
5717                         if (underlying_type == null)
5718                                 return false;
5719                         
5720                         //
5721                         // We use this to store all the date values in the order in which we
5722                         // will need to store them in the byte blob later
5723                         //
5724                         array_data = new ArrayList ();
5725                         bounds = new Hashtable ();
5726                         
5727                         bool ret;
5728
5729                         if (arguments != null) {
5730                                 ret = CheckIndices (ec, initializers, 0, true);
5731                                 return ret;
5732                         } else {
5733                                 arguments = new ArrayList ();
5734
5735                                 ret = CheckIndices (ec, initializers, 0, false);
5736                                 
5737                                 if (!ret)
5738                                         return false;
5739                                 
5740                                 UpdateIndices (ec);
5741                                 
5742                                 if (arguments.Count != dimensions) {
5743                                         Error_IncorrectArrayInitializer ();
5744                                         return false;
5745                                 }
5746
5747                                 return ret;
5748                         }
5749                 }
5750
5751                 void Error_NegativeArrayIndex ()
5752                 {
5753                         Error (284, "Can not create array with a negative size");
5754                 }
5755                 
5756                 //
5757                 // Converts `source' to an int, uint, long or ulong.
5758                 //
5759                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5760                 {
5761                         Expression target;
5762                         
5763                         bool old_checked = ec.CheckState;
5764                         ec.CheckState = true;
5765                         
5766                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
5767                         if (target == null){
5768                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
5769                                 if (target == null){
5770                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
5771                                         if (target == null){
5772                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
5773                                                 if (target == null)
5774                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
5775                                         }
5776                                 }
5777                         } 
5778                         ec.CheckState = old_checked;
5779
5780                         //
5781                         // Only positive constants are allowed at compile time
5782                         //
5783                         if (target is Constant){
5784                                 if (target is IntConstant){
5785                                         if (((IntConstant) target).Value < 0){
5786                                                 Error_NegativeArrayIndex ();
5787                                                 return null;
5788                                         }
5789                                 }
5790
5791                                 if (target is LongConstant){
5792                                         if (((LongConstant) target).Value < 0){
5793                                                 Error_NegativeArrayIndex ();
5794                                                 return null;
5795                                         }
5796                                 }
5797                                 
5798                         }
5799
5800                         return target;
5801                 }
5802
5803                 //
5804                 // Creates the type of the array
5805                 //
5806                 bool LookupType (EmitContext ec)
5807                 {
5808                         StringBuilder array_qualifier = new StringBuilder (rank);
5809
5810                         //
5811                         // `In the first form allocates an array instace of the type that results
5812                         // from deleting each of the individual expression from the expression list'
5813                         //
5814                         if (num_arguments > 0) {
5815                                 array_qualifier.Append ("[");
5816                                 for (int i = num_arguments-1; i > 0; i--)
5817                                         array_qualifier.Append (",");
5818                                 array_qualifier.Append ("]");                           
5819                         }
5820
5821                         //
5822                         // Lookup the type
5823                         //
5824                         Expression array_type_expr;
5825                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5826                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5827
5828                         if (type == null)
5829                                 return false;
5830
5831                         underlying_type = type;
5832                         if (underlying_type.IsArray)
5833                                 underlying_type = TypeManager.GetElementType (underlying_type);
5834                         dimensions = type.GetArrayRank ();
5835
5836                         return true;
5837                 }
5838                 
5839                 public override Expression DoResolve (EmitContext ec)
5840                 {
5841                         int arg_count;
5842
5843                         if (!LookupType (ec))
5844                                 return null;
5845                         
5846                         //
5847                         // First step is to validate the initializers and fill
5848                         // in any missing bits
5849                         //
5850                         if (!ValidateInitializers (ec, type))
5851                                 return null;
5852
5853                         if (arguments == null)
5854                                 arg_count = 0;
5855                         else {
5856                                 arg_count = arguments.Count;
5857                                 foreach (Argument a in arguments){
5858                                         if (!a.Resolve (ec, loc))
5859                                                 return null;
5860
5861                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5862                                         if (real_arg == null)
5863                                                 return null;
5864
5865                                         a.Expr = real_arg;
5866                                 }
5867                         }
5868                         
5869                         array_element_type = TypeManager.GetElementType (type);
5870
5871                         if (arg_count == 1) {
5872                                 is_one_dimensional = true;
5873                                 eclass = ExprClass.Value;
5874                                 return this;
5875                         }
5876
5877                         is_builtin_type = TypeManager.IsBuiltinType (type);
5878
5879                         if (is_builtin_type) {
5880                                 Expression ml;
5881                                 
5882                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5883                                                    AllBindingFlags, loc);
5884                                 
5885                                 if (!(ml is MethodGroupExpr)) {
5886                                         ml.Error_UnexpectedKind ("method group");
5887                                         return null;
5888                                 }
5889                                 
5890                                 if (ml == null) {
5891                                         Error (-6, "New invocation: Can not find a constructor for " +
5892                                                       "this argument list");
5893                                         return null;
5894                                 }
5895                                 
5896                                 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5897
5898                                 if (new_method == null) {
5899                                         Error (-6, "New invocation: Can not find a constructor for " +
5900                                                       "this argument list");
5901                                         return null;
5902                                 }
5903                                 
5904                                 eclass = ExprClass.Value;
5905                                 return this;
5906                         } else {
5907                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5908                                 ArrayList args = new ArrayList ();
5909                                 
5910                                 if (arguments != null) {
5911                                         for (int i = 0; i < arg_count; i++)
5912                                                 args.Add (TypeManager.int32_type);
5913                                 }
5914                                 
5915                                 Type [] arg_types = null;
5916
5917                                 if (args.Count > 0)
5918                                         arg_types = new Type [args.Count];
5919                                 
5920                                 args.CopyTo (arg_types, 0);
5921                                 
5922                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5923                                                             arg_types);
5924
5925                                 if (new_method == null) {
5926                                         Error (-6, "New invocation: Can not find a constructor for " +
5927                                                       "this argument list");
5928                                         return null;
5929                                 }
5930                                 
5931                                 eclass = ExprClass.Value;
5932                                 return this;
5933                         }
5934                 }
5935
5936                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5937                 {
5938                         int factor;
5939                         byte [] data;
5940                         byte [] element;
5941                         int count = array_data.Count;
5942
5943                         if (underlying_type.IsEnum)
5944                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5945                         
5946                         factor = GetTypeSize (underlying_type);
5947                         if (factor == 0)
5948                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5949
5950                         data = new byte [(count * factor + 4) & ~3];
5951                         int idx = 0;
5952                         
5953                         for (int i = 0; i < count; ++i) {
5954                                 object v = array_data [i];
5955
5956                                 if (v is EnumConstant)
5957                                         v = ((EnumConstant) v).Child;
5958                                 
5959                                 if (v is Constant && !(v is StringConstant))
5960                                         v = ((Constant) v).GetValue ();
5961                                 else {
5962                                         idx += factor;
5963                                         continue;
5964                                 }
5965                                 
5966                                 if (underlying_type == TypeManager.int64_type){
5967                                         if (!(v is Expression)){
5968                                                 long val = (long) v;
5969                                                 
5970                                                 for (int j = 0; j < factor; ++j) {
5971                                                         data [idx + j] = (byte) (val & 0xFF);
5972                                                         val = (val >> 8);
5973                                                 }
5974                                         }
5975                                 } else if (underlying_type == TypeManager.uint64_type){
5976                                         if (!(v is Expression)){
5977                                                 ulong val = (ulong) v;
5978
5979                                                 for (int j = 0; j < factor; ++j) {
5980                                                         data [idx + j] = (byte) (val & 0xFF);
5981                                                         val = (val >> 8);
5982                                                 }
5983                                         }
5984                                 } else if (underlying_type == TypeManager.float_type) {
5985                                         if (!(v is Expression)){
5986                                                 element = BitConverter.GetBytes ((float) v);
5987                                                         
5988                                                 for (int j = 0; j < factor; ++j)
5989                                                         data [idx + j] = element [j];
5990                                         }
5991                                 } else if (underlying_type == TypeManager.double_type) {
5992                                         if (!(v is Expression)){
5993                                                 element = BitConverter.GetBytes ((double) v);
5994
5995                                                 for (int j = 0; j < factor; ++j)
5996                                                         data [idx + j] = element [j];
5997                                         }
5998                                 } else if (underlying_type == TypeManager.char_type){
5999                                         if (!(v is Expression)){
6000                                                 int val = (int) ((char) v);
6001                                                 
6002                                                 data [idx] = (byte) (val & 0xff);
6003                                                 data [idx+1] = (byte) (val >> 8);
6004                                         }
6005                                 } else if (underlying_type == TypeManager.short_type){
6006                                         if (!(v is Expression)){
6007                                                 int val = (int) ((short) v);
6008                                         
6009                                                 data [idx] = (byte) (val & 0xff);
6010                                                 data [idx+1] = (byte) (val >> 8);
6011                                         }
6012                                 } else if (underlying_type == TypeManager.ushort_type){
6013                                         if (!(v is Expression)){
6014                                                 int val = (int) ((ushort) v);
6015                                         
6016                                                 data [idx] = (byte) (val & 0xff);
6017                                                 data [idx+1] = (byte) (val >> 8);
6018                                         }
6019                                 } else if (underlying_type == TypeManager.int32_type) {
6020                                         if (!(v is Expression)){
6021                                                 int val = (int) v;
6022                                         
6023                                                 data [idx]   = (byte) (val & 0xff);
6024                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6025                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6026                                                 data [idx+3] = (byte) (val >> 24);
6027                                         }
6028                                 } else if (underlying_type == TypeManager.uint32_type) {
6029                                         if (!(v is Expression)){
6030                                                 uint val = (uint) v;
6031                                         
6032                                                 data [idx]   = (byte) (val & 0xff);
6033                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6034                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6035                                                 data [idx+3] = (byte) (val >> 24);
6036                                         }
6037                                 } else if (underlying_type == TypeManager.sbyte_type) {
6038                                         if (!(v is Expression)){
6039                                                 sbyte val = (sbyte) v;
6040                                                 data [idx] = (byte) val;
6041                                         }
6042                                 } else if (underlying_type == TypeManager.byte_type) {
6043                                         if (!(v is Expression)){
6044                                                 byte val = (byte) v;
6045                                                 data [idx] = (byte) val;
6046                                         }
6047                                 } else if (underlying_type == TypeManager.bool_type) {
6048                                         if (!(v is Expression)){
6049                                                 bool val = (bool) v;
6050                                                 data [idx] = (byte) (val ? 1 : 0);
6051                                         }
6052                                 } else if (underlying_type == TypeManager.decimal_type){
6053                                         if (!(v is Expression)){
6054                                                 int [] bits = Decimal.GetBits ((decimal) v);
6055                                                 int p = idx;
6056
6057                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6058                                                 int [] nbits = new int [4];
6059                                                 nbits [0] = bits [3];
6060                                                 nbits [1] = bits [2];
6061                                                 nbits [2] = bits [0];
6062                                                 nbits [3] = bits [1];
6063                                                 
6064                                                 for (int j = 0; j < 4; j++){
6065                                                         data [p++] = (byte) (nbits [j] & 0xff);
6066                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6067                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6068                                                         data [p++] = (byte) (nbits [j] >> 24);
6069                                                 }
6070                                         }
6071                                 } else
6072                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6073
6074                                 idx += factor;
6075                         }
6076
6077                         return data;
6078                 }
6079
6080                 //
6081                 // Emits the initializers for the array
6082                 //
6083                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
6084                 {
6085                         //
6086                         // First, the static data
6087                         //
6088                         FieldBuilder fb;
6089                         ILGenerator ig = ec.ig;
6090                         
6091                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6092
6093                         fb = RootContext.MakeStaticData (data);
6094
6095                         if (is_expression)
6096                                 ig.Emit (OpCodes.Dup);
6097                         ig.Emit (OpCodes.Ldtoken, fb);
6098                         ig.Emit (OpCodes.Call,
6099                                  TypeManager.void_initializearray_array_fieldhandle);
6100                 }
6101
6102                 //
6103                 // Emits pieces of the array that can not be computed at compile
6104                 // time (variables and string locations).
6105                 //
6106                 // This always expect the top value on the stack to be the array
6107                 //
6108                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
6109                 {
6110                         ILGenerator ig = ec.ig;
6111                         int dims = bounds.Count;
6112                         int [] current_pos = new int [dims];
6113                         int top = array_data.Count;
6114                         LocalBuilder temp = ig.DeclareLocal (type);
6115
6116                         ig.Emit (OpCodes.Stloc, temp);
6117
6118                         MethodInfo set = null;
6119
6120                         if (dims != 1){
6121                                 Type [] args;
6122                                 ModuleBuilder mb = null;
6123                                 mb = CodeGen.ModuleBuilder;
6124                                 args = new Type [dims + 1];
6125
6126                                 int j;
6127                                 for (j = 0; j < dims; j++)
6128                                         args [j] = TypeManager.int32_type;
6129
6130                                 args [j] = array_element_type;
6131                                 
6132                                 set = mb.GetArrayMethod (
6133                                         type, "Set",
6134                                         CallingConventions.HasThis | CallingConventions.Standard,
6135                                         TypeManager.void_type, args);
6136                         }
6137                         
6138                         for (int i = 0; i < top; i++){
6139
6140                                 Expression e = null;
6141
6142                                 if (array_data [i] is Expression)
6143                                         e = (Expression) array_data [i];
6144
6145                                 if (e != null) {
6146                                         //
6147                                         // Basically we do this for string literals and
6148                                         // other non-literal expressions
6149                                         //
6150                                         if (e is EnumConstant){
6151                                                 e = ((EnumConstant) e).Child;
6152                                         }
6153                                         
6154                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6155                                             num_automatic_initializers <= max_automatic_initializers) {
6156                                                 Type etype = e.Type;
6157                                                 
6158                                                 ig.Emit (OpCodes.Ldloc, temp);
6159
6160                                                 for (int idx = 0; idx < dims; idx++) 
6161                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6162
6163                                                 //
6164                                                 // If we are dealing with a struct, get the
6165                                                 // address of it, so we can store it.
6166                                                 //
6167                                                 if ((dims == 1) && 
6168                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6169                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6170                                                      etype == TypeManager.decimal_type)) {
6171                                                         if (e is New){
6172                                                                 New n = (New) e;
6173
6174                                                                 //
6175                                                                 // Let new know that we are providing
6176                                                                 // the address where to store the results
6177                                                                 //
6178                                                                 n.DisableTemporaryValueType ();
6179                                                         }
6180
6181                                                         ig.Emit (OpCodes.Ldelema, etype);
6182                                                 }
6183
6184                                                 e.Emit (ec);
6185
6186                                                 if (dims == 1)
6187                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
6188                                                 else 
6189                                                         ig.Emit (OpCodes.Call, set);
6190                                                 
6191                                         }
6192                                 }
6193                                 
6194                                 //
6195                                 // Advance counter
6196                                 //
6197                                 for (int j = dims - 1; j >= 0; j--){
6198                                         current_pos [j]++;
6199                                         if (current_pos [j] < (int) bounds [j])
6200                                                 break;
6201                                         current_pos [j] = 0;
6202                                 }
6203                         }
6204
6205                         if (is_expression)
6206                                 ig.Emit (OpCodes.Ldloc, temp);
6207                 }
6208
6209                 void EmitArrayArguments (EmitContext ec)
6210                 {
6211                         ILGenerator ig = ec.ig;
6212                         
6213                         foreach (Argument a in arguments) {
6214                                 Type atype = a.Type;
6215                                 a.Emit (ec);
6216
6217                                 if (atype == TypeManager.uint64_type)
6218                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6219                                 else if (atype == TypeManager.int64_type)
6220                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6221                         }
6222                 }
6223                 
6224                 void DoEmit (EmitContext ec, bool is_statement)
6225                 {
6226                         ILGenerator ig = ec.ig;
6227                         
6228                         EmitArrayArguments (ec);
6229                         if (is_one_dimensional)
6230                                 ig.Emit (OpCodes.Newarr, array_element_type);
6231                         else {
6232                                 if (is_builtin_type) 
6233                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6234                                 else 
6235                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6236                         }
6237                         
6238                         if (initializers != null){
6239                                 //
6240                                 // FIXME: Set this variable correctly.
6241                                 // 
6242                                 bool dynamic_initializers = true;
6243
6244                                 if (underlying_type != TypeManager.string_type &&
6245                                     underlying_type != TypeManager.decimal_type &&
6246                                     underlying_type != TypeManager.object_type) {
6247                                         if (num_automatic_initializers > max_automatic_initializers)
6248                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
6249                                 }
6250                                 
6251                                 if (dynamic_initializers)
6252                                         EmitDynamicInitializers (ec, !is_statement);
6253                         }
6254                 }
6255                 
6256                 public override void Emit (EmitContext ec)
6257                 {
6258                         DoEmit (ec, false);
6259                 }
6260
6261                 public override void EmitStatement (EmitContext ec)
6262                 {
6263                         DoEmit (ec, true);
6264                 }
6265
6266                 public object EncodeAsAttribute ()
6267                 {
6268                         if (!is_one_dimensional){
6269                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6270                                 return null;
6271                         }
6272
6273                         if (array_data == null){
6274                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6275                                 return null;
6276                         }
6277                         
6278                         object [] ret = new object [array_data.Count];
6279                         int i = 0;
6280                         foreach (Expression e in array_data){
6281                                 object v;
6282                                 
6283                                 if (e is NullLiteral)
6284                                         v = null;
6285                                 else {
6286                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
6287                                                 return null;
6288                                 }
6289                                 ret [i++] = v;
6290                         }
6291                         return ret;
6292                 }
6293         }
6294         
6295         /// <summary>
6296         ///   Represents the `this' construct
6297         /// </summary>
6298         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6299
6300                 Block block;
6301                 VariableInfo variable_info;
6302                 
6303                 public This (Block block, Location loc)
6304                 {
6305                         this.loc = loc;
6306                         this.block = block;
6307                 }
6308
6309                 public This (Location loc)
6310                 {
6311                         this.loc = loc;
6312                 }
6313
6314                 public VariableInfo VariableInfo {
6315                         get { return variable_info; }
6316                 }
6317
6318                 public bool VerifyFixed (bool is_expression)
6319                 {
6320                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6321                                 return false;
6322                         else
6323                                 return variable_info.LocalInfo.IsFixed;
6324                 }
6325
6326                 public bool ResolveBase (EmitContext ec)
6327                 {
6328                         eclass = ExprClass.Variable;
6329                         type = ec.ContainerType;
6330
6331                         if (ec.IsStatic) {
6332                                 Error (26, "Keyword this not valid in static code");
6333                                 return false;
6334                         }
6335
6336                         if ((block != null) && (block.ThisVariable != null))
6337                                 variable_info = block.ThisVariable.VariableInfo;
6338
6339                         return true;
6340                 }
6341
6342                 public override Expression DoResolve (EmitContext ec)
6343                 {
6344                         if (!ResolveBase (ec))
6345                                 return null;
6346
6347                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6348                                 Error (188, "The this object cannot be used before all " +
6349                                        "of its fields are assigned to");
6350                                 variable_info.SetAssigned (ec);
6351                                 return this;
6352                         }
6353
6354                         if (ec.IsFieldInitializer) {
6355                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6356                                        "a method or a property.");
6357                                 return null;
6358                         }
6359
6360                         return this;
6361                 }
6362
6363                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6364                 {
6365                         if (!ResolveBase (ec))
6366                                 return null;
6367
6368                         if (variable_info != null)
6369                                 variable_info.SetAssigned (ec);
6370                         
6371                         if (ec.TypeContainer is Class){
6372                                 Error (1604, "Cannot assign to `this'");
6373                                 return null;
6374                         }
6375
6376                         return this;
6377                 }
6378
6379                 public override void Emit (EmitContext ec)
6380                 {
6381                         ILGenerator ig = ec.ig;
6382                         
6383                         ig.Emit (OpCodes.Ldarg_0);
6384                         if (ec.TypeContainer is Struct)
6385                                 ig.Emit (OpCodes.Ldobj, type);
6386                 }
6387
6388                 public void EmitAssign (EmitContext ec, Expression source)
6389                 {
6390                         ILGenerator ig = ec.ig;
6391                         
6392                         if (ec.TypeContainer is Struct){
6393                                 ig.Emit (OpCodes.Ldarg_0);
6394                                 source.Emit (ec);
6395                                 ig.Emit (OpCodes.Stobj, type);
6396                         } else {
6397                                 source.Emit (ec);
6398                                 ig.Emit (OpCodes.Starg, 0);
6399                         }
6400                 }
6401
6402                 public void AddressOf (EmitContext ec, AddressOp mode)
6403                 {
6404                         ec.ig.Emit (OpCodes.Ldarg_0);
6405
6406                         // FIMXE
6407                         // FIGURE OUT WHY LDARG_S does not work
6408                         //
6409                         // consider: struct X { int val; int P { set { val = value; }}}
6410                         //
6411                         // Yes, this looks very bad. Look at `NOTAS' for
6412                         // an explanation.
6413                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6414                 }
6415         }
6416
6417         //
6418         // This produces the value that renders an instance, used by the iterators code
6419         //
6420         public class ProxyInstance : Expression, IMemoryLocation  {
6421                 public override Expression DoResolve (EmitContext ec)
6422                 {
6423                         eclass = ExprClass.Variable;
6424                         type = ec.ContainerType;
6425                         return this;
6426                 }
6427                 
6428                 public override void Emit (EmitContext ec)
6429                 {
6430                         ec.ig.Emit (OpCodes.Ldarg_0);
6431
6432                 }
6433                 
6434                 public void AddressOf (EmitContext ec, AddressOp mode)
6435                 {
6436                         ec.ig.Emit (OpCodes.Ldarg_0);
6437                 }
6438         }
6439
6440         /// <summary>
6441         ///   Implements the typeof operator
6442         /// </summary>
6443         public class TypeOf : Expression {
6444                 public readonly Expression QueriedType;
6445                 protected Type typearg;
6446                 
6447                 public TypeOf (Expression queried_type, Location l)
6448                 {
6449                         QueriedType = queried_type;
6450                         loc = l;
6451                 }
6452
6453                 public override Expression DoResolve (EmitContext ec)
6454                 {
6455                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6456
6457                         if (typearg == null)
6458                                 return null;
6459
6460                         if (typearg == TypeManager.void_type) {
6461                                 Error (673, "System.Void cannot be used from C# - " +
6462                                        "use typeof (void) to get the void type object");
6463                                 return null;
6464                         }
6465
6466                         type = TypeManager.type_type;
6467                         eclass = ExprClass.Type;
6468                         return this;
6469                 }
6470
6471                 public override void Emit (EmitContext ec)
6472                 {
6473                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6474                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6475                 }
6476
6477                 public Type TypeArg { 
6478                         get { return typearg; }
6479                 }
6480         }
6481
6482         /// <summary>
6483         ///   Implements the `typeof (void)' operator
6484         /// </summary>
6485         public class TypeOfVoid : TypeOf {
6486                 public TypeOfVoid (Location l) : base (null, l)
6487                 {
6488                         loc = l;
6489                 }
6490
6491                 public override Expression DoResolve (EmitContext ec)
6492                 {
6493                         type = TypeManager.type_type;
6494                         typearg = TypeManager.void_type;
6495                         eclass = ExprClass.Type;
6496                         return this;
6497                 }
6498         }
6499
6500         /// <summary>
6501         ///   Implements the sizeof expression
6502         /// </summary>
6503         public class SizeOf : Expression {
6504                 public readonly Expression QueriedType;
6505                 Type type_queried;
6506                 
6507                 public SizeOf (Expression queried_type, Location l)
6508                 {
6509                         this.QueriedType = queried_type;
6510                         loc = l;
6511                 }
6512
6513                 public override Expression DoResolve (EmitContext ec)
6514                 {
6515                         if (!ec.InUnsafe) {
6516                                 Report.Error (
6517                                         233, loc, "Sizeof may only be used in an unsafe context " +
6518                                         "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
6519                                 return null;
6520                         }
6521                                 
6522                         type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6523                         if (type_queried == null)
6524                                 return null;
6525
6526                         if (!TypeManager.IsUnmanagedType (type_queried)){
6527                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6528                                 return null;
6529                         }
6530                         
6531                         type = TypeManager.int32_type;
6532                         eclass = ExprClass.Value;
6533                         return this;
6534                 }
6535
6536                 public override void Emit (EmitContext ec)
6537                 {
6538                         int size = GetTypeSize (type_queried);
6539
6540                         if (size == 0)
6541                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6542                         else
6543                                 IntConstant.EmitInt (ec.ig, size);
6544                 }
6545         }
6546
6547         /// <summary>
6548         ///   Implements the member access expression
6549         /// </summary>
6550         public class MemberAccess : Expression {
6551                 public readonly string Identifier;
6552                 Expression expr;
6553                 
6554                 public MemberAccess (Expression expr, string id, Location l)
6555                 {
6556                         this.expr = expr;
6557                         Identifier = id;
6558                         loc = l;
6559                 }
6560
6561                 public Expression Expr {
6562                         get {
6563                                 return expr;
6564                         }
6565                 }
6566
6567                 static void error176 (Location loc, string name)
6568                 {
6569                         Report.Error (176, loc, "Static member `" +
6570                                       name + "' cannot be accessed " +
6571                                       "with an instance reference, qualify with a " +
6572                                       "type name instead");
6573                 }
6574
6575                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6576                 {
6577                         if (left_original == null)
6578                                 return false;
6579
6580                         if (!(left_original is SimpleName))
6581                                 return false;
6582
6583                         SimpleName sn = (SimpleName) left_original;
6584
6585                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6586                         if (t != null)
6587                                 return true;
6588
6589                         return false;
6590                 }
6591                 
6592                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6593                                                               Expression left, Location loc,
6594                                                               Expression left_original)
6595                 {
6596                         bool left_is_type, left_is_explicit;
6597
6598                         // If `left' is null, then we're called from SimpleNameResolve and this is
6599                         // a member in the currently defining class.
6600                         if (left == null) {
6601                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6602                                 left_is_explicit = false;
6603
6604                                 // Implicitly default to `this' unless we're static.
6605                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6606                                         left = ec.GetThis (loc);
6607                         } else {
6608                                 left_is_type = left is TypeExpr;
6609                                 left_is_explicit = true;
6610                         }
6611
6612                         if (member_lookup is FieldExpr){
6613                                 FieldExpr fe = (FieldExpr) member_lookup;
6614                                 FieldInfo fi = fe.FieldInfo;
6615                                 Type decl_type = fi.DeclaringType;
6616
6617                                 if (fi is FieldBuilder) {
6618                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6619                                         
6620                                         if (c != null) {
6621                                                 object o = c.LookupConstantValue ();
6622                                                 if (o == null)
6623                                                         return null;
6624                                                 
6625                                                 object real_value = ((Constant) c.Expr).GetValue ();
6626
6627                                                 return Constantify (real_value, fi.FieldType);
6628                                         }
6629                                 }
6630
6631                                 if (fi.IsLiteral) {
6632                                         Type t = fi.FieldType;
6633                                         
6634                                         object o;
6635
6636                                         if (fi is FieldBuilder)
6637                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
6638                                         else
6639                                                 o = fi.GetValue (fi);
6640                                         
6641                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6642                                                 if (left_is_explicit && !left_is_type &&
6643                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {
6644                                                         error176 (loc, fe.FieldInfo.Name);
6645                                                         return null;
6646                                                 }                                       
6647                                                 
6648                                                 Expression enum_member = MemberLookup (
6649                                                         ec, decl_type, "value__", MemberTypes.Field,
6650                                                         AllBindingFlags, loc); 
6651
6652                                                 Enum en = TypeManager.LookupEnum (decl_type);
6653
6654                                                 Constant c;
6655                                                 if (en != null)
6656                                                         c = Constantify (o, en.UnderlyingType);
6657                                                 else 
6658                                                         c = Constantify (o, enum_member.Type);
6659                                                 
6660                                                 return new EnumConstant (c, decl_type);
6661                                         }
6662                                         
6663                                         Expression exp = Constantify (o, t);
6664
6665                                         if (left_is_explicit && !left_is_type) {
6666                                                 error176 (loc, fe.FieldInfo.Name);
6667                                                 return null;
6668                                         }
6669                                         
6670                                         return exp;
6671                                 }
6672
6673                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6674                                         UnsafeError (loc);
6675                                         return null;
6676                                 }
6677                         }
6678
6679                         if (member_lookup is EventExpr) {
6680                                 EventExpr ee = (EventExpr) member_lookup;
6681                                 
6682                                 //
6683                                 // If the event is local to this class, we transform ourselves into
6684                                 // a FieldExpr
6685                                 //
6686
6687                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
6688                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
6689                                         MemberInfo mi = GetFieldFromEvent (ee);
6690
6691                                         if (mi == null) {
6692                                                 //
6693                                                 // If this happens, then we have an event with its own
6694                                                 // accessors and private field etc so there's no need
6695                                                 // to transform ourselves.
6696                                                 //
6697                                                 return ee;
6698                                         }
6699
6700                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
6701                                         
6702                                         if (ml == null) {
6703                                                 Report.Error (-200, loc, "Internal error!!");
6704                                                 return null;
6705                                         }
6706
6707                                         if (!left_is_explicit)
6708                                                 left = null;
6709                                         
6710                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
6711                                 }
6712                         }
6713
6714                         if (member_lookup is IMemberExpr) {
6715                                 IMemberExpr me = (IMemberExpr) member_lookup;
6716
6717                                 if (left_is_type){
6718                                         MethodGroupExpr mg = me as MethodGroupExpr;
6719                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6720                                                 mg.IsExplicitImpl = left_is_explicit;
6721
6722                                         if (!me.IsStatic){
6723                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
6724                                                     IdenticalNameAndTypeName (ec, left_original, loc))
6725                                                         return member_lookup;
6726
6727                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6728                                                 return null;
6729                                         }
6730
6731                                 } else {
6732                                         if (!me.IsInstance){
6733                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
6734                                                         return member_lookup;
6735
6736                                                 if (left_is_explicit) {
6737                                                         error176 (loc, me.Name);
6738                                                         return null;
6739                                                 }
6740                                         }
6741
6742                                         //
6743                                         // Since we can not check for instance objects in SimpleName,
6744                                         // becaue of the rule that allows types and variables to share
6745                                         // the name (as long as they can be de-ambiguated later, see 
6746                                         // IdenticalNameAndTypeName), we have to check whether left 
6747                                         // is an instance variable in a static context
6748                                         //
6749                                         // However, if the left-hand value is explicitly given, then
6750                                         // it is already our instance expression, so we aren't in
6751                                         // static context.
6752                                         //
6753
6754                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6755                                                 IMemberExpr mexp = (IMemberExpr) left;
6756
6757                                                 if (!mexp.IsStatic){
6758                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6759                                                         return null;
6760                                                 }
6761                                         }
6762
6763                                         me.InstanceExpression = left;
6764                                 }
6765
6766                                 return member_lookup;
6767                         }
6768
6769                         Console.WriteLine ("Left is: " + left);
6770                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6771                         Environment.Exit (0);
6772                         return null;
6773                 }
6774                 
6775                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6776                 {
6777                         if (type != null)
6778                                 throw new Exception ();
6779
6780                         //
6781                         // Resolve the expression with flow analysis turned off, we'll do the definite
6782                         // assignment checks later.  This is because we don't know yet what the expression
6783                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6784                         // definite assignment check on the actual field and not on the whole struct.
6785                         //
6786
6787                         Expression original = expr;
6788                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6789                         if (expr == null)
6790                                 return null;
6791
6792                         if (expr is SimpleName){
6793                                 SimpleName child_expr = (SimpleName) expr;
6794
6795                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6796
6797                                 return new_expr.Resolve (ec, flags);
6798                         }
6799                                         
6800                         //
6801                         // TODO: I mailed Ravi about this, and apparently we can get rid
6802                         // of this and put it in the right place.
6803                         // 
6804                         // Handle enums here when they are in transit.
6805                         // Note that we cannot afford to hit MemberLookup in this case because
6806                         // it will fail to find any members at all
6807                         //
6808
6809                         Type expr_type = expr.Type;
6810                         if (expr is TypeExpr){
6811                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
6812                                         Error (122, "`" + expr_type + "' " +
6813                                                "is inaccessible because of its protection level");
6814                                         return null;
6815                                 }
6816
6817                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6818                                         Enum en = TypeManager.LookupEnum (expr_type);
6819
6820                                         if (en != null) {
6821                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
6822                                                 
6823                                                 if (value != null){
6824                                                         Constant c = Constantify (value, en.UnderlyingType);
6825                                                         return new EnumConstant (c, expr_type);
6826                                                 }
6827                                         }
6828                                 }
6829                         }
6830                         
6831                         if (expr_type.IsPointer){
6832                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6833                                        TypeManager.CSharpName (expr_type) + ")");
6834                                 return null;
6835                         }
6836
6837                         Expression member_lookup;
6838                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6839                         if (member_lookup == null)
6840                                 return null;
6841
6842                         if (member_lookup is TypeExpr) {
6843                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
6844                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
6845                                                member_lookup.Type + "' instead");
6846                                         return null;
6847                                 }
6848
6849                                 return member_lookup;
6850                         }
6851                         
6852                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6853                         if (member_lookup == null)
6854                                 return null;
6855
6856                         // The following DoResolve/DoResolveLValue will do the definite assignment
6857                         // check.
6858
6859                         if (right_side != null)
6860                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6861                         else
6862                                 member_lookup = member_lookup.DoResolve (ec);
6863
6864                         return member_lookup;
6865                 }
6866
6867                 public override Expression DoResolve (EmitContext ec)
6868                 {
6869                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6870                                           ResolveFlags.SimpleName | ResolveFlags.Type);
6871                 }
6872
6873                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6874                 {
6875                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6876                                           ResolveFlags.SimpleName | ResolveFlags.Type);
6877                 }
6878
6879                 public override Expression ResolveAsTypeStep (EmitContext ec)
6880                 {
6881                         string fname = null;
6882                         MemberAccess full_expr = this;
6883                         while (full_expr != null) {
6884                                 if (fname != null)
6885                                         fname = String.Concat (full_expr.Identifier, ".", fname);
6886                                 else
6887                                         fname = full_expr.Identifier;
6888
6889                                 if (full_expr.Expr is SimpleName) {
6890                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
6891                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
6892                                         if (fully_qualified != null)
6893                                                 return new TypeExpression (fully_qualified, loc);
6894                                 }
6895
6896                                 full_expr = full_expr.Expr as MemberAccess;
6897                         }
6898
6899                         Expression new_expr = expr.ResolveAsTypeStep (ec);
6900
6901                         if (new_expr == null)
6902                                 return null;
6903
6904                         if (new_expr is SimpleName){
6905                                 SimpleName child_expr = (SimpleName) new_expr;
6906                                 
6907                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6908
6909                                 return new_expr.ResolveAsTypeStep (ec);
6910                         }
6911
6912                         Type expr_type = new_expr.Type;
6913                       
6914                         if (expr_type.IsPointer){
6915                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6916                                        TypeManager.CSharpName (expr_type) + ")");
6917                                 return null;
6918                         }
6919                         
6920                         Expression member_lookup;
6921                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6922                         if (member_lookup == null)
6923                                 return null;
6924
6925                         if (member_lookup is TypeExpr){
6926                                 member_lookup.Resolve (ec, ResolveFlags.Type);
6927                                 return member_lookup;
6928                         } 
6929
6930                         return null;                    
6931                 }
6932
6933                 public override void Emit (EmitContext ec)
6934                 {
6935                         throw new Exception ("Should not happen");
6936                 }
6937
6938                 public override string ToString ()
6939                 {
6940                         return expr + "." + Identifier;
6941                 }
6942         }
6943
6944         /// <summary>
6945         ///   Implements checked expressions
6946         /// </summary>
6947         public class CheckedExpr : Expression {
6948
6949                 public Expression Expr;
6950
6951                 public CheckedExpr (Expression e, Location l)
6952                 {
6953                         Expr = e;
6954                         loc = l;
6955                 }
6956
6957                 public override Expression DoResolve (EmitContext ec)
6958                 {
6959                         bool last_check = ec.CheckState;
6960                         bool last_const_check = ec.ConstantCheckState;
6961
6962                         ec.CheckState = true;
6963                         ec.ConstantCheckState = true;
6964                         Expr = Expr.Resolve (ec);
6965                         ec.CheckState = last_check;
6966                         ec.ConstantCheckState = last_const_check;
6967                         
6968                         if (Expr == null)
6969                                 return null;
6970
6971                         if (Expr is Constant)
6972                                 return Expr;
6973                         
6974                         eclass = Expr.eclass;
6975                         type = Expr.Type;
6976                         return this;
6977                 }
6978
6979                 public override void Emit (EmitContext ec)
6980                 {
6981                         bool last_check = ec.CheckState;
6982                         bool last_const_check = ec.ConstantCheckState;
6983                         
6984                         ec.CheckState = true;
6985                         ec.ConstantCheckState = true;
6986                         Expr.Emit (ec);
6987                         ec.CheckState = last_check;
6988                         ec.ConstantCheckState = last_const_check;
6989                 }
6990                 
6991         }
6992
6993         /// <summary>
6994         ///   Implements the unchecked expression
6995         /// </summary>
6996         public class UnCheckedExpr : Expression {
6997
6998                 public Expression Expr;
6999
7000                 public UnCheckedExpr (Expression e, Location l)
7001                 {
7002                         Expr = e;
7003                         loc = l;
7004                 }
7005
7006                 public override Expression DoResolve (EmitContext ec)
7007                 {
7008                         bool last_check = ec.CheckState;
7009                         bool last_const_check = ec.ConstantCheckState;
7010
7011                         ec.CheckState = false;
7012                         ec.ConstantCheckState = false;
7013                         Expr = Expr.Resolve (ec);
7014                         ec.CheckState = last_check;
7015                         ec.ConstantCheckState = last_const_check;
7016
7017                         if (Expr == null)
7018                                 return null;
7019
7020                         if (Expr is Constant)
7021                                 return Expr;
7022                         
7023                         eclass = Expr.eclass;
7024                         type = Expr.Type;
7025                         return this;
7026                 }
7027
7028                 public override void Emit (EmitContext ec)
7029                 {
7030                         bool last_check = ec.CheckState;
7031                         bool last_const_check = ec.ConstantCheckState;
7032                         
7033                         ec.CheckState = false;
7034                         ec.ConstantCheckState = false;
7035                         Expr.Emit (ec);
7036                         ec.CheckState = last_check;
7037                         ec.ConstantCheckState = last_const_check;
7038                 }
7039                 
7040         }
7041
7042         /// <summary>
7043         ///   An Element Access expression.
7044         ///
7045         ///   During semantic analysis these are transformed into 
7046         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7047         /// </summary>
7048         public class ElementAccess : Expression {
7049                 public ArrayList  Arguments;
7050                 public Expression Expr;
7051                 
7052                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7053                 {
7054                         Expr = e;
7055
7056                         loc  = l;
7057                         
7058                         if (e_list == null)
7059                                 return;
7060                         
7061                         Arguments = new ArrayList ();
7062                         foreach (Expression tmp in e_list)
7063                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7064                         
7065                 }
7066
7067                 bool CommonResolve (EmitContext ec)
7068                 {
7069                         Expr = Expr.Resolve (ec);
7070
7071                         if (Expr == null) 
7072                                 return false;
7073
7074                         if (Arguments == null)
7075                                 return false;
7076
7077                         foreach (Argument a in Arguments){
7078                                 if (!a.Resolve (ec, loc))
7079                                         return false;
7080                         }
7081
7082                         return true;
7083                 }
7084
7085                 Expression MakePointerAccess ()
7086                 {
7087                         Type t = Expr.Type;
7088
7089                         if (t == TypeManager.void_ptr_type){
7090                                 Error (242, "The array index operation is not valid for void pointers");
7091                                 return null;
7092                         }
7093                         if (Arguments.Count != 1){
7094                                 Error (196, "A pointer must be indexed by a single value");
7095                                 return null;
7096                         }
7097                         Expression p;
7098
7099                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
7100                         return new Indirection (p, loc);
7101                 }
7102                 
7103                 public override Expression DoResolve (EmitContext ec)
7104                 {
7105                         if (!CommonResolve (ec))
7106                                 return null;
7107
7108                         //
7109                         // We perform some simple tests, and then to "split" the emit and store
7110                         // code we create an instance of a different class, and return that.
7111                         //
7112                         // I am experimenting with this pattern.
7113                         //
7114                         Type t = Expr.Type;
7115
7116                         if (t == TypeManager.array_type){
7117                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7118                                 return null;
7119                         }
7120                         
7121                         if (t.IsArray)
7122                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7123                         else if (t.IsPointer)
7124                                 return MakePointerAccess ();
7125                         else
7126                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7127                 }
7128
7129                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7130                 {
7131                         if (!CommonResolve (ec))
7132                                 return null;
7133
7134                         Type t = Expr.Type;
7135                         if (t.IsArray)
7136                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7137                         else if (t.IsPointer)
7138                                 return MakePointerAccess ();
7139                         else
7140                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7141                 }
7142                 
7143                 public override void Emit (EmitContext ec)
7144                 {
7145                         throw new Exception ("Should never be reached");
7146                 }
7147         }
7148
7149         /// <summary>
7150         ///   Implements array access 
7151         /// </summary>
7152         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7153                 //
7154                 // Points to our "data" repository
7155                 //
7156                 ElementAccess ea;
7157
7158                 LocalTemporary [] cached_locations;
7159                 
7160                 public ArrayAccess (ElementAccess ea_data, Location l)
7161                 {
7162                         ea = ea_data;
7163                         eclass = ExprClass.Variable;
7164                         loc = l;
7165                 }
7166
7167                 public override Expression DoResolve (EmitContext ec)
7168                 {
7169 #if false
7170                         ExprClass eclass = ea.Expr.eclass;
7171
7172                         // As long as the type is valid
7173                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7174                               eclass == ExprClass.Value)) {
7175                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7176                                 return null;
7177                         }
7178 #endif
7179
7180                         Type t = ea.Expr.Type;
7181                         if (t.GetArrayRank () != ea.Arguments.Count){
7182                                 ea.Error (22,
7183                                           "Incorrect number of indexes for array " +
7184                                           " expected: " + t.GetArrayRank () + " got: " +
7185                                           ea.Arguments.Count);
7186                                 return null;
7187                         }
7188
7189                         type = TypeManager.GetElementType (t);
7190                         if (type.IsPointer && !ec.InUnsafe){
7191                                 UnsafeError (ea.Location);
7192                                 return null;
7193                         }
7194
7195                         foreach (Argument a in ea.Arguments){
7196                                 Type argtype = a.Type;
7197
7198                                 if (argtype == TypeManager.int32_type ||
7199                                     argtype == TypeManager.uint32_type ||
7200                                     argtype == TypeManager.int64_type ||
7201                                     argtype == TypeManager.uint64_type)
7202                                         continue;
7203
7204                                 //
7205                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7206                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7207                                 //
7208                                 // Wonder if I will run into trouble for this.
7209                                 //
7210                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7211                                 if (a.Expr == null)
7212                                         return null;
7213                         }
7214                         
7215                         eclass = ExprClass.Variable;
7216
7217                         return this;
7218                 }
7219
7220                 /// <summary>
7221                 ///    Emits the right opcode to load an object of Type `t'
7222                 ///    from an array of T
7223                 /// </summary>
7224                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7225                 {
7226                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7227                                 ig.Emit (OpCodes.Ldelem_U1);
7228                         else if (type == TypeManager.sbyte_type)
7229                                 ig.Emit (OpCodes.Ldelem_I1);
7230                         else if (type == TypeManager.short_type)
7231                                 ig.Emit (OpCodes.Ldelem_I2);
7232                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7233                                 ig.Emit (OpCodes.Ldelem_U2);
7234                         else if (type == TypeManager.int32_type)
7235                                 ig.Emit (OpCodes.Ldelem_I4);
7236                         else if (type == TypeManager.uint32_type)
7237                                 ig.Emit (OpCodes.Ldelem_U4);
7238                         else if (type == TypeManager.uint64_type)
7239                                 ig.Emit (OpCodes.Ldelem_I8);
7240                         else if (type == TypeManager.int64_type)
7241                                 ig.Emit (OpCodes.Ldelem_I8);
7242                         else if (type == TypeManager.float_type)
7243                                 ig.Emit (OpCodes.Ldelem_R4);
7244                         else if (type == TypeManager.double_type)
7245                                 ig.Emit (OpCodes.Ldelem_R8);
7246                         else if (type == TypeManager.intptr_type)
7247                                 ig.Emit (OpCodes.Ldelem_I);
7248                         else if (type.IsValueType){
7249                                 ig.Emit (OpCodes.Ldelema, type);
7250                                 ig.Emit (OpCodes.Ldobj, type);
7251                         } else 
7252                                 ig.Emit (OpCodes.Ldelem_Ref);
7253                 }
7254
7255                 /// <summary>
7256                 ///    Emits the right opcode to store an object of Type `t'
7257                 ///    from an array of T.  
7258                 /// </summary>
7259                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
7260                 {
7261                         bool is_stobj;
7262                         OpCode op = GetStoreOpcode (t, out is_stobj);
7263                         if (is_stobj)
7264                                 ig.Emit (OpCodes.Stobj, t);
7265                         else
7266                                 ig.Emit (op);
7267                 }
7268
7269                 /// <summary>
7270                 ///    Returns the right opcode to store an object of Type `t'
7271                 ///    from an array of T.  
7272                 /// </summary>
7273                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7274                 {
7275                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7276                         is_stobj = false;
7277                         t = TypeManager.TypeToCoreType (t);
7278                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
7279                                 t = TypeManager.EnumToUnderlying (t);
7280                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7281                             t == TypeManager.bool_type)
7282                                 return OpCodes.Stelem_I1;
7283                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7284                                  t == TypeManager.char_type)
7285                                 return OpCodes.Stelem_I2;
7286                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7287                                 return OpCodes.Stelem_I4;
7288                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7289                                 return OpCodes.Stelem_I8;
7290                         else if (t == TypeManager.float_type)
7291                                 return OpCodes.Stelem_R4;
7292                         else if (t == TypeManager.double_type)
7293                                 return OpCodes.Stelem_R8;
7294                         else if (t == TypeManager.intptr_type) {
7295                                 is_stobj = true;
7296                                 return OpCodes.Stobj;
7297                         } else if (t.IsValueType) {
7298                                 is_stobj = true;
7299                                 return OpCodes.Stobj;
7300                         } else
7301                                 return OpCodes.Stelem_Ref;
7302                 }
7303
7304                 MethodInfo FetchGetMethod ()
7305                 {
7306                         ModuleBuilder mb = CodeGen.ModuleBuilder;
7307                         int arg_count = ea.Arguments.Count;
7308                         Type [] args = new Type [arg_count];
7309                         MethodInfo get;
7310                         
7311                         for (int i = 0; i < arg_count; i++){
7312                                 //args [i++] = a.Type;
7313                                 args [i] = TypeManager.int32_type;
7314                         }
7315                         
7316                         get = mb.GetArrayMethod (
7317                                 ea.Expr.Type, "Get",
7318                                 CallingConventions.HasThis |
7319                                 CallingConventions.Standard,
7320                                 type, args);
7321                         return get;
7322                 }
7323                                 
7324
7325                 MethodInfo FetchAddressMethod ()
7326                 {
7327                         ModuleBuilder mb = CodeGen.ModuleBuilder;
7328                         int arg_count = ea.Arguments.Count;
7329                         Type [] args = new Type [arg_count];
7330                         MethodInfo address;
7331                         Type ret_type;
7332                         
7333                         ret_type = TypeManager.GetReferenceType (type);
7334                         
7335                         for (int i = 0; i < arg_count; i++){
7336                                 //args [i++] = a.Type;
7337                                 args [i] = TypeManager.int32_type;
7338                         }
7339                         
7340                         address = mb.GetArrayMethod (
7341                                 ea.Expr.Type, "Address",
7342                                 CallingConventions.HasThis |
7343                                 CallingConventions.Standard,
7344                                 ret_type, args);
7345
7346                         return address;
7347                 }
7348
7349                 //
7350                 // Load the array arguments into the stack.
7351                 //
7352                 // If we have been requested to cache the values (cached_locations array
7353                 // initialized), then load the arguments the first time and store them
7354                 // in locals.  otherwise load from local variables.
7355                 //
7356                 void LoadArrayAndArguments (EmitContext ec)
7357                 {
7358                         ILGenerator ig = ec.ig;
7359                         
7360                         if (cached_locations == null){
7361                                 ea.Expr.Emit (ec);
7362                                 foreach (Argument a in ea.Arguments){
7363                                         Type argtype = a.Expr.Type;
7364                                         
7365                                         a.Expr.Emit (ec);
7366                                         
7367                                         if (argtype == TypeManager.int64_type)
7368                                                 ig.Emit (OpCodes.Conv_Ovf_I);
7369                                         else if (argtype == TypeManager.uint64_type)
7370                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7371                                 }
7372                                 return;
7373                         }
7374
7375                         if (cached_locations [0] == null){
7376                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
7377                                 ea.Expr.Emit (ec);
7378                                 ig.Emit (OpCodes.Dup);
7379                                 cached_locations [0].Store (ec);
7380                                 
7381                                 int j = 1;
7382                                 
7383                                 foreach (Argument a in ea.Arguments){
7384                                         Type argtype = a.Expr.Type;
7385                                         
7386                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
7387                                         a.Expr.Emit (ec);
7388                                         if (argtype == TypeManager.int64_type)
7389                                                 ig.Emit (OpCodes.Conv_Ovf_I);
7390                                         else if (argtype == TypeManager.uint64_type)
7391                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7392
7393                                         ig.Emit (OpCodes.Dup);
7394                                         cached_locations [j].Store (ec);
7395                                         j++;
7396                                 }
7397                                 return;
7398                         }
7399
7400                         foreach (LocalTemporary lt in cached_locations)
7401                                 lt.Emit (ec);
7402                 }
7403
7404                 public new void CacheTemporaries (EmitContext ec)
7405                 {
7406                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
7407                 }
7408                 
7409                 public override void Emit (EmitContext ec)
7410                 {
7411                         int rank = ea.Expr.Type.GetArrayRank ();
7412                         ILGenerator ig = ec.ig;
7413
7414                         LoadArrayAndArguments (ec);
7415                         
7416                         if (rank == 1)
7417                                 EmitLoadOpcode (ig, type);
7418                         else {
7419                                 MethodInfo method;
7420                                 
7421                                 method = FetchGetMethod ();
7422                                 ig.Emit (OpCodes.Call, method);
7423                         }
7424                 }
7425
7426                 public void EmitAssign (EmitContext ec, Expression source)
7427                 {
7428                         int rank = ea.Expr.Type.GetArrayRank ();
7429                         ILGenerator ig = ec.ig;
7430                         Type t = source.Type;
7431
7432                         LoadArrayAndArguments (ec);
7433
7434                         //
7435                         // The stobj opcode used by value types will need
7436                         // an address on the stack, not really an array/array
7437                         // pair
7438                         //
7439                         if (rank == 1){
7440                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
7441                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
7442                                         ig.Emit (OpCodes.Ldelema, t);
7443                         }
7444                         
7445                         source.Emit (ec);
7446
7447                         if (rank == 1)
7448                                 EmitStoreOpcode (ig, t);
7449                         else {
7450                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
7451                                 int arg_count = ea.Arguments.Count;
7452                                 Type [] args = new Type [arg_count + 1];
7453                                 MethodInfo set;
7454                                 
7455                                 for (int i = 0; i < arg_count; i++){
7456                                         //args [i++] = a.Type;
7457                                         args [i] = TypeManager.int32_type;
7458                                 }
7459
7460                                 args [arg_count] = type;
7461                                 
7462                                 set = mb.GetArrayMethod (
7463                                         ea.Expr.Type, "Set",
7464                                         CallingConventions.HasThis |
7465                                         CallingConventions.Standard,
7466                                         TypeManager.void_type, args);
7467                                 
7468                                 ig.Emit (OpCodes.Call, set);
7469                         }
7470                 }
7471
7472                 public void AddressOf (EmitContext ec, AddressOp mode)
7473                 {
7474                         int rank = ea.Expr.Type.GetArrayRank ();
7475                         ILGenerator ig = ec.ig;
7476
7477                         LoadArrayAndArguments (ec);
7478
7479                         if (rank == 1){
7480                                 ig.Emit (OpCodes.Ldelema, type);
7481                         } else {
7482                                 MethodInfo address = FetchAddressMethod ();
7483                                 ig.Emit (OpCodes.Call, address);
7484                         }
7485                 }
7486         }
7487
7488         
7489         class Indexers {
7490                 public ArrayList Properties;
7491                 static Hashtable map;
7492
7493                 public struct Indexer {
7494                         public readonly Type Type;
7495                         public readonly MethodInfo Getter, Setter;
7496
7497                         public Indexer (Type type, MethodInfo get, MethodInfo set)
7498                         {
7499                                 this.Type = type;
7500                                 this.Getter = get;
7501                                 this.Setter = set;
7502                         }
7503                 }
7504
7505                 static Indexers ()
7506                 {
7507                         map = new Hashtable ();
7508                 }
7509
7510                 Indexers ()
7511                 {
7512                         Properties = new ArrayList ();
7513                 }
7514                                 
7515                 void Append (MemberInfo [] mi)
7516                 {
7517                         foreach (PropertyInfo property in mi){
7518                                 MethodInfo get, set;
7519                                 
7520                                 get = property.GetGetMethod (true);
7521                                 set = property.GetSetMethod (true);
7522                                 Properties.Add (new Indexer (property.PropertyType, get, set));
7523                         }
7524                 }
7525
7526                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7527                 {
7528                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7529
7530                         MemberInfo [] mi = TypeManager.MemberLookup (
7531                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7532                                 BindingFlags.Public | BindingFlags.Instance |
7533                                 BindingFlags.DeclaredOnly, p_name);
7534
7535                         if (mi == null || mi.Length == 0)
7536                                 return null;
7537
7538                         return mi;
7539                 }
7540                 
7541                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
7542                 {
7543                         Indexers ix = (Indexers) map [lookup_type];
7544
7545                         if (ix != null)
7546                                 return ix;
7547
7548                         Type copy = lookup_type;
7549                         while (copy != TypeManager.object_type && copy != null){
7550                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
7551
7552                                 if (mi != null){
7553                                         if (ix == null)
7554                                                 ix = new Indexers ();
7555
7556                                         ix.Append (mi);
7557                                 }
7558                                         
7559                                 copy = copy.BaseType;
7560                         }
7561
7562                         if (!lookup_type.IsInterface)
7563                                 return ix;
7564
7565                         TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
7566                         if (ifaces != null) {
7567                                 foreach (TypeExpr iface in ifaces) {
7568                                         Type itype = iface.Type;
7569                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
7570                                         if (mi != null){
7571                                                 if (ix == null)
7572                                                         ix = new Indexers ();
7573                                         
7574                                                 ix.Append (mi);
7575                                         }
7576                                 }
7577                         }
7578
7579                         return ix;
7580                 }
7581         }
7582
7583         /// <summary>
7584         ///   Expressions that represent an indexer call.
7585         /// </summary>
7586         public class IndexerAccess : Expression, IAssignMethod {
7587                 //
7588                 // Points to our "data" repository
7589                 //
7590                 MethodInfo get, set;
7591                 ArrayList set_arguments;
7592                 bool is_base_indexer;
7593
7594                 protected Type indexer_type;
7595                 protected Type current_type;
7596                 protected Expression instance_expr;
7597                 protected ArrayList arguments;
7598                 
7599                 public IndexerAccess (ElementAccess ea, Location loc)
7600                         : this (ea.Expr, false, loc)
7601                 {
7602                         this.arguments = ea.Arguments;
7603                 }
7604
7605                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7606                                          Location loc)
7607                 {
7608                         this.instance_expr = instance_expr;
7609                         this.is_base_indexer = is_base_indexer;
7610                         this.eclass = ExprClass.Value;
7611                         this.loc = loc;
7612                 }
7613
7614                 protected virtual bool CommonResolve (EmitContext ec)
7615                 {
7616                         indexer_type = instance_expr.Type;
7617                         current_type = ec.ContainerType;
7618
7619                         return true;
7620                 }
7621
7622                 public override Expression DoResolve (EmitContext ec)
7623                 {
7624                         ArrayList AllGetters = new ArrayList();
7625                         if (!CommonResolve (ec))
7626                                 return null;
7627
7628                         //
7629                         // Step 1: Query for all `Item' *properties*.  Notice
7630                         // that the actual methods are pointed from here.
7631                         //
7632                         // This is a group of properties, piles of them.  
7633
7634                         bool found_any = false, found_any_getters = false;
7635                         Type lookup_type = indexer_type;
7636
7637                         Indexers ilist;
7638                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
7639                         if (ilist != null) {
7640                                 found_any = true;
7641                                 if (ilist.Properties != null) {
7642                                         foreach (Indexers.Indexer ix in ilist.Properties) {
7643                                                 if (ix.Getter != null)
7644                                                         AllGetters.Add(ix.Getter);
7645                                         }
7646                                 }
7647                         }
7648
7649                         if (AllGetters.Count > 0) {
7650                                 found_any_getters = true;
7651                                 get = (MethodInfo) Invocation.OverloadResolve (
7652                                         ec, new MethodGroupExpr (AllGetters, loc), arguments, loc);
7653                         }
7654
7655                         if (!found_any) {
7656                                 Report.Error (21, loc,
7657                                               "Type `" + TypeManager.CSharpName (indexer_type) +
7658                                               "' does not have any indexers defined");
7659                                 return null;
7660                         }
7661
7662                         if (!found_any_getters) {
7663                                 Error (154, "indexer can not be used in this context, because " +
7664                                        "it lacks a `get' accessor");
7665                                 return null;
7666                         }
7667
7668                         if (get == null) {
7669                                 Error (1501, "No Overload for method `this' takes `" +
7670                                        arguments.Count + "' arguments");
7671                                 return null;
7672                         }
7673
7674                         //
7675                         // Only base will allow this invocation to happen.
7676                         //
7677                         if (get.IsAbstract && this is BaseIndexerAccess){
7678                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
7679                                 return null;
7680                         }
7681
7682                         type = get.ReturnType;
7683                         if (type.IsPointer && !ec.InUnsafe){
7684                                 UnsafeError (loc);
7685                                 return null;
7686                         }
7687                         
7688                         eclass = ExprClass.IndexerAccess;
7689                         return this;
7690                 }
7691
7692                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7693                 {
7694                         ArrayList AllSetters = new ArrayList();
7695                         if (!CommonResolve (ec))
7696                                 return null;
7697
7698                         bool found_any = false, found_any_setters = false;
7699
7700                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
7701                         if (ilist != null) {
7702                                 found_any = true;
7703                                 if (ilist.Properties != null) {
7704                                         foreach (Indexers.Indexer ix in ilist.Properties) {
7705                                                 if (ix.Setter != null)
7706                                                         AllSetters.Add(ix.Setter);
7707                                         }
7708                                 }
7709                         }
7710                         if (AllSetters.Count > 0) {
7711                                 found_any_setters = true;
7712                                 set_arguments = (ArrayList) arguments.Clone ();
7713                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7714                                 set = (MethodInfo) Invocation.OverloadResolve (
7715                                         ec, new MethodGroupExpr (AllSetters, loc),
7716                                         set_arguments, loc);
7717                         }
7718
7719                         if (!found_any) {
7720                                 Report.Error (21, loc,
7721                                               "Type `" + TypeManager.CSharpName (indexer_type) +
7722                                               "' does not have any indexers defined");
7723                                 return null;
7724                         }
7725
7726                         if (!found_any_setters) {
7727                                 Error (154, "indexer can not be used in this context, because " +
7728                                        "it lacks a `set' accessor");
7729                                 return null;
7730                         }
7731
7732                         if (set == null) {
7733                                 Error (1501, "No Overload for method `this' takes `" +
7734                                        arguments.Count + "' arguments");
7735                                 return null;
7736                         }
7737
7738                         //
7739                         // Only base will allow this invocation to happen.
7740                         //
7741                         if (set.IsAbstract && this is BaseIndexerAccess){
7742                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
7743                                 return null;
7744                         }
7745
7746                         //
7747                         // Now look for the actual match in the list of indexers to set our "return" type
7748                         //
7749                         type = TypeManager.void_type;   // default value
7750                         foreach (Indexers.Indexer ix in ilist.Properties){
7751                                 if (ix.Setter == set){
7752                                         type = ix.Type;
7753                                         break;
7754                                 }
7755                         }
7756                         
7757                         eclass = ExprClass.IndexerAccess;
7758                         return this;
7759                 }
7760                 
7761                 public override void Emit (EmitContext ec)
7762                 {
7763                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
7764                 }
7765
7766                 //
7767                 // source is ignored, because we already have a copy of it from the
7768                 // LValue resolution and we have already constructed a pre-cached
7769                 // version of the arguments (ea.set_arguments);
7770                 //
7771                 public void EmitAssign (EmitContext ec, Expression source)
7772                 {
7773                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
7774                 }
7775         }
7776
7777         /// <summary>
7778         ///   The base operator for method names
7779         /// </summary>
7780         public class BaseAccess : Expression {
7781                 string member;
7782                 
7783                 public BaseAccess (string member, Location l)
7784                 {
7785                         this.member = member;
7786                         loc = l;
7787                 }
7788
7789                 public override Expression DoResolve (EmitContext ec)
7790                 {
7791                         Expression c = CommonResolve (ec);
7792
7793                         if (c == null)
7794                                 return null;
7795
7796                         //
7797                         // MethodGroups use this opportunity to flag an error on lacking ()
7798                         //
7799                         if (!(c is MethodGroupExpr))
7800                                 return c.Resolve (ec);
7801                         return c;
7802                 }
7803
7804                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7805                 {
7806                         Expression c = CommonResolve (ec);
7807
7808                         if (c == null)
7809                                 return null;
7810
7811                         //
7812                         // MethodGroups use this opportunity to flag an error on lacking ()
7813                         //
7814                         if (! (c is MethodGroupExpr))
7815                                 return c.DoResolveLValue (ec, right_side);
7816
7817                         return c;
7818                 }
7819
7820                 Expression CommonResolve (EmitContext ec)
7821                 {
7822                         Expression member_lookup;
7823                         Type current_type = ec.ContainerType;
7824                         Type base_type = current_type.BaseType;
7825                         Expression e;
7826
7827                         if (ec.IsStatic){
7828                                 Error (1511, "Keyword base is not allowed in static method");
7829                                 return null;
7830                         }
7831                         
7832                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
7833                                                       AllMemberTypes, AllBindingFlags, loc);
7834                         if (member_lookup == null) {
7835                                 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
7836                                 return null;
7837                         }
7838
7839                         Expression left;
7840                         
7841                         if (ec.IsStatic)
7842                                 left = new TypeExpression (base_type, loc);
7843                         else
7844                                 left = ec.GetThis (loc);
7845                         
7846                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7847
7848                         if (e is PropertyExpr){
7849                                 PropertyExpr pe = (PropertyExpr) e;
7850
7851                                 pe.IsBase = true;
7852                         }
7853
7854                         return e;
7855                 }
7856
7857                 public override void Emit (EmitContext ec)
7858                 {
7859                         throw new Exception ("Should never be called"); 
7860                 }
7861         }
7862
7863         /// <summary>
7864         ///   The base indexer operator
7865         /// </summary>
7866         public class BaseIndexerAccess : IndexerAccess {
7867                 public BaseIndexerAccess (ArrayList args, Location loc)
7868                         : base (null, true, loc)
7869                 {
7870                         arguments = new ArrayList ();
7871                         foreach (Expression tmp in args)
7872                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7873                 }
7874
7875                 protected override bool CommonResolve (EmitContext ec)
7876                 {
7877                         instance_expr = ec.GetThis (loc);
7878
7879                         current_type = ec.ContainerType.BaseType;
7880                         indexer_type = current_type;
7881
7882                         foreach (Argument a in arguments){
7883                                 if (!a.Resolve (ec, loc))
7884                                         return false;
7885                         }
7886
7887                         return true;
7888                 }
7889         }
7890         
7891         /// <summary>
7892         ///   This class exists solely to pass the Type around and to be a dummy
7893         ///   that can be passed to the conversion functions (this is used by
7894         ///   foreach implementation to typecast the object return value from
7895         ///   get_Current into the proper type.  All code has been generated and
7896         ///   we only care about the side effect conversions to be performed
7897         ///
7898         ///   This is also now used as a placeholder where a no-action expression
7899         ///   is needed (the `New' class).
7900         /// </summary>
7901         public class EmptyExpression : Expression {
7902                 public EmptyExpression ()
7903                 {
7904                         type = TypeManager.object_type;
7905                         eclass = ExprClass.Value;
7906                         loc = Location.Null;
7907                 }
7908
7909                 public EmptyExpression (Type t)
7910                 {
7911                         type = t;
7912                         eclass = ExprClass.Value;
7913                         loc = Location.Null;
7914                 }
7915                 
7916                 public override Expression DoResolve (EmitContext ec)
7917                 {
7918                         return this;
7919                 }
7920
7921                 public override void Emit (EmitContext ec)
7922                 {
7923                         // nothing, as we only exist to not do anything.
7924                 }
7925
7926                 //
7927                 // This is just because we might want to reuse this bad boy
7928                 // instead of creating gazillions of EmptyExpressions.
7929                 // (CanImplicitConversion uses it)
7930                 //
7931                 public void SetType (Type t)
7932                 {
7933                         type = t;
7934                 }
7935         }
7936
7937         public class UserCast : Expression {
7938                 MethodBase method;
7939                 Expression source;
7940                 
7941                 public UserCast (MethodInfo method, Expression source, Location l)
7942                 {
7943                         this.method = method;
7944                         this.source = source;
7945                         type = method.ReturnType;
7946                         eclass = ExprClass.Value;
7947                         loc = l;
7948                 }
7949
7950                 public override Expression DoResolve (EmitContext ec)
7951                 {
7952                         //
7953                         // We are born fully resolved
7954                         //
7955                         return this;
7956                 }
7957
7958                 public override void Emit (EmitContext ec)
7959                 {
7960                         ILGenerator ig = ec.ig;
7961
7962                         source.Emit (ec);
7963                         
7964                         if (method is MethodInfo)
7965                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
7966                         else
7967                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7968
7969                 }
7970         }
7971
7972         // <summary>
7973         //   This class is used to "construct" the type during a typecast
7974         //   operation.  Since the Type.GetType class in .NET can parse
7975         //   the type specification, we just use this to construct the type
7976         //   one bit at a time.
7977         // </summary>
7978         public class ComposedCast : TypeExpr {
7979                 Expression left;
7980                 string dim;
7981                 
7982                 public ComposedCast (Expression left, string dim, Location l)
7983                 {
7984                         this.left = left;
7985                         this.dim = dim;
7986                         loc = l;
7987                 }
7988
7989                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
7990                 {
7991                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7992                         if (ltype == null)
7993                                 return null;
7994
7995                         //
7996                         // ltype.Fullname is already fully qualified, so we can skip
7997                         // a lot of probes, and go directly to TypeManager.LookupType
7998                         //
7999                         string cname = ltype.FullName + dim;
8000                         type = TypeManager.LookupTypeDirect (cname);
8001                         if (type == null){
8002                                 //
8003                                 // For arrays of enumerations we are having a problem
8004                                 // with the direct lookup.  Need to investigate.
8005                                 //
8006                                 // For now, fall back to the full lookup in that case.
8007                                 //
8008                                 type = RootContext.LookupType (
8009                                         ec.DeclSpace, cname, false, loc);
8010
8011                                 if (type == null)
8012                                         return null;
8013                         }
8014
8015                         if (!ec.ResolvingTypeTree){
8016                                 //
8017                                 // If the above flag is set, this is being invoked from the ResolveType function.
8018                                 // Upper layers take care of the type validity in this context.
8019                                 //
8020                         if (!ec.InUnsafe && type.IsPointer){
8021                                 UnsafeError (loc);
8022                                 return null;
8023                         }
8024                         }
8025                         
8026                         eclass = ExprClass.Type;
8027                         return this;
8028                 }
8029
8030                 public override string Name {
8031                         get {
8032                                 return left + dim;
8033                         }
8034                 }
8035         }
8036
8037         //
8038         // This class is used to represent the address of an array, used
8039         // only by the Fixed statement, this is like the C "&a [0]" construct.
8040         //
8041         public class ArrayPtr : Expression {
8042                 Expression array;
8043                 
8044                 public ArrayPtr (Expression array, Location l)
8045                 {
8046                         Type array_type = TypeManager.GetElementType (array.Type);
8047
8048                         this.array = array;
8049
8050                         type = TypeManager.GetPointerType (array_type);
8051                         eclass = ExprClass.Value;
8052                         loc = l;
8053                 }
8054
8055                 public override void Emit (EmitContext ec)
8056                 {
8057                         ILGenerator ig = ec.ig;
8058                         
8059                         array.Emit (ec);
8060                         IntLiteral.EmitInt (ig, 0);
8061                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8062                 }
8063
8064                 public override Expression DoResolve (EmitContext ec)
8065                 {
8066                         //
8067                         // We are born fully resolved
8068                         //
8069                         return this;
8070                 }
8071         }
8072
8073         //
8074         // Used by the fixed statement
8075         //
8076         public class StringPtr : Expression {
8077                 LocalBuilder b;
8078                 
8079                 public StringPtr (LocalBuilder b, Location l)
8080                 {
8081                         this.b = b;
8082                         eclass = ExprClass.Value;
8083                         type = TypeManager.char_ptr_type;
8084                         loc = l;
8085                 }
8086
8087                 public override Expression DoResolve (EmitContext ec)
8088                 {
8089                         // This should never be invoked, we are born in fully
8090                         // initialized state.
8091
8092                         return this;
8093                 }
8094
8095                 public override void Emit (EmitContext ec)
8096                 {
8097                         ILGenerator ig = ec.ig;
8098
8099                         ig.Emit (OpCodes.Ldloc, b);
8100                         ig.Emit (OpCodes.Conv_I);
8101                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8102                         ig.Emit (OpCodes.Add);
8103                 }
8104         }
8105         
8106         //
8107         // Implements the `stackalloc' keyword
8108         //
8109         public class StackAlloc : Expression {
8110                 Type otype;
8111                 Expression t;
8112                 Expression count;
8113                 
8114                 public StackAlloc (Expression type, Expression count, Location l)
8115                 {
8116                         t = type;
8117                         this.count = count;
8118                         loc = l;
8119                 }
8120
8121                 public override Expression DoResolve (EmitContext ec)
8122                 {
8123                         count = count.Resolve (ec);
8124                         if (count == null)
8125                                 return null;
8126                         
8127                         if (count.Type != TypeManager.int32_type){
8128                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8129                                 if (count == null)
8130                                         return null;
8131                         }
8132
8133                         if (ec.CurrentBranching.InCatch () ||
8134                             ec.CurrentBranching.InFinally (true)) {
8135                                 Error (255,
8136                                        "stackalloc can not be used in a catch or finally block");
8137                                 return null;
8138                         }
8139
8140                         otype = ec.DeclSpace.ResolveType (t, false, loc);
8141
8142                         if (otype == null)
8143                                 return null;
8144
8145                         if (!TypeManager.VerifyUnManaged (otype, loc))
8146                                 return null;
8147
8148                         type = TypeManager.GetPointerType (otype);
8149                         eclass = ExprClass.Value;
8150
8151                         return this;
8152                 }
8153
8154                 public override void Emit (EmitContext ec)
8155                 {
8156                         int size = GetTypeSize (otype);
8157                         ILGenerator ig = ec.ig;
8158                                 
8159                         if (size == 0)
8160                                 ig.Emit (OpCodes.Sizeof, otype);
8161                         else
8162                                 IntConstant.EmitInt (ig, size);
8163                         count.Emit (ec);
8164                         ig.Emit (OpCodes.Mul);
8165                         ig.Emit (OpCodes.Localloc);
8166                 }
8167         }
8168 }