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