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