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