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