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