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