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