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