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