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