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