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