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