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