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