* Context.cs: Added finalizer to match MS.NET
[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                 };
4001
4002                 public readonly AType ArgType;
4003                 public Expression Expr;
4004                 
4005                 public Argument (Expression expr, AType type)
4006                 {
4007                         this.Expr = expr;
4008                         this.ArgType = type;
4009                 }
4010
4011                 public Type Type {
4012                         get {
4013                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4014                                         return TypeManager.GetReferenceType (Expr.Type);
4015                                 else
4016                                         return Expr.Type;
4017                         }
4018                 }
4019
4020                 public Parameter.Modifier GetParameterModifier ()
4021                 {
4022                         switch (ArgType) {
4023                         case AType.Out:
4024                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4025
4026                         case AType.Ref:
4027                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4028
4029                         default:
4030                                 return Parameter.Modifier.NONE;
4031                         }
4032                 }
4033
4034                 public static string FullDesc (Argument a)
4035                 {
4036                         return (a.ArgType == AType.Ref ? "ref " :
4037                                 (a.ArgType == AType.Out ? "out " : "")) +
4038                                 TypeManager.CSharpName (a.Expr.Type);
4039                 }
4040
4041                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4042                 {
4043                         ConstructedType ctype = Expr as ConstructedType;
4044                         if (ctype != null)
4045                                 Expr = ctype.GetSimpleName (ec);
4046
4047                         // FIXME: csc doesn't report any error if you try to use `ref' or
4048                         //        `out' in a delegate creation expression.
4049                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4050                         if (Expr == null)
4051                                 return false;
4052
4053                         return true;
4054                 }
4055                 
4056                 public bool Resolve (EmitContext ec, Location loc)
4057                 {
4058                         if (ArgType == AType.Ref) {
4059                                 Expr = Expr.Resolve (ec);
4060                                 if (Expr == null)
4061                                         return false;
4062
4063                                 Expr = Expr.ResolveLValue (ec, Expr);
4064                         } else if (ArgType == AType.Out)
4065                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
4066                         else
4067                                 Expr = Expr.Resolve (ec);
4068
4069                         if (Expr == null)
4070                                 return false;
4071
4072                         if (ArgType == AType.Expression)
4073                                 return true;
4074                         else {
4075                                 //
4076                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4077                                 // This is only allowed for `this'
4078                                 //
4079                                 FieldExpr fe = Expr as FieldExpr;
4080                                 if (fe != null && !fe.IsStatic){
4081                                         Expression instance = fe.InstanceExpression;
4082
4083                                         if (instance.GetType () != typeof (This)){
4084                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4085                                                         Report.Error (197, loc,
4086                                                                       "Can not pass a type that derives from MarshalByRefObject with out or ref");
4087                                                         return false;
4088                                                 }
4089                                         }
4090                                 }
4091                         }
4092
4093                         if (Expr.eclass != ExprClass.Variable){
4094                                 //
4095                                 // We just probe to match the CSC output
4096                                 //
4097                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4098                                     Expr.eclass == ExprClass.IndexerAccess){
4099                                         Report.Error (
4100                                                 206, loc,
4101                                                 "A property or indexer can not be passed as an out or ref " +
4102                                                 "parameter");
4103                                 } else {
4104                                         Report.Error (
4105                                                 1510, loc,
4106                                                 "An lvalue is required as an argument to out or ref");
4107                                 }
4108                                 return false;
4109                         }
4110                                 
4111                         return true;
4112                 }
4113
4114                 public void Emit (EmitContext ec)
4115                 {
4116                         //
4117                         // Ref and Out parameters need to have their addresses taken.
4118                         //
4119                         // ParameterReferences might already be references, so we want
4120                         // to pass just the value
4121                         //
4122                         if (ArgType == AType.Ref || ArgType == AType.Out){
4123                                 AddressOp mode = AddressOp.Store;
4124
4125                                 if (ArgType == AType.Ref)
4126                                         mode |= AddressOp.Load;
4127                                 
4128                                 if (Expr is ParameterReference){
4129                                         ParameterReference pr = (ParameterReference) Expr;
4130
4131                                         if (pr.is_ref)
4132                                                 pr.EmitLoad (ec);
4133                                         else {
4134                                                 
4135                                                 pr.AddressOf (ec, mode);
4136                                         }
4137                                 } else {
4138                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
4139                                 }
4140                         } else
4141                                 Expr.Emit (ec);
4142                 }
4143         }
4144
4145         /// <summary>
4146         ///   Invocation of methods or delegates.
4147         /// </summary>
4148         public class Invocation : ExpressionStatement {
4149                 public readonly ArrayList Arguments;
4150
4151                 Expression expr;
4152                 MethodBase method = null;
4153                 bool is_base;
4154                 
4155                 static Hashtable method_parameter_cache;
4156
4157                 static Invocation ()
4158                 {
4159                         method_parameter_cache = new PtrHashtable ();
4160                 }
4161                         
4162                 //
4163                 // arguments is an ArrayList, but we do not want to typecast,
4164                 // as it might be null.
4165                 //
4166                 // FIXME: only allow expr to be a method invocation or a
4167                 // delegate invocation (7.5.5)
4168                 //
4169                 public Invocation (Expression expr, ArrayList arguments, Location l)
4170                 {
4171                         this.expr = expr;
4172                         Arguments = arguments;
4173                         loc = l;
4174                 }
4175
4176                 public Expression Expr {
4177                         get {
4178                                 return expr;
4179                         }
4180                 }
4181
4182                 /// <summary>
4183                 ///   Returns the Parameters (a ParameterData interface) for the
4184                 ///   Method `mb'
4185                 /// </summary>
4186                 public static ParameterData GetParameterData (MethodBase mb)
4187                 {
4188                         object pd = method_parameter_cache [mb];
4189                         object ip;
4190                         
4191                         if (pd != null)
4192                                 return (ParameterData) pd;
4193
4194                         ip = TypeManager.LookupParametersByBuilder (mb);
4195                         if (ip != null){
4196                                 method_parameter_cache [mb] = ip;
4197
4198                                 return (ParameterData) ip;
4199                         } else {
4200                                 ReflectionParameters rp = new ReflectionParameters (mb);
4201                                 method_parameter_cache [mb] = rp;
4202
4203                                 return (ParameterData) rp;
4204                         }
4205                 }
4206
4207                 /// <summary>
4208                 ///   Determines "better conversion" as specified in 7.4.2.3
4209                 ///
4210                 ///    Returns : 1 if a->p is better
4211                 ///              0 if a->q or neither is better 
4212                 /// </summary>
4213                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4214                 {
4215                         Type argument_type = a.Type;
4216                         Expression argument_expr = a.Expr;
4217
4218                         if (argument_type == null)
4219                                 throw new Exception ("Expression of type " + a.Expr +
4220                                                      " does not resolve its type");
4221
4222                         //
4223                         // This is a special case since csc behaves this way.
4224                         //
4225                         if (argument_expr is NullLiteral &&
4226                             p == TypeManager.string_type &&
4227                             q == TypeManager.object_type)
4228                                 return 1;
4229                         else if (argument_expr is NullLiteral &&
4230                                  p == TypeManager.object_type &&
4231                                  q == TypeManager.string_type)
4232                                 return 0;
4233                         
4234                         //
4235                         // csc behaves this way so we emulate it. Basically, if the argument
4236                         // is null and one of the types to compare is 'object' and the other
4237                         // is a reference type, we prefer the other.
4238                         //
4239                         // I can't find this anywhere in the spec but we can interpret this
4240                         // to mean that null can be of any type you wish in such a context
4241                         //
4242                         if (p != null && q != null) {
4243                                 if (argument_expr is NullLiteral &&
4244                                     !p.IsValueType &&
4245                                     q == TypeManager.object_type)
4246                                         return 1;
4247                                 else if (argument_expr is NullLiteral &&
4248                                          !q.IsValueType &&
4249                                          p == TypeManager.object_type)
4250                                         return 0;
4251                         }
4252                                 
4253                         if (p == q)
4254                                 return 0;
4255                         
4256                         if (argument_type == p)
4257                                 return 1;
4258
4259                         if (argument_type == q)
4260                                 return 0;
4261
4262                         //
4263                         // Now probe whether an implicit constant expression conversion
4264                         // can be used.
4265                         //
4266                         // An implicit constant expression conversion permits the following
4267                         // conversions:
4268                         //
4269                         //    * A constant-expression of type `int' can be converted to type
4270                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
4271                         //      of the expression is withing the range of the destination type.
4272                         //
4273                         //    * A constant-expression of type long can be converted to type
4274                         //      ulong, provided the value of the constant expression is not negative
4275                         //
4276                         // FIXME: Note that this assumes that constant folding has
4277                         // taken place.  We dont do constant folding yet.
4278                         //
4279
4280                         if (argument_expr is IntConstant){
4281                                 IntConstant ei = (IntConstant) argument_expr;
4282                                 int value = ei.Value;
4283
4284                                 if (p == TypeManager.sbyte_type){
4285                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
4286                                                 return 1;
4287                                 } else if (p == TypeManager.byte_type){
4288                                         if (q == TypeManager.sbyte_type &&
4289                                             value >= SByte.MinValue && value <= SByte.MaxValue)
4290                                                 return 0;
4291                                         else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
4292                                                 return 1;
4293                                 } else if (p == TypeManager.short_type){
4294                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
4295                                                 return 1;
4296                                 } else if (p == TypeManager.ushort_type){
4297                                         if (q == TypeManager.short_type &&
4298                                             value >= Int16.MinValue && value <= Int16.MaxValue)
4299                                                 return 0;
4300                                         else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
4301                                                 return 1;
4302                                 } else if (p == TypeManager.int32_type){
4303                                         if (value >= Int32.MinValue && value <= Int32.MaxValue)
4304                                                 return 1;
4305                                 } else if (p == TypeManager.uint32_type){
4306                                         //
4307                                         // we can optimize this case: a positive int32
4308                                         // always fits on a uint32
4309                                         //
4310                                         if (value >= 0)
4311                                                 return 1;
4312                                 } else if (p == TypeManager.uint64_type){
4313                                         //
4314                                         // we can optimize this case: a positive int32
4315                                         // always fits on a uint64
4316                                         //
4317
4318                                         //
4319                                         // This special case is needed because csc behaves like this.
4320                                         // int -> uint is better than int -> ulong!
4321                                         //
4322                                         if (q == TypeManager.uint32_type)
4323                                                 return 0;
4324                                         
4325                                         if (q == TypeManager.int64_type)
4326                                                 return 0;
4327                                         else if (value >= 0)
4328                                                 return 1;
4329                                 } else if (p == TypeManager.int64_type){
4330                                         return 1;
4331                                 }
4332                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
4333                                 LongConstant lc = (LongConstant) argument_expr;
4334                                 
4335                                 if (p == TypeManager.uint64_type){
4336                                         if (lc.Value > 0)
4337                                                 return 1;
4338                                 }
4339                         }
4340
4341                         if (q == null) {
4342                                 Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
4343                                 
4344                                 if (tmp != null)
4345                                         return 1;
4346                                 else
4347                                         return 0;
4348                         }
4349
4350                         Expression p_tmp = new EmptyExpression (p);
4351                         Expression q_tmp = new EmptyExpression (q);
4352                         
4353                         if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true &&
4354                             Convert.ImplicitConversionExists (ec, q_tmp, p) == false)
4355                                 return 1;
4356
4357                         if (p == TypeManager.sbyte_type)
4358                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4359                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4360                                         return 1;
4361
4362                         if (p == TypeManager.short_type)
4363                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4364                                     q == TypeManager.uint64_type)
4365                                         return 1;
4366
4367                         if (p == TypeManager.int32_type)
4368                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4369                                         return 1;
4370
4371                         if (p == TypeManager.int64_type)
4372                                 if (q == TypeManager.uint64_type)
4373                                         return 1;
4374
4375                         return 0;
4376                 }
4377                 
4378                 /// <summary>
4379                 ///   Determines "Better function" between candidate
4380                 ///   and the current best match
4381                 /// </summary>
4382                 /// <remarks>
4383                 ///    Returns an integer indicating :
4384                 ///     0 if candidate ain't better
4385                 ///     1 if candidate is better than the current best match
4386                 /// </remarks>
4387                 static int BetterFunction (EmitContext ec, ArrayList args,
4388                                            MethodBase candidate, bool candidate_params,
4389                                            MethodBase best, bool best_params,
4390                                            Location loc)
4391                 {
4392                         ParameterData candidate_pd = GetParameterData (candidate);
4393                         ParameterData best_pd;
4394                         int argument_count;
4395                 
4396                         if (args == null)
4397                                 argument_count = 0;
4398                         else
4399                                 argument_count = args.Count;
4400
4401                         int cand_count = candidate_pd.Count;
4402
4403                         //
4404                         // If there is no best method, than this one
4405                         // is better, however, if we already found a
4406                         // best method, we cant tell. This happens
4407                         // if we have:
4408                         // 
4409                         //      interface IFoo {
4410                         //              void DoIt ();
4411                         //      }
4412                         //      
4413                         //      interface IBar {
4414                         //              void DoIt ();
4415                         //      }
4416                         //      
4417                         //      interface IFooBar : IFoo, IBar {}
4418                         //
4419                         // We cant tell if IFoo.DoIt is better than IBar.DoIt
4420                         //
4421                         // However, we have to consider that
4422                         // Trim (); is better than Trim (params char[] chars);
4423                         //
4424                         if (cand_count == 0 && argument_count == 0)
4425                                 return best == null || best_params ? 1 : 0;
4426
4427                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
4428                                 if (cand_count != argument_count)
4429                                         return 0;
4430
4431                         if (best == null) {
4432                                 int x = 0;
4433
4434                                 if (argument_count == 0 && cand_count == 1 &&
4435                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
4436                                         return 1;
4437                                 
4438                                 for (int j = 0; j < argument_count; ++j) {
4439
4440                                         Argument a = (Argument) args [j];
4441                                         Type t = candidate_pd.ParameterType (j);
4442
4443                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4444                                                 if (candidate_params)
4445                                                         t = TypeManager.GetElementType (t);
4446
4447                                         x = BetterConversion (ec, a, t, null, loc);
4448                                         
4449                                         if (x <= 0)
4450                                                 break;
4451                                 }
4452
4453                                 if (x > 0)
4454                                         return 1;
4455                                 else
4456                                         return 0;
4457                         }
4458
4459                         best_pd = GetParameterData (best);
4460
4461                         int rating1 = 0, rating2 = 0;
4462                         
4463                         for (int j = 0; j < argument_count; ++j) {
4464                                 int x, y;
4465                                 
4466                                 Argument a = (Argument) args [j];
4467
4468                                 Type ct = candidate_pd.ParameterType (j);
4469                                 Type bt = best_pd.ParameterType (j);
4470
4471                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4472                                         if (candidate_params)
4473                                                 ct = TypeManager.GetElementType (ct);
4474
4475                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4476                                         if (best_params)
4477                                                 bt = TypeManager.GetElementType (bt);
4478
4479                                 x = BetterConversion (ec, a, ct, bt, loc);
4480                                 y = BetterConversion (ec, a, bt, ct, loc);
4481
4482                                 if (x < y)
4483                                         return 0;
4484                                 
4485                                 rating1 += x;
4486                                 rating2 += y;
4487                         }
4488
4489                         //
4490                         // If a method (in the normal form) with the
4491                         // same signature as the expanded form of the
4492                         // current best params method already exists,
4493                         // the expanded form is not applicable so we
4494                         // force it to select the candidate
4495                         //
4496                         if (!candidate_params && best_params && cand_count == argument_count)
4497                                 return 1;
4498
4499                         if (rating1 > rating2)
4500                                 return 1;
4501                         else
4502                                 return 0;
4503                 }
4504
4505                 public static string FullMethodDesc (MethodBase mb)
4506                 {
4507                         string ret_type = "";
4508
4509                         if (mb == null)
4510                                 return "";
4511
4512                         if (mb is MethodInfo)
4513                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4514                         
4515                         StringBuilder sb = new StringBuilder (ret_type);
4516                         sb.Append (" ");
4517                         sb.Append (mb.ReflectedType.ToString ());
4518                         sb.Append (".");
4519                         sb.Append (mb.Name);
4520                         
4521                         ParameterData pd = GetParameterData (mb);
4522
4523                         int count = pd.Count;
4524                         sb.Append (" (");
4525                         
4526                         for (int i = count; i > 0; ) {
4527                                 i--;
4528
4529                                 sb.Append (pd.ParameterDesc (count - i - 1));
4530                                 if (i != 0)
4531                                         sb.Append (", ");
4532                         }
4533                         
4534                         sb.Append (")");
4535                         return sb.ToString ();
4536                 }
4537
4538                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4539                 {
4540                         MemberInfo [] miset;
4541                         MethodGroupExpr union;
4542
4543                         if (mg1 == null) {
4544                                 if (mg2 == null)
4545                                         return null;
4546                                 return (MethodGroupExpr) mg2;
4547                         } else {
4548                                 if (mg2 == null)
4549                                         return (MethodGroupExpr) mg1;
4550                         }
4551                         
4552                         MethodGroupExpr left_set = null, right_set = null;
4553                         int length1 = 0, length2 = 0;
4554                         
4555                         left_set = (MethodGroupExpr) mg1;
4556                         length1 = left_set.Methods.Length;
4557                         
4558                         right_set = (MethodGroupExpr) mg2;
4559                         length2 = right_set.Methods.Length;
4560                         
4561                         ArrayList common = new ArrayList ();
4562
4563                         foreach (MethodBase r in right_set.Methods){
4564                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4565                                         common.Add (r);
4566                         }
4567
4568                         miset = new MemberInfo [length1 + length2 - common.Count];
4569                         left_set.Methods.CopyTo (miset, 0);
4570                         
4571                         int k = length1;
4572
4573                         foreach (MethodBase r in right_set.Methods) {
4574                                 if (!common.Contains (r))
4575                                         miset [k++] = r;
4576                         }
4577
4578                         union = new MethodGroupExpr (miset, loc);
4579                         
4580                         return union;
4581                 }
4582
4583                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4584                                                       ArrayList arguments, ref MethodBase candidate)
4585                 {
4586                         if (!me.HasTypeArguments &&
4587                             !InferParamsTypeArguments (ec, arguments, ref candidate))
4588                                 return false;
4589
4590                         return IsParamsMethodApplicable (ec, arguments, candidate);
4591                 }
4592
4593                 /// <summary>
4594                 ///   Determines if the candidate method, if a params method, is applicable
4595                 ///   in its expanded form to the given set of arguments
4596                 /// </summary>
4597                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4598                 {
4599                         int arg_count;
4600                         
4601                         if (arguments == null)
4602                                 arg_count = 0;
4603                         else
4604                                 arg_count = arguments.Count;
4605                         
4606                         ParameterData pd = GetParameterData (candidate);
4607                         
4608                         int pd_count = pd.Count;
4609
4610                         if (pd_count == 0)
4611                                 return false;
4612                         
4613                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
4614                                 return false;
4615                         
4616                         if (pd_count - 1 > arg_count)
4617                                 return false;
4618                         
4619                         if (pd_count == 1 && arg_count == 0)
4620                                 return true;
4621
4622                         //
4623                         // If we have come this far, the case which
4624                         // remains is when the number of parameters is
4625                         // less than or equal to the argument count.
4626                         //
4627                         for (int i = 0; i < pd_count - 1; ++i) {
4628
4629                                 Argument a = (Argument) arguments [i];
4630
4631                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4632                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4633                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4634                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4635
4636                                 if (a_mod == p_mod) {
4637
4638                                         if (a_mod == Parameter.Modifier.NONE)
4639                                                 if (!Convert.ImplicitConversionExists (ec,
4640                                                                                        a.Expr,
4641                                                                                        pd.ParameterType (i)))
4642                                                         return false;
4643                                                                                 
4644                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4645                                                 Type pt = pd.ParameterType (i);
4646
4647                                                 if (!pt.IsByRef)
4648                                                         pt = TypeManager.GetReferenceType (pt);
4649                                                 
4650                                                 if (pt != a.Type)
4651                                                         return false;
4652                                         }
4653                                 } else
4654                                         return false;
4655                                 
4656                         }
4657
4658                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4659
4660                         for (int i = pd_count - 1; i < arg_count; i++) {
4661                                 Argument a = (Argument) arguments [i];
4662                                 
4663                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4664                                         return false;
4665                         }
4666                         
4667                         return true;
4668                 }
4669
4670                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4671                                           ArrayList arguments, ref MethodBase candidate)
4672                 {
4673                         if (!me.HasTypeArguments &&
4674                             !InferTypeArguments (ec, arguments, ref candidate))
4675                                 return false;
4676
4677                         return IsApplicable (ec, arguments, candidate);
4678                 }
4679
4680                 /// <summary>
4681                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4682                 ///   to the given set of arguments
4683                 /// </summary>
4684                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4685                 {
4686                         int arg_count;
4687
4688                         if (arguments == null)
4689                                 arg_count = 0;
4690                         else
4691                                 arg_count = arguments.Count;
4692
4693
4694                         ParameterData pd = GetParameterData (candidate);
4695
4696                         if (arg_count != pd.Count)
4697                                 return false;
4698
4699                         for (int i = arg_count; i > 0; ) {
4700                                 i--;
4701
4702                                 Argument a = (Argument) arguments [i];
4703
4704                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4705                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4706                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4707                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4708
4709
4710                                 if (a_mod == p_mod ||
4711                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4712                                         if (a_mod == Parameter.Modifier.NONE) {
4713                                                 if (!Convert.ImplicitConversionExists (ec,
4714                                                                                        a.Expr,
4715                                                                                        pd.ParameterType (i)))
4716                                                         return false;
4717                                         }
4718                                         
4719                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4720                                                 Type pt = pd.ParameterType (i);
4721
4722                                                 if (!pt.IsByRef)
4723                                                         pt = TypeManager.GetReferenceType (pt);
4724                                                 
4725                                                 if (pt != a.Type)
4726                                                         return false;
4727                                         }
4728                                 } else
4729                                         return false;
4730                         }
4731
4732                         return true;
4733                 }
4734                 
4735                 /// <summary>
4736                 ///   Find the Applicable Function Members (7.4.2.1)
4737                 ///
4738                 ///   me: Method Group expression with the members to select.
4739                 ///       it might contain constructors or methods (or anything
4740                 ///       that maps to a method).
4741                 ///
4742                 ///   Arguments: ArrayList containing resolved Argument objects.
4743                 ///
4744                 ///   loc: The location if we want an error to be reported, or a Null
4745                 ///        location for "probing" purposes.
4746                 ///
4747                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4748                 ///            that is the best match of me on Arguments.
4749                 ///
4750                 /// </summary>
4751                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4752                                                           ArrayList Arguments, bool may_fail,
4753                                                           Location loc)
4754                 {
4755                         MethodBase method = null;
4756                         Type applicable_type = null;
4757                         int argument_count;
4758                         ArrayList candidates = new ArrayList ();
4759
4760                         //
4761                         // Used to keep a map between the candidate
4762                         // and whether it is being considered in its
4763                         // normal or expanded form
4764                         //
4765                         // false is normal form, true is expanded form
4766                         //
4767                         Hashtable candidate_to_form = new PtrHashtable ();
4768
4769
4770                         //
4771                         // First we construct the set of applicable methods
4772                         //
4773                         // We start at the top of the type hierarchy and
4774                         // go down to find applicable methods
4775                         //
4776                         applicable_type = me.DeclaringType;
4777                         
4778                         if (me.Name == "Invoke" && TypeManager.IsDelegateType (applicable_type)) {
4779                                 Error_InvokeOnDelegate (loc);
4780                                 return null;
4781                         }
4782
4783                         bool found_applicable = false;
4784
4785                         MethodBase[] methods = me.Methods;
4786
4787                         for (int i = 0; i < methods.Length; i++) {
4788                                 Type decl_type = methods [i].DeclaringType;
4789
4790                                 //
4791                                 // If we have already found an applicable method
4792                                 // we eliminate all base types (Section 14.5.5.1)
4793                                 //
4794                                 if (decl_type != applicable_type &&
4795                                     (applicable_type.IsSubclassOf (decl_type) ||
4796                                      TypeManager.ImplementsInterface (applicable_type, decl_type)) &&
4797                                     found_applicable)
4798                                         continue;
4799
4800                                 // Check if candidate is applicable (section 14.4.2.1)
4801                                 if (IsApplicable (ec, me, Arguments, ref methods [i])) {
4802                                         // Candidate is applicable in normal form
4803                                         MethodBase candidate = methods [i];
4804                                         candidates.Add (candidate);
4805                                         applicable_type = candidate.DeclaringType;
4806                                         found_applicable = true;
4807                                         candidate_to_form [candidate] = false;
4808                                 } else if (IsParamsMethodApplicable (ec, me, Arguments, ref methods [i])) {
4809                                         // Candidate is applicable in expanded form
4810                                         MethodBase candidate = methods [i];
4811                                         candidates.Add (candidate);
4812                                         applicable_type = candidate.DeclaringType;
4813                                         found_applicable = true; 
4814                                         candidate_to_form [candidate] = true;
4815                                 }
4816                         }
4817
4818                         if (Arguments == null)
4819                                 argument_count = 0;
4820                         else
4821                                 argument_count = Arguments.Count;
4822
4823                         //
4824                         // Now we actually find the best method
4825                         //
4826                         int candidate_top = candidates.Count;
4827                         for (int ix = 0; ix < candidate_top; ix++){
4828                                 MethodBase candidate = (MethodBase) candidates [ix];
4829                                 
4830                                 bool cand_params = (bool) candidate_to_form [candidate];
4831                                 bool method_params = false;
4832                                 
4833                                 if (method != null)
4834                                         method_params = (bool) candidate_to_form [method];
4835                                 
4836                                 int x = BetterFunction (ec, Arguments,
4837                                                         candidate, cand_params,
4838                                                         method, method_params,
4839                                                         loc);
4840                                 if (x == 0)
4841                                         continue;
4842                                 
4843                                 method = candidate;
4844                         }
4845
4846                         if (method == null) {
4847                                 int errors = Report.Errors;
4848
4849                                 //
4850                                 // Okay so we have failed to find anything so we
4851                                 // return by providing info about the closest match
4852                                 //
4853                                 for (int i = 0; i < methods.Length; ++i) {
4854
4855                                         MethodBase c = methods [i];
4856                                         if (c == null)
4857                                                 continue;
4858
4859                                         ParameterData pd = GetParameterData (c);
4860                                         if (pd.Count != argument_count)
4861                                                 continue;
4862
4863                                         if (!InferTypeArguments (ec, Arguments, ref c))
4864                                                 continue;
4865
4866                                         VerifyArgumentsCompat (ec, Arguments, argument_count,
4867                                                                c, false, null, loc);
4868                                         break;
4869                                 }
4870
4871                                 if (Report.Errors > errors)
4872                                         return null;
4873
4874                                 string report_name = me.Name;
4875                                 if (report_name == ".ctor")
4876                                         report_name = me.DeclaringType.ToString ();
4877                                         
4878                                 for (int i = 0; i < methods.Length; ++i) {
4879
4880                                         MethodBase c = methods [i];
4881                                         if (c == null)
4882                                                 continue;
4883
4884                                         ParameterData pd = GetParameterData (c);
4885                                         if (pd.Count != argument_count)
4886                                                 continue;
4887
4888                                         if (InferTypeArguments (ec, Arguments, ref c))
4889                                                 continue;
4890
4891                                         Report.Error (411, loc, "The type arguments for " +
4892                                                       "method `{0}' cannot be infered from " +
4893                                                       "the usage. Try specifying the type " +
4894                                                       "arguments explicitly.", report_name);
4895                                         break;
4896                                 }
4897
4898                                 if (!may_fail && (errors == Report.Errors))
4899                                         Error_WrongNumArguments (loc, report_name,
4900                                                                  argument_count);
4901                                 
4902                                 return null;
4903                         }
4904
4905                         //
4906                         // Now check that there are no ambiguities i.e the selected method
4907                         // should be better than all the others
4908                         //
4909                         bool best_params = (bool) candidate_to_form [method];
4910
4911                         for (int ix = 0; ix < candidate_top; ix++){
4912                                 MethodBase candidate = (MethodBase) candidates [ix];
4913
4914                                 if (candidate == method)
4915                                         continue;
4916                                                
4917                                 //
4918                                 // If a normal method is applicable in
4919                                 // the sense that it has the same
4920                                 // number of arguments, then the
4921                                 // expanded params method is never
4922                                 // applicable so we debar the params
4923                                 // method.
4924                                 //
4925                                 // if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
4926 //                                      IsApplicable (ec, Arguments, method)))
4927 //                                         continue;
4928                                 
4929                                 bool cand_params = (bool) candidate_to_form [candidate];
4930                                 int x = BetterFunction (ec, Arguments,
4931                                                         method, best_params,
4932                                                         candidate, cand_params,
4933                                                         loc);
4934
4935                                 if (x != 1) {
4936                                         Report.Error (
4937                                                 121, loc,
4938                                                 "Ambiguous call when selecting function due to implicit casts");
4939                                         return null;
4940                                 }
4941                         }
4942
4943                         //
4944                         // And now check if the arguments are all
4945                         // compatible, perform conversions if
4946                         // necessary etc. and return if everything is
4947                         // all right
4948                         //
4949                         if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4950                                                     best_params, null, loc))
4951                                 return null;
4952
4953                         return method;
4954                 }
4955
4956                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4957                 {
4958                         Report.Error (1501, loc,
4959                                       "No overload for method `" + name + "' takes `" +
4960                                       arg_count + "' arguments");
4961                 }
4962
4963                 static void Error_InvokeOnDelegate (Location loc)
4964                 {
4965                         Report.Error (1533, loc,
4966                                       "Invoke cannot be called directly on a delegate");
4967                 }
4968                         
4969                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4970                                                     Type delegate_type, string arg_sig, string par_desc)
4971                 {
4972                         if (delegate_type == null) 
4973                                 Report.Error (1502, loc,
4974                                               "The best overloaded match for method '" +
4975                                               FullMethodDesc (method) +
4976                                               "' has some invalid arguments");
4977                         else
4978                                 Report.Error (1594, loc,
4979                                               "Delegate '" + delegate_type.ToString () +
4980                                               "' has some invalid arguments.");
4981                         Report.Error (1503, loc,
4982                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4983                                                      idx, arg_sig, par_desc));
4984                 }
4985                 
4986                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4987                                                           int argument_count,
4988                                                           MethodBase method, 
4989                                                           bool chose_params_expanded,
4990                                                           Type delegate_type,
4991                                                           Location loc)
4992                 {
4993                         ParameterData pd = GetParameterData (method);
4994                         int pd_count = pd.Count;
4995                         
4996                         for (int j = 0; j < argument_count; j++) {
4997                                 Argument a = (Argument) Arguments [j];
4998                                 Expression a_expr = a.Expr;
4999                                 Type parameter_type = pd.ParameterType (j);
5000                                 Parameter.Modifier pm = pd.ParameterModifier (j);
5001                                 
5002                                 if (pm == Parameter.Modifier.PARAMS){
5003                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
5004                                                 if (!Location.IsNull (loc))
5005                                                         Error_InvalidArguments (
5006                                                                 loc, j, method, delegate_type,
5007                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5008                                                 return false;
5009                                         }
5010
5011                                         if (chose_params_expanded)
5012                                                 parameter_type = TypeManager.GetElementType (parameter_type);
5013                                 } else {
5014                                         //
5015                                         // Check modifiers
5016                                         //
5017                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
5018                                                 if (!Location.IsNull (loc))
5019                                                         Error_InvalidArguments (
5020                                                                 loc, j, method, delegate_type,
5021                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5022                                                 return false;
5023                                         }
5024                                 }
5025
5026                                 //
5027                                 // Check Type
5028                                 //
5029                                 if (a.Type != parameter_type){
5030                                         Expression conv;
5031                                         
5032                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5033
5034                                         if (conv == null) {
5035                                                 if (!Location.IsNull (loc)) 
5036                                                         Error_InvalidArguments (
5037                                                                 loc, j, method, delegate_type,
5038                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5039                                                 return false;
5040                                         }
5041                                         
5042                                         //
5043                                         // Update the argument with the implicit conversion
5044                                         //
5045                                         if (a_expr != conv)
5046                                                 a.Expr = conv;
5047                                 }
5048
5049                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
5050                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
5051                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5052                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
5053                                 
5054                                 if (a_mod != p_mod &&
5055                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5056                                         if (!Location.IsNull (loc)) {
5057                                                 Report.Error (1502, loc,
5058                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
5059                                                        "' has some invalid arguments");
5060                                                 Report.Error (1503, loc,
5061                                                        "Argument " + (j+1) +
5062                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
5063                                                        + "' to '" + pd.ParameterDesc (j) + "'");
5064                                         }
5065                                         
5066                                         return false;
5067                                 }
5068                         }
5069
5070                         return true;
5071                 }
5072
5073                 static bool InferType (Type pt, Type at, ref Type[] infered)
5074                 {
5075                         if (pt.IsGenericParameter) {
5076                                 int pos = pt.GenericParameterPosition;
5077
5078                                 if (infered [pos] == null) {
5079                                         Type check = at;
5080                                         while (check.IsArray)
5081                                                 check = check.GetElementType ();
5082
5083                                         if (pt.Equals (check))
5084                                                 return false;
5085
5086                                         infered [pos] = at;
5087                                         return true;
5088                                 }
5089
5090                                 if (infered [pos] != at)
5091                                         return false;
5092
5093                                 return true;
5094                         }
5095
5096                         if (!pt.ContainsGenericParameters)
5097                                 return true;
5098
5099                         if (at.IsArray) {
5100                                 if (!pt.IsArray ||
5101                                     (at.GetArrayRank () != pt.GetArrayRank ()))
5102                                         return false;
5103
5104                                 return InferType (pt.GetElementType (), at.GetElementType (),
5105                                                   ref infered);
5106                         }
5107
5108                         if (pt.IsArray) {
5109                                 if (!at.IsArray ||
5110                                     (pt.GetArrayRank () != at.GetArrayRank ()))
5111                                         return false;
5112
5113                                 return InferType (pt.GetElementType (), at.GetElementType (),
5114                                                   ref infered);
5115                         }
5116
5117                         if (!at.IsGenericInstance)
5118                                 return false;
5119
5120                         Type[] at_args = at.GetGenericArguments ();
5121                         Type[] pt_args = pt.GetGenericArguments ();
5122
5123                         if (at_args.Length != pt_args.Length)
5124                                 return false;
5125
5126                         Type[] infered_types = new Type [at_args.Length];
5127
5128                         for (int i = 0; i < at_args.Length; i++)
5129                                 if (!InferType (pt_args [i], at_args [i], ref infered_types))
5130                                         return false;
5131
5132                         for (int i = 0; i < infered_types.Length; i++)
5133                                 if (infered_types [i] == null)
5134                                         return false;
5135
5136                         for (int i = 0; i < infered_types.Length; i++) {
5137                                 if (infered [i] == null) {
5138                                         infered [i] = infered_types [i];
5139                                         continue;
5140                                 }
5141
5142                                 if (infered [i] != infered_types [i])
5143                                         return false;
5144                         }
5145
5146                         return true;
5147                 }
5148
5149                 static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
5150                                                       ref MethodBase method)
5151                 {
5152                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
5153                                 return true;
5154
5155                         int arg_count;
5156                         
5157                         if (arguments == null)
5158                                 arg_count = 0;
5159                         else
5160                                 arg_count = arguments.Count;
5161                         
5162                         ParameterData pd = GetParameterData (method);
5163
5164                         int pd_count = pd.Count;
5165
5166                         if (pd_count == 0)
5167                                 return false;
5168                         
5169                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
5170                                 return false;
5171                         
5172                         if (pd_count - 1 > arg_count)
5173                                 return false;
5174                         
5175                         if (pd_count == 1 && arg_count == 0)
5176                                 return true;
5177
5178                         Type[] method_args = method.GetGenericArguments ();
5179                         Type[] infered_types = new Type [method_args.Length];
5180
5181                         //
5182                         // If we have come this far, the case which
5183                         // remains is when the number of parameters is
5184                         // less than or equal to the argument count.
5185                         //
5186                         for (int i = 0; i < pd_count - 1; ++i) {
5187                                 Argument a = (Argument) arguments [i];
5188
5189                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5190                                         continue;
5191
5192                                 Type pt = pd.ParameterType (i);
5193                                 Type at = a.Type;
5194
5195                                 if (!InferType (pt, at, ref infered_types))
5196                                         return false;
5197                         }
5198
5199                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
5200
5201                         for (int i = pd_count - 1; i < arg_count; i++) {
5202                                 Argument a = (Argument) arguments [i];
5203
5204                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5205                                         continue;
5206
5207                                 if (!InferType (element_type, a.Type, ref infered_types))
5208                                         return false;
5209                         }
5210
5211                         for (int i = 0; i < infered_types.Length; i++)
5212                                 if (infered_types [i] == null)
5213                                         return false;
5214
5215                         method = method.BindGenericParameters (infered_types);
5216                         return true;
5217                 }
5218
5219                 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types,
5220                                                        ref Type[] infered_types)
5221                 {
5222                         for (int i = 0; i < arg_types.Length; i++) {
5223                                 if (arg_types [i] == null)
5224                                         continue;
5225
5226                                 if (!InferType (param_types [i], arg_types [i],
5227                                                 ref infered_types))
5228                                         return false;
5229                         }
5230
5231                         for (int i = 0; i < infered_types.Length; i++)
5232                                 if (infered_types [i] == null)
5233                                         return false;
5234
5235                         return true;
5236                 }
5237
5238                 static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
5239                                                 ref MethodBase method)
5240                 {
5241                         if (!TypeManager.IsGenericMethod (method))
5242                                 return true;
5243
5244                         int arg_count;
5245                         if (arguments != null)
5246                                 arg_count = arguments.Count;
5247                         else
5248                                 arg_count = 0;
5249
5250                         ParameterData pd = GetParameterData (method);
5251                         if (arg_count != pd.Count)
5252                                 return false;
5253
5254                         Type[] method_args = method.GetGenericArguments ();
5255                         Type[] infered_types = new Type [method_args.Length];
5256
5257                         Type[] param_types = new Type [pd.Count];
5258                         Type[] arg_types = new Type [pd.Count];
5259
5260                         for (int i = 0; i < arg_count; i++) {
5261                                 param_types [i] = pd.ParameterType (i);
5262
5263                                 Argument a = (Argument) arguments [i];
5264                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5265                                         continue;
5266
5267                                 arg_types [i] = a.Type;
5268                         }
5269
5270                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5271                                 return false;
5272
5273                         method = method.BindGenericParameters (infered_types);
5274                         return true;
5275                 }
5276
5277                 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
5278                                                        ref MethodBase method)
5279                 {
5280                         if (!TypeManager.IsGenericMethod (method))
5281                                 return true;
5282
5283                         ParameterData pd = GetParameterData (method);
5284                         if (apd.Count != pd.Count)
5285                                 return false;
5286
5287                         Type[] method_args = method.GetGenericArguments ();
5288                         Type[] infered_types = new Type [method_args.Length];
5289
5290                         Type[] param_types = new Type [pd.Count];
5291                         Type[] arg_types = new Type [pd.Count];
5292
5293                         for (int i = 0; i < apd.Count; i++) {
5294                                 param_types [i] = pd.ParameterType (i);
5295                                 arg_types [i] = apd.ParameterType (i);
5296                         }
5297
5298                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5299                                 return false;
5300
5301                         method = method.BindGenericParameters (infered_types);
5302                         return true;
5303                 }
5304
5305                 public override Expression DoResolve (EmitContext ec)
5306                 {
5307                         //
5308                         // First, resolve the expression that is used to
5309                         // trigger the invocation
5310                         //
5311                         if (expr is BaseAccess)
5312                                 is_base = true;
5313
5314                         if (expr is ConstructedType)
5315                                 expr = ((ConstructedType) expr).GetSimpleName (ec);
5316
5317                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5318                         if (expr == null)
5319                                 return null;
5320
5321                         if (!(expr is MethodGroupExpr)) {
5322                                 Type expr_type = expr.Type;
5323
5324                                 if (expr_type != null){
5325                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5326                                         if (IsDelegate)
5327                                                 return (new DelegateInvocation (
5328                                                         this.expr, Arguments, loc)).Resolve (ec);
5329                                 }
5330                         }
5331
5332                         if (!(expr is MethodGroupExpr)){
5333                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
5334                                 return null;
5335                         }
5336
5337                         //
5338                         // Next, evaluate all the expressions in the argument list
5339                         //
5340                         if (Arguments != null){
5341                                 foreach (Argument a in Arguments){
5342                                         if (!a.Resolve (ec, loc))
5343                                                 return null;
5344                                 }
5345                         }
5346
5347                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5348                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5349
5350                         if (method == null)
5351                                 return null;
5352
5353                         MethodInfo mi = method as MethodInfo;
5354                         if (mi != null) {
5355                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5356                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5357                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5358                                         return null;
5359                                 }
5360
5361                                 Expression iexpr = mg.InstanceExpression;
5362                                 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5363                                         if (mg.IdenticalTypeName)
5364                                                 mg.InstanceExpression = null;
5365                                         else {
5366                                                 MemberAccess.error176 (loc, mi.Name);
5367                                                 return null;
5368                                         }
5369                                 }
5370                         }
5371
5372                         if (type.IsPointer){
5373                                 if (!ec.InUnsafe){
5374                                         UnsafeError (loc);
5375                                         return null;
5376                                 }
5377                         }
5378                         
5379                         //
5380                         // Only base will allow this invocation to happen.
5381                         //
5382                         if (is_base && method.IsAbstract){
5383                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5384                                               FullMethodDesc (method));
5385                                 return null;
5386                         }
5387
5388                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
5389                                 if (TypeManager.IsSpecialMethod (method))
5390                                         Report.Error (571, loc, method.Name + ": can not call operator or accessor");
5391                         }
5392                         
5393                         eclass = ExprClass.Value;
5394                         return this;
5395                 }
5396
5397                 // <summary>
5398                 //   Emits the list of arguments as an array
5399                 // </summary>
5400                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5401                 {
5402                         ILGenerator ig = ec.ig;
5403                         int count = arguments.Count - idx;
5404                         Argument a = (Argument) arguments [idx];
5405                         Type t = a.Expr.Type;
5406
5407                         IntConstant.EmitInt (ig, count);
5408                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5409
5410                         int top = arguments.Count;
5411                         for (int j = idx; j < top; j++){
5412                                 a = (Argument) arguments [j];
5413                                 
5414                                 ig.Emit (OpCodes.Dup);
5415                                 IntConstant.EmitInt (ig, j - idx);
5416
5417                                 bool is_stobj, has_type_arg;
5418                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5419                                 if (is_stobj)
5420                                         ig.Emit (OpCodes.Ldelema, t);
5421
5422                                 a.Emit (ec);
5423
5424                                 if (has_type_arg)
5425                                         ig.Emit (op, t);
5426                                 else
5427                                         ig.Emit (op);
5428                         }
5429                 }
5430                 
5431                 /// <summary>
5432                 ///   Emits a list of resolved Arguments that are in the arguments
5433                 ///   ArrayList.
5434                 /// 
5435                 ///   The MethodBase argument might be null if the
5436                 ///   emission of the arguments is known not to contain
5437                 ///   a `params' field (for example in constructors or other routines
5438                 ///   that keep their arguments in this structure)
5439                 /// </summary>
5440                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
5441                 {
5442                         ParameterData pd;
5443                         if (mb != null)
5444                                 pd = GetParameterData (mb);
5445                         else
5446                                 pd = null;
5447
5448                         //
5449                         // If we are calling a params method with no arguments, special case it
5450                         //
5451                         if (arguments == null){
5452                                 if (pd != null && pd.Count > 0 &&
5453                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5454                                         ILGenerator ig = ec.ig;
5455
5456                                         IntConstant.EmitInt (ig, 0);
5457                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5458                                 }
5459
5460                                 return;
5461                         }
5462
5463                         int top = arguments.Count;
5464
5465                         for (int i = 0; i < top; i++){
5466                                 Argument a = (Argument) arguments [i];
5467
5468                                 if (pd != null){
5469                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5470                                                 //
5471                                                 // Special case if we are passing the same data as the
5472                                                 // params argument, do not put it in an array.
5473                                                 //
5474                                                 if (pd.ParameterType (i) == a.Type)
5475                                                         a.Emit (ec);
5476                                                 else
5477                                                         EmitParams (ec, i, arguments);
5478                                                 return;
5479                                         }
5480                                 }
5481                                             
5482                                 a.Emit (ec);
5483                         }
5484
5485                         if (pd != null && pd.Count > top &&
5486                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5487                                 ILGenerator ig = ec.ig;
5488
5489                                 IntConstant.EmitInt (ig, 0);
5490                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5491                         }
5492                 }
5493
5494                 /// <summary>
5495                 /// This checks the ConditionalAttribute on the method 
5496                 /// </summary>
5497                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5498                 {
5499                         if (method.IsConstructor)
5500                                 return false;
5501
5502                         IMethodData md = TypeManager.GetMethod (method);
5503                         if (md != null)
5504                                 return md.IsExcluded (ec);
5505
5506                         // For some methods (generated by delegate class) GetMethod returns null
5507                         // because they are not included in builder_to_method table
5508                         if (method.DeclaringType is TypeBuilder)
5509                                 return false;
5510
5511                         return AttributeTester.IsConditionalMethodExcluded (method);
5512                 }
5513
5514                 /// <remarks>
5515                 ///   is_base tells whether we want to force the use of the `call'
5516                 ///   opcode instead of using callvirt.  Call is required to call
5517                 ///   a specific method, while callvirt will always use the most
5518                 ///   recent method in the vtable.
5519                 ///
5520                 ///   is_static tells whether this is an invocation on a static method
5521                 ///
5522                 ///   instance_expr is an expression that represents the instance
5523                 ///   it must be non-null if is_static is false.
5524                 ///
5525                 ///   method is the method to invoke.
5526                 ///
5527                 ///   Arguments is the list of arguments to pass to the method or constructor.
5528                 /// </remarks>
5529                 public static void EmitCall (EmitContext ec, bool is_base,
5530                                              bool is_static, Expression instance_expr,
5531                                              MethodBase method, ArrayList Arguments, Location loc)
5532                 {
5533                         ILGenerator ig = ec.ig;
5534                         bool struct_call = false;
5535                         bool this_call = false;
5536
5537                         Type decl_type = method.DeclaringType;
5538
5539                         if (!RootContext.StdLib) {
5540                                 // Replace any calls to the system's System.Array type with calls to
5541                                 // the newly created one.
5542                                 if (method == TypeManager.system_int_array_get_length)
5543                                         method = TypeManager.int_array_get_length;
5544                                 else if (method == TypeManager.system_int_array_get_rank)
5545                                         method = TypeManager.int_array_get_rank;
5546                                 else if (method == TypeManager.system_object_array_clone)
5547                                         method = TypeManager.object_array_clone;
5548                                 else if (method == TypeManager.system_int_array_get_length_int)
5549                                         method = TypeManager.int_array_get_length_int;
5550                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5551                                         method = TypeManager.int_array_get_lower_bound_int;
5552                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5553                                         method = TypeManager.int_array_get_upper_bound_int;
5554                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5555                                         method = TypeManager.void_array_copyto_array_int;
5556                         }
5557
5558                         //
5559                         // This checks ObsoleteAttribute on the method and on the declaring type
5560                         //
5561                         ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5562                         if (oa != null)
5563                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5564
5565                         oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5566                         if (oa != null) {
5567                                 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5568                         }
5569
5570
5571                         oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5572                         if (oa != null) {
5573                                 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5574                         }
5575
5576                         if (IsMethodExcluded (method, ec))
5577                                 return;
5578                         
5579                         if (!is_static){
5580                                 if (TypeManager.IsValueType (decl_type))
5581                                         struct_call = true;
5582                                 //
5583                                 // If this is ourselves, push "this"
5584                                 //
5585                                 if (instance_expr == null){
5586                                         this_call = true;
5587                                         ig.Emit (OpCodes.Ldarg_0);
5588                                 } else {
5589                                         Type itype = instance_expr.Type;
5590
5591                                         //
5592                                         // Push the instance expression
5593                                         //
5594                                         if (TypeManager.IsValueType (itype)){
5595                                                 //
5596                                                 // Special case: calls to a function declared in a 
5597                                                 // reference-type with a value-type argument need
5598                                                 // to have their value boxed.  
5599                                                 if (decl_type.IsValueType || itype.IsGenericParameter){
5600                                                         //
5601                                                         // If the expression implements IMemoryLocation, then
5602                                                         // we can optimize and use AddressOf on the
5603                                                         // return.
5604                                                         //
5605                                                         // If not we have to use some temporary storage for
5606                                                         // it.
5607                                                         if (instance_expr is IMemoryLocation){
5608                                                                 ((IMemoryLocation)instance_expr).
5609                                                                         AddressOf (ec, AddressOp.LoadStore);
5610                                                         }
5611                                                         else {
5612                                                                 instance_expr.Emit (ec);
5613                                                                 LocalBuilder temp = ig.DeclareLocal (itype);
5614                                                                 ig.Emit (OpCodes.Stloc, temp);
5615                                                                 ig.Emit (OpCodes.Ldloca, temp);
5616                                                         }
5617                                                         if (itype.IsGenericParameter)
5618                                                                 ig.Emit (OpCodes.Constrained, itype);
5619                                                         else
5620                                                                 struct_call = true;
5621                                                 } else {
5622                                                         instance_expr.Emit (ec);
5623                                                         ig.Emit (OpCodes.Box, itype);
5624                                                 } 
5625                                         } else
5626                                                 instance_expr.Emit (ec);
5627                                 }
5628                         }
5629
5630                         EmitArguments (ec, method, Arguments);
5631                         //
5632                         // If you have:
5633                         // this.DoFoo ();
5634                         // and DoFoo is not virtual, you can omit the callvirt,
5635                         // because you don't need the null checking behavior.
5636                         //
5637                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)){
5638                                 if (method is MethodInfo) {
5639                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
5640                                 } else
5641                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5642                         } else {
5643                                 if (method is MethodInfo)
5644                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
5645                                 else
5646                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
5647                         }
5648                 }
5649                 
5650                 public override void Emit (EmitContext ec)
5651                 {
5652                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5653
5654                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5655                 }
5656                 
5657                 public override void EmitStatement (EmitContext ec)
5658                 {
5659                         Emit (ec);
5660
5661                         // 
5662                         // Pop the return value if there is one
5663                         //
5664                         if (method is MethodInfo){
5665                                 Type ret = ((MethodInfo)method).ReturnType;
5666                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5667                                         ec.ig.Emit (OpCodes.Pop);
5668                         }
5669                 }
5670         }
5671
5672         public class InvocationOrCast : ExpressionStatement
5673         {
5674                 Expression expr;
5675                 Expression argument;
5676
5677                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5678                 {
5679                         this.expr = expr;
5680                         this.argument = argument;
5681                         this.loc = loc;
5682                 }
5683
5684                 public override Expression DoResolve (EmitContext ec)
5685                 {
5686                         //
5687                         // First try to resolve it as a cast.
5688                         //
5689                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5690                         if (type != null) {
5691                                 Cast cast = new Cast (new TypeExpression (type, loc), argument, loc);
5692                                 return cast.Resolve (ec);
5693                         }
5694
5695                         //
5696                         // This can either be a type or a delegate invocation.
5697                         // Let's just resolve it and see what we'll get.
5698                         //
5699                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5700                         if (expr == null)
5701                                 return null;
5702
5703                         //
5704                         // Ok, so it's a Cast.
5705                         //
5706                         if (expr.eclass == ExprClass.Type) {
5707                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5708                                 return cast.Resolve (ec);
5709                         }
5710
5711                         //
5712                         // It's a delegate invocation.
5713                         //
5714                         if (!TypeManager.IsDelegateType (expr.Type)) {
5715                                 Error (149, "Method name expected");
5716                                 return null;
5717                         }
5718
5719                         ArrayList args = new ArrayList ();
5720                         args.Add (new Argument (argument, Argument.AType.Expression));
5721                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5722                         return invocation.Resolve (ec);
5723                 }
5724
5725                 void error201 ()
5726                 {
5727                         Error (201, "Only assignment, call, increment, decrement and new object " +
5728                                "expressions can be used as a statement");
5729                 }
5730
5731                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5732                 {
5733                         //
5734                         // First try to resolve it as a cast.
5735                         //
5736                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5737                         if (type != null) {
5738                                 error201 ();
5739                                 return null;
5740                         }
5741
5742                         //
5743                         // This can either be a type or a delegate invocation.
5744                         // Let's just resolve it and see what we'll get.
5745                         //
5746                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5747                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5748                                 error201 ();
5749                                 return null;
5750                         }
5751
5752                         //
5753                         // It's a delegate invocation.
5754                         //
5755                         if (!TypeManager.IsDelegateType (expr.Type)) {
5756                                 Error (149, "Method name expected");
5757                                 return null;
5758                         }
5759
5760                         ArrayList args = new ArrayList ();
5761                         args.Add (new Argument (argument, Argument.AType.Expression));
5762                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5763                         return invocation.ResolveStatement (ec);
5764                 }
5765
5766                 public override void Emit (EmitContext ec)
5767                 {
5768                         throw new Exception ("Cannot happen");
5769                 }
5770
5771                 public override void EmitStatement (EmitContext ec)
5772                 {
5773                         throw new Exception ("Cannot happen");
5774                 }
5775         }
5776
5777         //
5778         // This class is used to "disable" the code generation for the
5779         // temporary variable when initializing value types.
5780         //
5781         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5782                 public void AddressOf (EmitContext ec, AddressOp Mode)
5783                 {
5784                         // nothing
5785                 }
5786         }
5787         
5788         /// <summary>
5789         ///    Implements the new expression 
5790         /// </summary>
5791         public class New : ExpressionStatement, IMemoryLocation {
5792                 public readonly ArrayList Arguments;
5793
5794                 //
5795                 // During bootstrap, it contains the RequestedType,
5796                 // but if `type' is not null, it *might* contain a NewDelegate
5797                 // (because of field multi-initialization)
5798                 //
5799                 public Expression RequestedType;
5800
5801                 MethodBase method = null;
5802
5803                 //
5804                 // If set, the new expression is for a value_target, and
5805                 // we will not leave anything on the stack.
5806                 //
5807                 Expression value_target;
5808                 bool value_target_set = false;
5809                 bool is_type_parameter = false;
5810                 
5811                 public New (Expression requested_type, ArrayList arguments, Location l)
5812                 {
5813                         RequestedType = requested_type;
5814                         Arguments = arguments;
5815                         loc = l;
5816                 }
5817
5818                 public bool SetValueTypeVariable (Expression value)
5819                 {
5820                         value_target = value;
5821                         value_target_set = true;
5822                         if (!(value_target is IMemoryLocation)){
5823                                 Error_UnexpectedKind ("variable");
5824                                 return false;
5825                         }
5826                         return true;
5827                 }
5828
5829                 //
5830                 // This function is used to disable the following code sequence for
5831                 // value type initialization:
5832                 //
5833                 // AddressOf (temporary)
5834                 // Construct/Init
5835                 // LoadTemporary
5836                 //
5837                 // Instead the provide will have provided us with the address on the
5838                 // stack to store the results.
5839                 //
5840                 static Expression MyEmptyExpression;
5841                 
5842                 public void DisableTemporaryValueType ()
5843                 {
5844                         if (MyEmptyExpression == null)
5845                                 MyEmptyExpression = new EmptyAddressOf ();
5846
5847                         //
5848                         // To enable this, look into:
5849                         // test-34 and test-89 and self bootstrapping.
5850                         //
5851                         // For instance, we can avoid a copy by using `newobj'
5852                         // instead of Call + Push-temp on value types.
5853 //                      value_target = MyEmptyExpression;
5854                 }
5855
5856                 public override Expression DoResolve (EmitContext ec)
5857                 {
5858                         //
5859                         // The New DoResolve might be called twice when initializing field
5860                         // expressions (see EmitFieldInitializers, the call to
5861                         // GetInitializerExpression will perform a resolve on the expression,
5862                         // and later the assign will trigger another resolution
5863                         //
5864                         // This leads to bugs (#37014)
5865                         //
5866                         if (type != null){
5867                                 if (RequestedType is NewDelegate)
5868                                         return RequestedType;
5869                                 return this;
5870                         }
5871                         
5872                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5873                         
5874                         if (type == null)
5875                                 return null;
5876                         
5877                         CheckObsoleteAttribute (type);
5878
5879                         bool IsDelegate = TypeManager.IsDelegateType (type);
5880                         
5881                         if (IsDelegate){
5882                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5883                                 if (RequestedType != null)
5884                                         if (!(RequestedType is NewDelegate))
5885                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5886                                 return RequestedType;
5887                         }
5888
5889                         if (type.IsGenericParameter) {
5890                                 if (!TypeManager.HasConstructorConstraint (type)) {
5891                                         Error (304, String.Format (
5892                                                        "Cannot create an instance of the " +
5893                                                        "variable type '{0}' because it " +
5894                                                        "doesn't have the new() constraint",
5895                                                        type));
5896                                         return null;
5897                                 }
5898
5899                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5900                                         Error (417, String.Format (
5901                                                        "`{0}': cannot provide arguments " +
5902                                                        "when creating an instance of a " +
5903                                                        "variable type.", type));
5904                                         return null;
5905                                 }
5906
5907                                 is_type_parameter = true;
5908                                 eclass = ExprClass.Value;
5909                                 return this;
5910                         } else if (type.IsInterface || type.IsAbstract){
5911                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5912                                 return null;
5913                         }
5914                         
5915                         bool is_struct = type.IsValueType;
5916                         eclass = ExprClass.Value;
5917
5918                         //
5919                         // SRE returns a match for .ctor () on structs (the object constructor), 
5920                         // so we have to manually ignore it.
5921                         //
5922                         if (is_struct && Arguments == null)
5923                                 return this;
5924                         
5925                         Expression ml;
5926                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5927                                                 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5928                                                 MemberTypes.Constructor,
5929                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5930
5931                         if (ml == null)
5932                                 return null;
5933                         
5934                         if (! (ml is MethodGroupExpr)){
5935                                 if (!is_struct){
5936                                         ml.Error_UnexpectedKind ("method group");
5937                                         return null;
5938                                 }
5939                         }
5940
5941                         if (ml != null) {
5942                                 if (Arguments != null){
5943                                         foreach (Argument a in Arguments){
5944                                                 if (!a.Resolve (ec, loc))
5945                                                         return null;
5946                                         }
5947                                 }
5948
5949                                 method = Invocation.OverloadResolve (
5950                                         ec, (MethodGroupExpr) ml, Arguments, false, loc);
5951                                 
5952                         }
5953
5954                         if (method == null) { 
5955                                 if (!is_struct || Arguments.Count > 0) {
5956                                         Error (1501, String.Format (
5957                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5958                                             TypeManager.CSharpName (type)));
5959                                         return null;
5960                                 }
5961                         }
5962
5963                         return this;
5964                 }
5965
5966                 bool DoEmitTypeParameter (EmitContext ec)
5967                 {
5968                         ILGenerator ig = ec.ig;
5969
5970                         ig.Emit (OpCodes.Ldtoken, type);
5971                         ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5972                         ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5973                         ig.Emit (OpCodes.Unbox_Any, type);
5974
5975                         return true;
5976                 }
5977
5978                 //
5979                 // This DoEmit can be invoked in two contexts:
5980                 //    * As a mechanism that will leave a value on the stack (new object)
5981                 //    * As one that wont (init struct)
5982                 //
5983                 // You can control whether a value is required on the stack by passing
5984                 // need_value_on_stack.  The code *might* leave a value on the stack
5985                 // so it must be popped manually
5986                 //
5987                 // If we are dealing with a ValueType, we have a few
5988                 // situations to deal with:
5989                 //
5990                 //    * The target is a ValueType, and we have been provided
5991                 //      the instance (this is easy, we are being assigned).
5992                 //
5993                 //    * The target of New is being passed as an argument,
5994                 //      to a boxing operation or a function that takes a
5995                 //      ValueType.
5996                 //
5997                 //      In this case, we need to create a temporary variable
5998                 //      that is the argument of New.
5999                 //
6000                 // Returns whether a value is left on the stack
6001                 //
6002                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
6003                 {
6004                         bool is_value_type = type.IsValueType;
6005                         ILGenerator ig = ec.ig;
6006
6007                         if (is_value_type){
6008                                 IMemoryLocation ml;
6009
6010                                 // Allow DoEmit() to be called multiple times.
6011                                 // We need to create a new LocalTemporary each time since
6012                                 // you can't share LocalBuilders among ILGeneators.
6013                                 if (!value_target_set)
6014                                         value_target = new LocalTemporary (ec, type);
6015
6016                                 ml = (IMemoryLocation) value_target;
6017                                 ml.AddressOf (ec, AddressOp.Store);
6018                         }
6019
6020                         if (method != null)
6021                                 Invocation.EmitArguments (ec, method, Arguments);
6022
6023                         if (is_value_type){
6024                                 if (method == null)
6025                                         ig.Emit (OpCodes.Initobj, type);
6026                                 else 
6027                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6028                                 if (need_value_on_stack){
6029                                         value_target.Emit (ec);
6030                                         return true;
6031                                 }
6032                                 return false;
6033                         } else {
6034                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6035                                 return true;
6036                         }
6037                 }
6038
6039                 public override void Emit (EmitContext ec)
6040                 {
6041                         if (is_type_parameter)
6042                                 DoEmitTypeParameter (ec);
6043                         else
6044                                 DoEmit (ec, true);
6045                 }
6046                 
6047                 public override void EmitStatement (EmitContext ec)
6048                 {
6049                         if (is_type_parameter)
6050                                 throw new InvalidOperationException ();
6051
6052                         if (DoEmit (ec, false))
6053                                 ec.ig.Emit (OpCodes.Pop);
6054                 }
6055
6056                 public void AddressOf (EmitContext ec, AddressOp Mode)
6057                 {
6058                         if (is_type_parameter)
6059                                 throw new InvalidOperationException ();
6060
6061                         if (!type.IsValueType){
6062                                 //
6063                                 // We throw an exception.  So far, I believe we only need to support
6064                                 // value types:
6065                                 // foreach (int j in new StructType ())
6066                                 // see bug 42390
6067                                 //
6068                                 throw new Exception ("AddressOf should not be used for classes");
6069                         }
6070
6071                         if (!value_target_set)
6072                                 value_target = new LocalTemporary (ec, type);
6073                                         
6074                         IMemoryLocation ml = (IMemoryLocation) value_target;
6075                         ml.AddressOf (ec, AddressOp.Store);
6076                         if (method != null)
6077                                 Invocation.EmitArguments (ec, method, Arguments);
6078
6079                         if (method == null)
6080                                 ec.ig.Emit (OpCodes.Initobj, type);
6081                         else 
6082                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6083                         
6084                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6085                 }
6086         }
6087
6088         /// <summary>
6089         ///   14.5.10.2: Represents an array creation expression.
6090         /// </summary>
6091         ///
6092         /// <remarks>
6093         ///   There are two possible scenarios here: one is an array creation
6094         ///   expression that specifies the dimensions and optionally the
6095         ///   initialization data and the other which does not need dimensions
6096         ///   specified but where initialization data is mandatory.
6097         /// </remarks>
6098         public class ArrayCreation : Expression {
6099                 Expression requested_base_type;
6100                 ArrayList initializers;
6101
6102                 //
6103                 // The list of Argument types.
6104                 // This is used to construct the `newarray' or constructor signature
6105                 //
6106                 ArrayList arguments;
6107
6108                 //
6109                 // Method used to create the array object.
6110                 //
6111                 MethodBase new_method = null;
6112                 
6113                 Type array_element_type;
6114                 Type underlying_type;
6115                 bool is_one_dimensional = false;
6116                 bool is_builtin_type = false;
6117                 bool expect_initializers = false;
6118                 int num_arguments = 0;
6119                 int dimensions = 0;
6120                 string rank;
6121
6122                 ArrayList array_data;
6123
6124                 Hashtable bounds;
6125
6126                 //
6127                 // The number of array initializers that we can handle
6128                 // via the InitializeArray method - through EmitStaticInitializers
6129                 //
6130                 int num_automatic_initializers;
6131
6132                 const int max_automatic_initializers = 6;
6133                 
6134                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6135                 {
6136                         this.requested_base_type = requested_base_type;
6137                         this.initializers = initializers;
6138                         this.rank = rank;
6139                         loc = l;
6140
6141                         arguments = new ArrayList ();
6142
6143                         foreach (Expression e in exprs) {
6144                                 arguments.Add (new Argument (e, Argument.AType.Expression));
6145                                 num_arguments++;
6146                         }
6147                 }
6148
6149                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6150                 {
6151                         this.requested_base_type = requested_base_type;
6152                         this.initializers = initializers;
6153                         this.rank = rank;
6154                         loc = l;
6155
6156                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6157                         //
6158                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
6159                         //
6160                         //dimensions = tmp.Length - 1;
6161                         expect_initializers = true;
6162                 }
6163
6164                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6165                 {
6166                         StringBuilder sb = new StringBuilder (rank);
6167                         
6168                         sb.Append ("[");
6169                         for (int i = 1; i < idx_count; i++)
6170                                 sb.Append (",");
6171                         
6172                         sb.Append ("]");
6173
6174                         return new ComposedCast (base_type, sb.ToString (), loc);
6175                 }
6176
6177                 void Error_IncorrectArrayInitializer ()
6178                 {
6179                         Error (178, "Incorrectly structured array initializer");
6180                 }
6181                 
6182                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6183                 {
6184                         if (specified_dims) { 
6185                                 Argument a = (Argument) arguments [idx];
6186                                 
6187                                 if (!a.Resolve (ec, loc))
6188                                         return false;
6189                                 
6190                                 if (!(a.Expr is Constant)) {
6191                                         Error (150, "A constant value is expected");
6192                                         return false;
6193                                 }
6194                                 
6195                                 int value = (int) ((Constant) a.Expr).GetValue ();
6196                                 
6197                                 if (value != probe.Count) {
6198                                         Error_IncorrectArrayInitializer ();
6199                                         return false;
6200                                 }
6201                                 
6202                                 bounds [idx] = value;
6203                         }
6204
6205                         int child_bounds = -1;
6206                         foreach (object o in probe) {
6207                                 if (o is ArrayList) {
6208                                         int current_bounds = ((ArrayList) o).Count;
6209                                         
6210                                         if (child_bounds == -1) 
6211                                                 child_bounds = current_bounds;
6212
6213                                         else if (child_bounds != current_bounds){
6214                                                 Error_IncorrectArrayInitializer ();
6215                                                 return false;
6216                                         }
6217                                         if (specified_dims && (idx + 1 >= arguments.Count)){
6218                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6219                                                 return false;
6220                                         }
6221                                         
6222                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
6223                                         if (!ret)
6224                                                 return false;
6225                                 } else {
6226                                         if (child_bounds != -1){
6227                                                 Error_IncorrectArrayInitializer ();
6228                                                 return false;
6229                                         }
6230                                         
6231                                         Expression tmp = (Expression) o;
6232                                         tmp = tmp.Resolve (ec);
6233                                         if (tmp == null)
6234                                                 continue;
6235
6236                                         // Console.WriteLine ("I got: " + tmp);
6237                                         // Handle initialization from vars, fields etc.
6238
6239                                         Expression conv = Convert.ImplicitConversionRequired (
6240                                                 ec, tmp, underlying_type, loc);
6241                                         
6242                                         if (conv == null) 
6243                                                 return false;
6244
6245                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6246                                                 // These are subclasses of Constant that can appear as elements of an
6247                                                 // array that cannot be statically initialized (with num_automatic_initializers
6248                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6249                                                 array_data.Add (conv);
6250                                         } else if (conv is Constant) {
6251                                                 // These are the types of Constant that can appear in arrays that can be
6252                                                 // statically allocated.
6253                                                 array_data.Add (conv);
6254                                                 num_automatic_initializers++;
6255                                         } else
6256                                                 array_data.Add (conv);
6257                                 }
6258                         }
6259
6260                         return true;
6261                 }
6262                 
6263                 public void UpdateIndices (EmitContext ec)
6264                 {
6265                         int i = 0;
6266                         for (ArrayList probe = initializers; probe != null;) {
6267                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6268                                         Expression e = new IntConstant (probe.Count);
6269                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6270
6271                                         bounds [i++] =  probe.Count;
6272                                         
6273                                         probe = (ArrayList) probe [0];
6274                                         
6275                                 } else {
6276                                         Expression e = new IntConstant (probe.Count);
6277                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6278
6279                                         bounds [i++] = probe.Count;
6280                                         probe = null;
6281                                 }
6282                         }
6283
6284                 }
6285                 
6286                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6287                 {
6288                         if (initializers == null) {
6289                                 if (expect_initializers)
6290                                         return false;
6291                                 else
6292                                         return true;
6293                         }
6294                         
6295                         if (underlying_type == null)
6296                                 return false;
6297                         
6298                         //
6299                         // We use this to store all the date values in the order in which we
6300                         // will need to store them in the byte blob later
6301                         //
6302                         array_data = new ArrayList ();
6303                         bounds = new Hashtable ();
6304                         
6305                         bool ret;
6306
6307                         if (arguments != null) {
6308                                 ret = CheckIndices (ec, initializers, 0, true);
6309                                 return ret;
6310                         } else {
6311                                 arguments = new ArrayList ();
6312
6313                                 ret = CheckIndices (ec, initializers, 0, false);
6314                                 
6315                                 if (!ret)
6316                                         return false;
6317                                 
6318                                 UpdateIndices (ec);
6319                                 
6320                                 if (arguments.Count != dimensions) {
6321                                         Error_IncorrectArrayInitializer ();
6322                                         return false;
6323                                 }
6324
6325                                 return ret;
6326                         }
6327                 }
6328
6329                 void Error_NegativeArrayIndex ()
6330                 {
6331                         Error (284, "Can not create array with a negative size");
6332                 }
6333                 
6334                 //
6335                 // Converts `source' to an int, uint, long or ulong.
6336                 //
6337                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6338                 {
6339                         Expression target;
6340                         
6341                         bool old_checked = ec.CheckState;
6342                         ec.CheckState = true;
6343                         
6344                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6345                         if (target == null){
6346                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6347                                 if (target == null){
6348                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6349                                         if (target == null){
6350                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6351                                                 if (target == null)
6352                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6353                                         }
6354                                 }
6355                         } 
6356                         ec.CheckState = old_checked;
6357
6358                         //
6359                         // Only positive constants are allowed at compile time
6360                         //
6361                         if (target is Constant){
6362                                 if (target is IntConstant){
6363                                         if (((IntConstant) target).Value < 0){
6364                                                 Error_NegativeArrayIndex ();
6365                                                 return null;
6366                                         }
6367                                 }
6368
6369                                 if (target is LongConstant){
6370                                         if (((LongConstant) target).Value < 0){
6371                                                 Error_NegativeArrayIndex ();
6372                                                 return null;
6373                                         }
6374                                 }
6375                                 
6376                         }
6377
6378                         return target;
6379                 }
6380
6381                 //
6382                 // Creates the type of the array
6383                 //
6384                 bool LookupType (EmitContext ec)
6385                 {
6386                         StringBuilder array_qualifier = new StringBuilder (rank);
6387
6388                         //
6389                         // `In the first form allocates an array instace of the type that results
6390                         // from deleting each of the individual expression from the expression list'
6391                         //
6392                         if (num_arguments > 0) {
6393                                 array_qualifier.Append ("[");
6394                                 for (int i = num_arguments-1; i > 0; i--)
6395                                         array_qualifier.Append (",");
6396                                 array_qualifier.Append ("]");                           
6397                         }
6398
6399                         //
6400                         // Lookup the type
6401                         //
6402                         Expression array_type_expr;
6403                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6404                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
6405
6406                         if (type == null)
6407                                 return false;
6408
6409                         underlying_type = type;
6410                         if (underlying_type.IsArray)
6411                                 underlying_type = TypeManager.GetElementType (underlying_type);
6412                         dimensions = type.GetArrayRank ();
6413
6414                         return true;
6415                 }
6416                 
6417                 public override Expression DoResolve (EmitContext ec)
6418                 {
6419                         int arg_count;
6420
6421                         if (!LookupType (ec))
6422                                 return null;
6423                         
6424                         //
6425                         // First step is to validate the initializers and fill
6426                         // in any missing bits
6427                         //
6428                         if (!ValidateInitializers (ec, type))
6429                                 return null;
6430
6431                         if (arguments == null)
6432                                 arg_count = 0;
6433                         else {
6434                                 arg_count = arguments.Count;
6435                                 foreach (Argument a in arguments){
6436                                         if (!a.Resolve (ec, loc))
6437                                                 return null;
6438
6439                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6440                                         if (real_arg == null)
6441                                                 return null;
6442
6443                                         a.Expr = real_arg;
6444                                 }
6445                         }
6446                         
6447                         array_element_type = TypeManager.GetElementType (type);
6448
6449                         if (arg_count == 1) {
6450                                 is_one_dimensional = true;
6451                                 eclass = ExprClass.Value;
6452                                 return this;
6453                         }
6454
6455                         is_builtin_type = TypeManager.IsBuiltinType (type);
6456
6457                         if (is_builtin_type) {
6458                                 Expression ml;
6459                                 
6460                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6461                                                    AllBindingFlags, loc);
6462                                 
6463                                 if (!(ml is MethodGroupExpr)) {
6464                                         ml.Error_UnexpectedKind ("method group");
6465                                         return null;
6466                                 }
6467                                 
6468                                 if (ml == null) {
6469                                         Error (-6, "New invocation: Can not find a constructor for " +
6470                                                       "this argument list");
6471                                         return null;
6472                                 }
6473                                 
6474                                 new_method = Invocation.OverloadResolve (
6475                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6476
6477                                 if (new_method == null) {
6478                                         Error (-6, "New invocation: Can not find a constructor for " +
6479                                                       "this argument list");
6480                                         return null;
6481                                 }
6482                                 
6483                                 eclass = ExprClass.Value;
6484                                 return this;
6485                         } else {
6486                                 ModuleBuilder mb = CodeGen.Module.Builder;
6487                                 ArrayList args = new ArrayList ();
6488                                 
6489                                 if (arguments != null) {
6490                                         for (int i = 0; i < arg_count; i++)
6491                                                 args.Add (TypeManager.int32_type);
6492                                 }
6493                                 
6494                                 Type [] arg_types = null;
6495
6496                                 if (args.Count > 0)
6497                                         arg_types = new Type [args.Count];
6498                                 
6499                                 args.CopyTo (arg_types, 0);
6500                                 
6501                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6502                                                             arg_types);
6503
6504                                 if (new_method == null) {
6505                                         Error (-6, "New invocation: Can not find a constructor for " +
6506                                                       "this argument list");
6507                                         return null;
6508                                 }
6509                                 
6510                                 eclass = ExprClass.Value;
6511                                 return this;
6512                         }
6513                 }
6514
6515                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6516                 {
6517                         int factor;
6518                         byte [] data;
6519                         byte [] element;
6520                         int count = array_data.Count;
6521
6522                         if (underlying_type.IsEnum)
6523                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6524                         
6525                         factor = GetTypeSize (underlying_type);
6526                         if (factor == 0)
6527                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6528
6529                         data = new byte [(count * factor + 4) & ~3];
6530                         int idx = 0;
6531                         
6532                         for (int i = 0; i < count; ++i) {
6533                                 object v = array_data [i];
6534
6535                                 if (v is EnumConstant)
6536                                         v = ((EnumConstant) v).Child;
6537                                 
6538                                 if (v is Constant && !(v is StringConstant))
6539                                         v = ((Constant) v).GetValue ();
6540                                 else {
6541                                         idx += factor;
6542                                         continue;
6543                                 }
6544                                 
6545                                 if (underlying_type == TypeManager.int64_type){
6546                                         if (!(v is Expression)){
6547                                                 long val = (long) v;
6548                                                 
6549                                                 for (int j = 0; j < factor; ++j) {
6550                                                         data [idx + j] = (byte) (val & 0xFF);
6551                                                         val = (val >> 8);
6552                                                 }
6553                                         }
6554                                 } else if (underlying_type == TypeManager.uint64_type){
6555                                         if (!(v is Expression)){
6556                                                 ulong val = (ulong) v;
6557
6558                                                 for (int j = 0; j < factor; ++j) {
6559                                                         data [idx + j] = (byte) (val & 0xFF);
6560                                                         val = (val >> 8);
6561                                                 }
6562                                         }
6563                                 } else if (underlying_type == TypeManager.float_type) {
6564                                         if (!(v is Expression)){
6565                                                 element = BitConverter.GetBytes ((float) v);
6566                                                         
6567                                                 for (int j = 0; j < factor; ++j)
6568                                                         data [idx + j] = element [j];
6569                                         }
6570                                 } else if (underlying_type == TypeManager.double_type) {
6571                                         if (!(v is Expression)){
6572                                                 element = BitConverter.GetBytes ((double) v);
6573
6574                                                 for (int j = 0; j < factor; ++j)
6575                                                         data [idx + j] = element [j];
6576                                         }
6577                                 } else if (underlying_type == TypeManager.char_type){
6578                                         if (!(v is Expression)){
6579                                                 int val = (int) ((char) v);
6580                                                 
6581                                                 data [idx] = (byte) (val & 0xff);
6582                                                 data [idx+1] = (byte) (val >> 8);
6583                                         }
6584                                 } else if (underlying_type == TypeManager.short_type){
6585                                         if (!(v is Expression)){
6586                                                 int val = (int) ((short) v);
6587                                         
6588                                                 data [idx] = (byte) (val & 0xff);
6589                                                 data [idx+1] = (byte) (val >> 8);
6590                                         }
6591                                 } else if (underlying_type == TypeManager.ushort_type){
6592                                         if (!(v is Expression)){
6593                                                 int val = (int) ((ushort) v);
6594                                         
6595                                                 data [idx] = (byte) (val & 0xff);
6596                                                 data [idx+1] = (byte) (val >> 8);
6597                                         }
6598                                 } else if (underlying_type == TypeManager.int32_type) {
6599                                         if (!(v is Expression)){
6600                                                 int val = (int) v;
6601                                         
6602                                                 data [idx]   = (byte) (val & 0xff);
6603                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6604                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6605                                                 data [idx+3] = (byte) (val >> 24);
6606                                         }
6607                                 } else if (underlying_type == TypeManager.uint32_type) {
6608                                         if (!(v is Expression)){
6609                                                 uint val = (uint) v;
6610                                         
6611                                                 data [idx]   = (byte) (val & 0xff);
6612                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6613                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6614                                                 data [idx+3] = (byte) (val >> 24);
6615                                         }
6616                                 } else if (underlying_type == TypeManager.sbyte_type) {
6617                                         if (!(v is Expression)){
6618                                                 sbyte val = (sbyte) v;
6619                                                 data [idx] = (byte) val;
6620                                         }
6621                                 } else if (underlying_type == TypeManager.byte_type) {
6622                                         if (!(v is Expression)){
6623                                                 byte val = (byte) v;
6624                                                 data [idx] = (byte) val;
6625                                         }
6626                                 } else if (underlying_type == TypeManager.bool_type) {
6627                                         if (!(v is Expression)){
6628                                                 bool val = (bool) v;
6629                                                 data [idx] = (byte) (val ? 1 : 0);
6630                                         }
6631                                 } else if (underlying_type == TypeManager.decimal_type){
6632                                         if (!(v is Expression)){
6633                                                 int [] bits = Decimal.GetBits ((decimal) v);
6634                                                 int p = idx;
6635
6636                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6637                                                 int [] nbits = new int [4];
6638                                                 nbits [0] = bits [3];
6639                                                 nbits [1] = bits [2];
6640                                                 nbits [2] = bits [0];
6641                                                 nbits [3] = bits [1];
6642                                                 
6643                                                 for (int j = 0; j < 4; j++){
6644                                                         data [p++] = (byte) (nbits [j] & 0xff);
6645                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6646                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6647                                                         data [p++] = (byte) (nbits [j] >> 24);
6648                                                 }
6649                                         }
6650                                 } else
6651                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6652
6653                                 idx += factor;
6654                         }
6655
6656                         return data;
6657                 }
6658
6659                 //
6660                 // Emits the initializers for the array
6661                 //
6662                 void EmitStaticInitializers (EmitContext ec)
6663                 {
6664                         //
6665                         // First, the static data
6666                         //
6667                         FieldBuilder fb;
6668                         ILGenerator ig = ec.ig;
6669                         
6670                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6671
6672                         fb = RootContext.MakeStaticData (data);
6673
6674                         ig.Emit (OpCodes.Dup);
6675                         ig.Emit (OpCodes.Ldtoken, fb);
6676                         ig.Emit (OpCodes.Call,
6677                                  TypeManager.void_initializearray_array_fieldhandle);
6678                 }
6679
6680                 //
6681                 // Emits pieces of the array that can not be computed at compile
6682                 // time (variables and string locations).
6683                 //
6684                 // This always expect the top value on the stack to be the array
6685                 //
6686                 void EmitDynamicInitializers (EmitContext ec)
6687                 {
6688                         ILGenerator ig = ec.ig;
6689                         int dims = bounds.Count;
6690                         int [] current_pos = new int [dims];
6691                         int top = array_data.Count;
6692
6693                         MethodInfo set = null;
6694
6695                         if (dims != 1){
6696                                 Type [] args;
6697                                 ModuleBuilder mb = null;
6698                                 mb = CodeGen.Module.Builder;
6699                                 args = new Type [dims + 1];
6700
6701                                 int j;
6702                                 for (j = 0; j < dims; j++)
6703                                         args [j] = TypeManager.int32_type;
6704
6705                                 args [j] = array_element_type;
6706                                 
6707                                 set = mb.GetArrayMethod (
6708                                         type, "Set",
6709                                         CallingConventions.HasThis | CallingConventions.Standard,
6710                                         TypeManager.void_type, args);
6711                         }
6712                         
6713                         for (int i = 0; i < top; i++){
6714
6715                                 Expression e = null;
6716
6717                                 if (array_data [i] is Expression)
6718                                         e = (Expression) array_data [i];
6719
6720                                 if (e != null) {
6721                                         //
6722                                         // Basically we do this for string literals and
6723                                         // other non-literal expressions
6724                                         //
6725                                         if (e is EnumConstant){
6726                                                 e = ((EnumConstant) e).Child;
6727                                         }
6728                                         
6729                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6730                                             num_automatic_initializers <= max_automatic_initializers) {
6731                                                 Type etype = e.Type;
6732                                                 
6733                                                 ig.Emit (OpCodes.Dup);
6734
6735                                                 for (int idx = 0; idx < dims; idx++) 
6736                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6737
6738                                                 //
6739                                                 // If we are dealing with a struct, get the
6740                                                 // address of it, so we can store it.
6741                                                 //
6742                                                 if ((dims == 1) && 
6743                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6744                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6745                                                      etype == TypeManager.decimal_type)) {
6746                                                         if (e is New){
6747                                                                 New n = (New) e;
6748
6749                                                                 //
6750                                                                 // Let new know that we are providing
6751                                                                 // the address where to store the results
6752                                                                 //
6753                                                                 n.DisableTemporaryValueType ();
6754                                                         }
6755
6756                                                         ig.Emit (OpCodes.Ldelema, etype);
6757                                                 }
6758
6759                                                 e.Emit (ec);
6760
6761                                                 if (dims == 1)
6762                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
6763                                                 else 
6764                                                         ig.Emit (OpCodes.Call, set);
6765                                                 
6766                                         }
6767                                 }
6768                                 
6769                                 //
6770                                 // Advance counter
6771                                 //
6772                                 for (int j = dims - 1; j >= 0; j--){
6773                                         current_pos [j]++;
6774                                         if (current_pos [j] < (int) bounds [j])
6775                                                 break;
6776                                         current_pos [j] = 0;
6777                                 }
6778                         }
6779                 }
6780
6781                 void EmitArrayArguments (EmitContext ec)
6782                 {
6783                         ILGenerator ig = ec.ig;
6784                         
6785                         foreach (Argument a in arguments) {
6786                                 Type atype = a.Type;
6787                                 a.Emit (ec);
6788
6789                                 if (atype == TypeManager.uint64_type)
6790                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6791                                 else if (atype == TypeManager.int64_type)
6792                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6793                         }
6794                 }
6795                 
6796                 public override void Emit (EmitContext ec)
6797                 {
6798                         ILGenerator ig = ec.ig;
6799                         
6800                         EmitArrayArguments (ec);
6801                         if (is_one_dimensional)
6802                                 ig.Emit (OpCodes.Newarr, array_element_type);
6803                         else {
6804                                 if (is_builtin_type) 
6805                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6806                                 else 
6807                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6808                         }
6809                         
6810                         if (initializers != null){
6811                                 //
6812                                 // FIXME: Set this variable correctly.
6813                                 // 
6814                                 bool dynamic_initializers = true;
6815
6816                                 // This will never be true for array types that cannot be statically
6817                                 // initialized. num_automatic_initializers will always be zero.  See
6818                                 // CheckIndices.
6819                                         if (num_automatic_initializers > max_automatic_initializers)
6820                                                 EmitStaticInitializers (ec);
6821                                 
6822                                 if (dynamic_initializers)
6823                                         EmitDynamicInitializers (ec);
6824                         }
6825                 }
6826                 
6827                 public object EncodeAsAttribute ()
6828                 {
6829                         if (!is_one_dimensional){
6830                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6831                                 return null;
6832                         }
6833
6834                         if (array_data == null){
6835                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6836                                 return null;
6837                         }
6838                         
6839                         object [] ret = new object [array_data.Count];
6840                         int i = 0;
6841                         foreach (Expression e in array_data){
6842                                 object v;
6843                                 
6844                                 if (e is NullLiteral)
6845                                         v = null;
6846                                 else {
6847                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
6848                                                 return null;
6849                                 }
6850                                 ret [i++] = v;
6851                         }
6852                         return ret;
6853                 }
6854
6855                 public Expression TurnIntoConstant ()
6856                 {
6857                         //
6858                         // Should use something like the above attribute thing.
6859                         // It should return a subclass of Constant that just returns
6860                         // the computed value of the array
6861                         //
6862                         throw new Exception ("Does not support yet Turning array into a Constant");
6863                 }
6864         }
6865         
6866         /// <summary>
6867         ///   Represents the `this' construct
6868         /// </summary>
6869         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6870
6871                 Block block;
6872                 VariableInfo variable_info;
6873                 
6874                 public This (Block block, Location loc)
6875                 {
6876                         this.loc = loc;
6877                         this.block = block;
6878                 }
6879
6880                 public This (Location loc)
6881                 {
6882                         this.loc = loc;
6883                 }
6884
6885                 public VariableInfo VariableInfo {
6886                         get { return variable_info; }
6887                 }
6888
6889                 public bool VerifyFixed (bool is_expression)
6890                 {
6891                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6892                                 return false;
6893                         else
6894                                 return variable_info.LocalInfo.IsFixed;
6895                 }
6896
6897                 public bool ResolveBase (EmitContext ec)
6898                 {
6899                         eclass = ExprClass.Variable;
6900
6901                         if (ec.TypeContainer.CurrentType != null)
6902                                 type = ec.TypeContainer.CurrentType.ResolveType (ec);
6903                         else
6904                                 type = ec.ContainerType;
6905
6906                         if (ec.IsStatic) {
6907                                 Error (26, "Keyword this not valid in static code");
6908                                 return false;
6909                         }
6910
6911                         if ((block != null) && (block.ThisVariable != null))
6912                                 variable_info = block.ThisVariable.VariableInfo;
6913
6914                         return true;
6915                 }
6916
6917                 public override Expression DoResolve (EmitContext ec)
6918                 {
6919                         if (!ResolveBase (ec))
6920                                 return null;
6921
6922                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6923                                 Error (188, "The this object cannot be used before all " +
6924                                        "of its fields are assigned to");
6925                                 variable_info.SetAssigned (ec);
6926                                 return this;
6927                         }
6928
6929                         if (ec.IsFieldInitializer) {
6930                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6931                                        "a method or a property.");
6932                                 return null;
6933                         }
6934
6935                         return this;
6936                 }
6937
6938                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6939                 {
6940                         if (!ResolveBase (ec))
6941                                 return null;
6942
6943                         if (variable_info != null)
6944                                 variable_info.SetAssigned (ec);
6945                         
6946                         if (ec.TypeContainer is Class){
6947                                 Error (1604, "Cannot assign to `this'");
6948                                 return null;
6949                         }
6950
6951                         return this;
6952                 }
6953
6954                 public override void Emit (EmitContext ec)
6955                 {
6956                         ILGenerator ig = ec.ig;
6957
6958                         ec.EmitThis ();
6959                         if (ec.TypeContainer is Struct)
6960                                 ig.Emit (OpCodes.Ldobj, type);
6961                 }
6962
6963                 public void EmitAssign (EmitContext ec, Expression source)
6964                 {
6965                         ILGenerator ig = ec.ig;
6966                         
6967                         if (ec.TypeContainer is Struct){
6968                                 ec.EmitThis ();
6969                                 source.Emit (ec);
6970                                 ig.Emit (OpCodes.Stobj, type);
6971                         } else {
6972                                 source.Emit (ec);
6973                                 ig.Emit (OpCodes.Starg, 0);
6974                         }
6975                 }
6976
6977                 public void AddressOf (EmitContext ec, AddressOp mode)
6978                 {
6979                         ec.EmitThis ();
6980
6981                         // FIMXE
6982                         // FIGURE OUT WHY LDARG_S does not work
6983                         //
6984                         // consider: struct X { int val; int P { set { val = value; }}}
6985                         //
6986                         // Yes, this looks very bad. Look at `NOTAS' for
6987                         // an explanation.
6988                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6989                 }
6990         }
6991
6992         //
6993         // This produces the value that renders an instance, used by the iterators code
6994         //
6995         public class ProxyInstance : Expression, IMemoryLocation  {
6996                 public override Expression DoResolve (EmitContext ec)
6997                 {
6998                         eclass = ExprClass.Variable;
6999                         type = ec.ContainerType;
7000                         return this;
7001                 }
7002                 
7003                 public override void Emit (EmitContext ec)
7004                 {
7005                         ec.ig.Emit (OpCodes.Ldarg_0);
7006
7007                 }
7008                 
7009                 public void AddressOf (EmitContext ec, AddressOp mode)
7010                 {
7011                         ec.ig.Emit (OpCodes.Ldarg_0);
7012                 }
7013         }
7014
7015         /// <summary>
7016         ///   Implements the typeof operator
7017         /// </summary>
7018         public class TypeOf : Expression {
7019                 public readonly Expression QueriedType;
7020                 protected Type typearg;
7021                 
7022                 public TypeOf (Expression queried_type, Location l)
7023                 {
7024                         QueriedType = queried_type;
7025                         loc = l;
7026                 }
7027
7028                 public override Expression DoResolve (EmitContext ec)
7029                 {
7030                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
7031
7032                         if (typearg == null)
7033                                 return null;
7034
7035                         if (typearg == TypeManager.void_type) {
7036                                 Error (673, "System.Void cannot be used from C# - " +
7037                                        "use typeof (void) to get the void type object");
7038                                 return null;
7039                         }
7040
7041                         CheckObsoleteAttribute (typearg);
7042
7043                         type = TypeManager.type_type;
7044                         eclass = ExprClass.Type;
7045                         return this;
7046                 }
7047
7048                 public override void Emit (EmitContext ec)
7049                 {
7050                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
7051                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7052                 }
7053
7054                 public Type TypeArg { 
7055                         get { return typearg; }
7056                 }
7057         }
7058
7059         /// <summary>
7060         ///   Implements the `typeof (void)' operator
7061         /// </summary>
7062         public class TypeOfVoid : TypeOf {
7063                 public TypeOfVoid (Location l) : base (null, l)
7064                 {
7065                         loc = l;
7066                 }
7067
7068                 public override Expression DoResolve (EmitContext ec)
7069                 {
7070                         type = TypeManager.type_type;
7071                         typearg = TypeManager.void_type;
7072                         eclass = ExprClass.Type;
7073                         return this;
7074                 }
7075         }
7076
7077         /// <summary>
7078         ///   Implements the sizeof expression
7079         /// </summary>
7080         public class SizeOf : Expression {
7081                 public Expression QueriedType;
7082                 Type type_queried;
7083                 
7084                 public SizeOf (Expression queried_type, Location l)
7085                 {
7086                         this.QueriedType = queried_type;
7087                         loc = l;
7088                 }
7089
7090                 public override Expression DoResolve (EmitContext ec)
7091                 {
7092                         if (!ec.InUnsafe) {
7093                                 Report.Error (
7094                                         233, loc, "Sizeof may only be used in an unsafe context " +
7095                                         "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
7096                                 return null;
7097                         }
7098                                 
7099                         QueriedType = ec.DeclSpace.ResolveTypeExpr (QueriedType, false, loc);
7100                         if (QueriedType == null || QueriedType.Type == null)
7101                                 return null;
7102
7103                         if (QueriedType is TypeParameterExpr){
7104                                 ((TypeParameterExpr)QueriedType).Error_CannotUseAsUnmanagedType (loc);
7105                                 return null;
7106                         }
7107
7108                         type_queried = QueriedType.Type;
7109                         if (type_queried == null)
7110                                 return null;
7111
7112                         CheckObsoleteAttribute (type_queried);
7113
7114                         if (!TypeManager.IsUnmanagedType (type_queried)){
7115                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
7116                                 return null;
7117                         }
7118                         
7119                         type = TypeManager.int32_type;
7120                         eclass = ExprClass.Value;
7121                         return this;
7122                 }
7123
7124                 public override void Emit (EmitContext ec)
7125                 {
7126                         int size = GetTypeSize (type_queried);
7127
7128                         if (size == 0)
7129                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7130                         else
7131                                 IntConstant.EmitInt (ec.ig, size);
7132                 }
7133         }
7134
7135         /// <summary>
7136         ///   Implements the member access expression
7137         /// </summary>
7138         public class MemberAccess : Expression {
7139                 public string Identifier;
7140                 protected Expression expr;
7141                 protected TypeArguments args;
7142                 
7143                 public MemberAccess (Expression expr, string id, Location l)
7144                 {
7145                         this.expr = expr;
7146                         Identifier = id;
7147                         loc = l;
7148                 }
7149
7150                 public MemberAccess (Expression expr, string id, TypeArguments args,
7151                                      Location l)
7152                         : this (expr, id, l)
7153                 {
7154                         this.args = args;
7155                 }
7156
7157                 public Expression Expr {
7158                         get {
7159                                 return expr;
7160                         }
7161                 }
7162
7163                 public static void error176 (Location loc, string name)
7164                 {
7165                         Report.Error (176, loc, "Static member `" +
7166                                       name + "' cannot be accessed " +
7167                                       "with an instance reference, qualify with a " +
7168                                       "type name instead");
7169                 }
7170
7171                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
7172                 {
7173                         if (left_original == null)
7174                                 return false;
7175
7176                         if (!(left_original is SimpleName))
7177                                 return false;
7178
7179                         SimpleName sn = (SimpleName) left_original;
7180
7181                         TypeExpr t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
7182                         if (t != null)
7183                                 return true;
7184
7185                         return false;
7186                 }
7187                 
7188                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7189                                                               Expression left, Location loc,
7190                                                               Expression left_original)
7191                 {
7192                         bool left_is_type, left_is_explicit;
7193
7194                         // If `left' is null, then we're called from SimpleNameResolve and this is
7195                         // a member in the currently defining class.
7196                         if (left == null) {
7197                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7198                                 left_is_explicit = false;
7199
7200                                 // Implicitly default to `this' unless we're static.
7201                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7202                                         left = ec.GetThis (loc);
7203                         } else {
7204                                 left_is_type = left is TypeExpr;
7205                                 left_is_explicit = true;
7206                         }
7207
7208                         if (member_lookup is FieldExpr){
7209                                 FieldExpr fe = (FieldExpr) member_lookup;
7210                                 FieldInfo fi = fe.FieldInfo;
7211                                 Type decl_type = fi.DeclaringType;
7212
7213                                 if (fi is FieldBuilder) {
7214                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7215                                         
7216                                         if (c != null) {
7217                                                 object o;
7218                                                 if (!c.LookupConstantValue (out o))
7219                                                         return null;
7220
7221                                                 object real_value = ((Constant) c.Expr).GetValue ();
7222
7223                                                 return Constantify (real_value, fi.FieldType);
7224                                         }
7225                                 }
7226
7227                                 if (fi.IsLiteral) {
7228                                         Type t = fi.FieldType;
7229                                         
7230                                         object o;
7231
7232                                         if (fi is FieldBuilder)
7233                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
7234                                         else
7235                                                 o = fi.GetValue (fi);
7236                                         
7237                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7238                                                 if (left_is_explicit && !left_is_type &&
7239                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {
7240                                                         error176 (loc, fe.FieldInfo.Name);
7241                                                         return null;
7242                                                 }                                       
7243                                                 
7244                                                 Expression enum_member = MemberLookup (
7245                                                         ec, decl_type, "value__", MemberTypes.Field,
7246                                                         AllBindingFlags, loc); 
7247
7248                                                 Enum en = TypeManager.LookupEnum (decl_type);
7249
7250                                                 Constant c;
7251                                                 if (en != null)
7252                                                         c = Constantify (o, en.UnderlyingType);
7253                                                 else 
7254                                                         c = Constantify (o, enum_member.Type);
7255                                                 
7256                                                 return new EnumConstant (c, decl_type);
7257                                         }
7258                                         
7259                                         Expression exp = Constantify (o, t);
7260
7261                                         if (left_is_explicit && !left_is_type) {
7262                                                 error176 (loc, fe.FieldInfo.Name);
7263                                                 return null;
7264                                         }
7265                                         
7266                                         return exp;
7267                                 }
7268
7269                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
7270                                         UnsafeError (loc);
7271                                         return null;
7272                                 }
7273                         }
7274
7275                         if (member_lookup is EventExpr) {
7276                                 EventExpr ee = (EventExpr) member_lookup;
7277                                 
7278                                 //
7279                                 // If the event is local to this class, we transform ourselves into
7280                                 // a FieldExpr
7281                                 //
7282
7283                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7284                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7285                                         MemberInfo mi = GetFieldFromEvent (ee);
7286
7287                                         if (mi == null) {
7288                                                 //
7289                                                 // If this happens, then we have an event with its own
7290                                                 // accessors and private field etc so there's no need
7291                                                 // to transform ourselves.
7292                                                 //
7293                                                 ee.InstanceExpression = left;
7294                                                 return ee;
7295                                         }
7296
7297                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7298                                         
7299                                         if (ml == null) {
7300                                                 Report.Error (-200, loc, "Internal error!!");
7301                                                 return null;
7302                                         }
7303
7304                                         if (!left_is_explicit)
7305                                                 left = null;
7306                                         
7307                                         ee.InstanceExpression = left;
7308
7309                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7310                                 }
7311                         }
7312
7313                         if (member_lookup is IMemberExpr) {
7314                                 IMemberExpr me = (IMemberExpr) member_lookup;
7315                                 MethodGroupExpr mg = me as MethodGroupExpr;
7316
7317                                 if (left_is_type){
7318                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7319                                                 mg.IsExplicitImpl = left_is_explicit;
7320
7321                                         if (!me.IsStatic){
7322                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7323                                                     IdenticalNameAndTypeName (ec, left_original, loc))
7324                                                         return member_lookup;
7325
7326                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7327                                                 return null;
7328                                         }
7329
7330                                 } else {
7331                                         if (!me.IsInstance){
7332                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
7333                                                         return member_lookup;
7334
7335                                                 if (left_is_explicit) {
7336                                                         error176 (loc, me.Name);
7337                                                         return null;
7338                                                 }
7339                                         }
7340
7341                                         //
7342                                         // Since we can not check for instance objects in SimpleName,
7343                                         // becaue of the rule that allows types and variables to share
7344                                         // the name (as long as they can be de-ambiguated later, see 
7345                                         // IdenticalNameAndTypeName), we have to check whether left 
7346                                         // is an instance variable in a static context
7347                                         //
7348                                         // However, if the left-hand value is explicitly given, then
7349                                         // it is already our instance expression, so we aren't in
7350                                         // static context.
7351                                         //
7352
7353                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7354                                                 IMemberExpr mexp = (IMemberExpr) left;
7355
7356                                                 if (!mexp.IsStatic){
7357                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7358                                                         return null;
7359                                                 }
7360                                         }
7361
7362                                         if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, loc))
7363                                                 mg.IdenticalTypeName = true;
7364
7365                                         me.InstanceExpression = left;
7366                                 }
7367
7368                                 return member_lookup;
7369                         }
7370
7371                         Console.WriteLine ("Left is: " + left);
7372                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7373                         Environment.Exit (1);
7374                         return null;
7375                 }
7376                 
7377                 public virtual Expression DoResolve (EmitContext ec, Expression right_side,
7378                                                      ResolveFlags flags)
7379                 {
7380                         if (type != null)
7381                                 throw new Exception ();
7382
7383                         //
7384                         // Resolve the expression with flow analysis turned off, we'll do the definite
7385                         // assignment checks later.  This is because we don't know yet what the expression
7386                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7387                         // definite assignment check on the actual field and not on the whole struct.
7388                         //
7389
7390                         Expression original = expr;
7391                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
7392                         if (expr == null)
7393                                 return null;
7394
7395                         if (expr is SimpleName){
7396                                 SimpleName child_expr = (SimpleName) expr;
7397
7398                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7399
7400                                 return new_expr.Resolve (ec, flags);
7401                         }
7402                                         
7403                         //
7404                         // TODO: I mailed Ravi about this, and apparently we can get rid
7405                         // of this and put it in the right place.
7406                         // 
7407                         // Handle enums here when they are in transit.
7408                         // Note that we cannot afford to hit MemberLookup in this case because
7409                         // it will fail to find any members at all
7410                         //
7411
7412                         Type expr_type;
7413                         if (expr is TypeExpr){
7414                                 expr_type = ((TypeExpr) expr).ResolveType (ec);
7415
7416                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7417                                         Report.Error_T (122, loc, expr_type);
7418                                         return null;
7419                                 }
7420
7421                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7422                                         Enum en = TypeManager.LookupEnum (expr_type);
7423
7424                                         if (en != null) {
7425                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7426                                                 
7427                                                 if (value != null){
7428                                                         ObsoleteAttribute oa = en.GetObsoleteAttribute (ec, Identifier);
7429                                                         if (oa != null) {
7430                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7431                                                         }
7432
7433                                                         Constant c = Constantify (value, en.UnderlyingType);
7434                                                         return new EnumConstant (c, expr_type);
7435                                                 }
7436                                         } else {
7437                                                 CheckObsoleteAttribute (expr_type);
7438
7439                                                 FieldInfo fi = expr_type.GetField (Identifier);
7440                                                 if (fi != null) {
7441                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7442                                                         if (oa != null)
7443                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7444                                                 }
7445                                         }
7446                                 }
7447                         } else
7448                                 expr_type = expr.Type;
7449                         
7450                         if (expr_type.IsPointer){
7451                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7452                                        TypeManager.CSharpName (expr_type) + ")");
7453                                 return null;
7454                         }
7455
7456                         int errors = Report.Errors;
7457
7458                         Expression member_lookup;
7459                         member_lookup = MemberLookup (
7460                                 ec, expr_type, expr_type, Identifier, loc);
7461                         if ((member_lookup == null) && (args != null)) {
7462                                 string lookup_id = Identifier + "!" + args.Count;
7463                                 member_lookup = MemberLookup (
7464                                         ec, expr_type, expr_type, lookup_id, loc);
7465                         }
7466                         if (member_lookup == null) {
7467                                 MemberLookupFailed (
7468                                         ec, expr_type, expr_type, Identifier, null, loc);
7469                                 return null;
7470                         }
7471
7472                         if (member_lookup is TypeExpr) {
7473                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7474                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7475                                                member_lookup.Type + "' instead");
7476                                         return null;
7477                                 }
7478
7479                                 return member_lookup;
7480                         }
7481
7482                         if (args != null) {
7483                                 string full_name = expr_type + "." + Identifier;
7484
7485                                 if (member_lookup is FieldExpr) {
7486                                         Report.Error (307, loc, "The field `{0}' cannot " +
7487                                                       "be used with type arguments", full_name);
7488                                         return null;
7489                                 } else if (member_lookup is EventExpr) {
7490                                         Report.Error (307, loc, "The event `{0}' cannot " +
7491                                                       "be used with type arguments", full_name);
7492                                         return null;
7493                                 } else if (member_lookup is PropertyExpr) {
7494                                         Report.Error (307, loc, "The property `{0}' cannot " +
7495                                                       "be used with type arguments", full_name);
7496                                         return null;
7497                                 }
7498                         }
7499                         
7500                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7501                         if (member_lookup == null)
7502                                 return null;
7503
7504                         if (args != null) {
7505                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7506                                 if (mg == null)
7507                                         throw new InternalErrorException ();
7508
7509                                 return mg.ResolveGeneric (ec, args);
7510                         }
7511
7512                         // The following DoResolve/DoResolveLValue will do the definite assignment
7513                         // check.
7514
7515                         if (right_side != null)
7516                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7517                         else
7518                                 member_lookup = member_lookup.DoResolve (ec);
7519
7520                         return member_lookup;
7521                 }
7522
7523                 public override Expression DoResolve (EmitContext ec)
7524                 {
7525                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7526                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7527                 }
7528
7529                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7530                 {
7531                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7532                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7533                 }
7534
7535                 public override Expression ResolveAsTypeStep (EmitContext ec)
7536                 {
7537                         string fname = null;
7538                         MemberAccess full_expr = this;
7539                         while (full_expr != null) {
7540                                 if (fname != null)
7541                                         fname = String.Concat (full_expr.Identifier, ".", fname);
7542                                 else
7543                                         fname = full_expr.Identifier;
7544
7545                                 if (full_expr.Expr is SimpleName) {
7546                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7547                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
7548                                         if (fully_qualified != null)
7549                                                 return new TypeExpression (fully_qualified, loc);
7550                                 }
7551
7552                                 full_expr = full_expr.Expr as MemberAccess;
7553                         }
7554
7555                         Expression new_expr = expr.ResolveAsTypeStep (ec);
7556
7557                         if (new_expr == null)
7558                                 return null;
7559
7560                         if (new_expr is SimpleName){
7561                                 SimpleName child_expr = (SimpleName) new_expr;
7562                                 
7563                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7564
7565                                 return new_expr.ResolveAsTypeStep (ec);
7566                         }
7567
7568                         Type expr_type = ((TypeExpr) new_expr).ResolveType (ec);
7569
7570                         if (expr_type.IsPointer){
7571                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7572                                        TypeManager.CSharpName (expr_type) + ")");
7573                                 return null;
7574                         }
7575
7576                         Expression member_lookup;
7577                         string lookup_id;
7578                         if (args != null)
7579                                 lookup_id = Identifier + "!" + args.Count;
7580                         else
7581                                 lookup_id = Identifier;
7582                         member_lookup = MemberLookupFinal (
7583                                 ec, expr_type, expr_type, lookup_id, loc);
7584                         if (member_lookup == null)
7585                                 return null;
7586
7587                         TypeExpr texpr = member_lookup as TypeExpr;
7588                         if (texpr == null)
7589                                 return null;
7590
7591                         Type t = texpr.ResolveType (ec);
7592                         if (t == null)
7593                                 return null;
7594
7595                         if (TypeManager.HasGenericArguments (expr_type)) {
7596                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7597
7598                                 TypeArguments new_args = new TypeArguments (loc);
7599                                 foreach (Type decl in decl_args)
7600                                         new_args.Add (new TypeExpression (decl, loc));
7601
7602                                 if (args != null)
7603                                         new_args.Add (args);
7604
7605                                 args = new_args;
7606                         }
7607
7608                         if (args != null) {
7609                                 ConstructedType ctype = new ConstructedType (t, args, loc);
7610                                 return ctype.ResolveAsTypeStep (ec);
7611                         }
7612
7613                         return texpr;
7614                 }
7615
7616                 public override void Emit (EmitContext ec)
7617                 {
7618                         throw new Exception ("Should not happen");
7619                 }
7620
7621                 public override string ToString ()
7622                 {
7623                         if (args != null)
7624                                 return expr + "." + Identifier + "!" + args.Count;
7625                         else
7626                                 return expr + "." + Identifier;
7627                 }
7628         }
7629
7630         /// <summary>
7631         ///   Implements checked expressions
7632         /// </summary>
7633         public class CheckedExpr : Expression {
7634
7635                 public Expression Expr;
7636
7637                 public CheckedExpr (Expression e, Location l)
7638                 {
7639                         Expr = e;
7640                         loc = l;
7641                 }
7642
7643                 public override Expression DoResolve (EmitContext ec)
7644                 {
7645                         bool last_check = ec.CheckState;
7646                         bool last_const_check = ec.ConstantCheckState;
7647
7648                         ec.CheckState = true;
7649                         ec.ConstantCheckState = true;
7650                         Expr = Expr.Resolve (ec);
7651                         ec.CheckState = last_check;
7652                         ec.ConstantCheckState = last_const_check;
7653                         
7654                         if (Expr == null)
7655                                 return null;
7656
7657                         if (Expr is Constant)
7658                                 return Expr;
7659                         
7660                         eclass = Expr.eclass;
7661                         type = Expr.Type;
7662                         return this;
7663                 }
7664
7665                 public override void Emit (EmitContext ec)
7666                 {
7667                         bool last_check = ec.CheckState;
7668                         bool last_const_check = ec.ConstantCheckState;
7669                         
7670                         ec.CheckState = true;
7671                         ec.ConstantCheckState = true;
7672                         Expr.Emit (ec);
7673                         ec.CheckState = last_check;
7674                         ec.ConstantCheckState = last_const_check;
7675                 }
7676                 
7677         }
7678
7679         /// <summary>
7680         ///   Implements the unchecked expression
7681         /// </summary>
7682         public class UnCheckedExpr : Expression {
7683
7684                 public Expression Expr;
7685
7686                 public UnCheckedExpr (Expression e, Location l)
7687                 {
7688                         Expr = e;
7689                         loc = l;
7690                 }
7691
7692                 public override Expression DoResolve (EmitContext ec)
7693                 {
7694                         bool last_check = ec.CheckState;
7695                         bool last_const_check = ec.ConstantCheckState;
7696
7697                         ec.CheckState = false;
7698                         ec.ConstantCheckState = false;
7699                         Expr = Expr.Resolve (ec);
7700                         ec.CheckState = last_check;
7701                         ec.ConstantCheckState = last_const_check;
7702
7703                         if (Expr == null)
7704                                 return null;
7705
7706                         if (Expr is Constant)
7707                                 return Expr;
7708                         
7709                         eclass = Expr.eclass;
7710                         type = Expr.Type;
7711                         return this;
7712                 }
7713
7714                 public override void Emit (EmitContext ec)
7715                 {
7716                         bool last_check = ec.CheckState;
7717                         bool last_const_check = ec.ConstantCheckState;
7718                         
7719                         ec.CheckState = false;
7720                         ec.ConstantCheckState = false;
7721                         Expr.Emit (ec);
7722                         ec.CheckState = last_check;
7723                         ec.ConstantCheckState = last_const_check;
7724                 }
7725                 
7726         }
7727
7728         /// <summary>
7729         ///   An Element Access expression.
7730         ///
7731         ///   During semantic analysis these are transformed into 
7732         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7733         /// </summary>
7734         public class ElementAccess : Expression {
7735                 public ArrayList  Arguments;
7736                 public Expression Expr;
7737                 
7738                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7739                 {
7740                         Expr = e;
7741
7742                         loc  = l;
7743                         
7744                         if (e_list == null)
7745                                 return;
7746                         
7747                         Arguments = new ArrayList ();
7748                         foreach (Expression tmp in e_list)
7749                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7750                         
7751                 }
7752
7753                 bool CommonResolve (EmitContext ec)
7754                 {
7755                         Expr = Expr.Resolve (ec);
7756
7757                         if (Expr == null) 
7758                                 return false;
7759
7760                         if (Arguments == null)
7761                                 return false;
7762
7763                         foreach (Argument a in Arguments){
7764                                 if (!a.Resolve (ec, loc))
7765                                         return false;
7766                         }
7767
7768                         return true;
7769                 }
7770
7771                 Expression MakePointerAccess ()
7772                 {
7773                         Type t = Expr.Type;
7774
7775                         if (t == TypeManager.void_ptr_type){
7776                                 Error (242, "The array index operation is not valid for void pointers");
7777                                 return null;
7778                         }
7779                         if (Arguments.Count != 1){
7780                                 Error (196, "A pointer must be indexed by a single value");
7781                                 return null;
7782                         }
7783                         Expression p;
7784
7785                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
7786                         return new Indirection (p, loc);
7787                 }
7788                 
7789                 public override Expression DoResolve (EmitContext ec)
7790                 {
7791                         if (!CommonResolve (ec))
7792                                 return null;
7793
7794                         //
7795                         // We perform some simple tests, and then to "split" the emit and store
7796                         // code we create an instance of a different class, and return that.
7797                         //
7798                         // I am experimenting with this pattern.
7799                         //
7800                         Type t = Expr.Type;
7801
7802                         if (t == TypeManager.array_type){
7803                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7804                                 return null;
7805                         }
7806                         
7807                         if (t.IsArray)
7808                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7809                         else if (t.IsPointer)
7810                                 return MakePointerAccess ();
7811                         else
7812                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7813                 }
7814
7815                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7816                 {
7817                         if (!CommonResolve (ec))
7818                                 return null;
7819
7820                         Type t = Expr.Type;
7821                         if (t.IsArray)
7822                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7823                         else if (t.IsPointer)
7824                                 return MakePointerAccess ();
7825                         else
7826                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7827                 }
7828                 
7829                 public override void Emit (EmitContext ec)
7830                 {
7831                         throw new Exception ("Should never be reached");
7832                 }
7833         }
7834
7835         /// <summary>
7836         ///   Implements array access 
7837         /// </summary>
7838         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7839                 //
7840                 // Points to our "data" repository
7841                 //
7842                 ElementAccess ea;
7843
7844                 LocalTemporary [] cached_locations;
7845                 
7846                 public ArrayAccess (ElementAccess ea_data, Location l)
7847                 {
7848                         ea = ea_data;
7849                         eclass = ExprClass.Variable;
7850                         loc = l;
7851                 }
7852
7853                 public override Expression DoResolve (EmitContext ec)
7854                 {
7855 #if false
7856                         ExprClass eclass = ea.Expr.eclass;
7857
7858                         // As long as the type is valid
7859                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7860                               eclass == ExprClass.Value)) {
7861                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7862                                 return null;
7863                         }
7864 #endif
7865
7866                         Type t = ea.Expr.Type;
7867                         if (t.GetArrayRank () != ea.Arguments.Count){
7868                                 ea.Error (22,
7869                                           "Incorrect number of indexes for array " +
7870                                           " expected: " + t.GetArrayRank () + " got: " +
7871                                           ea.Arguments.Count);
7872                                 return null;
7873                         }
7874
7875                         type = TypeManager.GetElementType (t);
7876                         if (type.IsPointer && !ec.InUnsafe){
7877                                 UnsafeError (ea.Location);
7878                                 return null;
7879                         }
7880
7881                         foreach (Argument a in ea.Arguments){
7882                                 Type argtype = a.Type;
7883
7884                                 if (argtype == TypeManager.int32_type ||
7885                                     argtype == TypeManager.uint32_type ||
7886                                     argtype == TypeManager.int64_type ||
7887                                     argtype == TypeManager.uint64_type)
7888                                         continue;
7889
7890                                 //
7891                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7892                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7893                                 //
7894                                 // Wonder if I will run into trouble for this.
7895                                 //
7896                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7897                                 if (a.Expr == null)
7898                                         return null;
7899                         }
7900                         
7901                         eclass = ExprClass.Variable;
7902
7903                         return this;
7904                 }
7905
7906                 /// <summary>
7907                 ///    Emits the right opcode to load an object of Type `t'
7908                 ///    from an array of T
7909                 /// </summary>
7910                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7911                 {
7912                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7913                                 ig.Emit (OpCodes.Ldelem_U1);
7914                         else if (type == TypeManager.sbyte_type)
7915                                 ig.Emit (OpCodes.Ldelem_I1);
7916                         else if (type == TypeManager.short_type)
7917                                 ig.Emit (OpCodes.Ldelem_I2);
7918                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7919                                 ig.Emit (OpCodes.Ldelem_U2);
7920                         else if (type == TypeManager.int32_type)
7921                                 ig.Emit (OpCodes.Ldelem_I4);
7922                         else if (type == TypeManager.uint32_type)
7923                                 ig.Emit (OpCodes.Ldelem_U4);
7924                         else if (type == TypeManager.uint64_type)
7925                                 ig.Emit (OpCodes.Ldelem_I8);
7926                         else if (type == TypeManager.int64_type)
7927                                 ig.Emit (OpCodes.Ldelem_I8);
7928                         else if (type == TypeManager.float_type)
7929                                 ig.Emit (OpCodes.Ldelem_R4);
7930                         else if (type == TypeManager.double_type)
7931                                 ig.Emit (OpCodes.Ldelem_R8);
7932                         else if (type == TypeManager.intptr_type)
7933                                 ig.Emit (OpCodes.Ldelem_I);
7934                         else if (TypeManager.IsEnumType (type)){
7935                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7936                         } else if (type.IsValueType){
7937                                 ig.Emit (OpCodes.Ldelema, type);
7938                                 ig.Emit (OpCodes.Ldobj, type);
7939                         } else if (type.IsGenericParameter)
7940                                 ig.Emit (OpCodes.Ldelem_Any, type);
7941                         else
7942                                 ig.Emit (OpCodes.Ldelem_Ref);
7943                 }
7944
7945                 /// <summary>
7946                 ///    Emits the right opcode to store an object of Type `t'
7947                 ///    from an array of T.  
7948                 /// </summary>
7949                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
7950                 {
7951                         bool is_stobj, has_type_arg;
7952                         OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7953                         if (has_type_arg)
7954                                 ig.Emit (op, t);
7955                         else
7956                                 ig.Emit (op);
7957                 }
7958
7959                 /// <summary>
7960                 ///    Returns the right opcode to store an object of Type `t'
7961                 ///    from an array of T.  
7962                 /// </summary>
7963                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7964                 {
7965                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7966                         has_type_arg = false; is_stobj = false;
7967                         t = TypeManager.TypeToCoreType (t);
7968                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
7969                                 t = TypeManager.EnumToUnderlying (t);
7970                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7971                             t == TypeManager.bool_type)
7972                                 return OpCodes.Stelem_I1;
7973                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7974                                  t == TypeManager.char_type)
7975                                 return OpCodes.Stelem_I2;
7976                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7977                                 return OpCodes.Stelem_I4;
7978                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7979                                 return OpCodes.Stelem_I8;
7980                         else if (t == TypeManager.float_type)
7981                                 return OpCodes.Stelem_R4;
7982                         else if (t == TypeManager.double_type)
7983                                 return OpCodes.Stelem_R8;
7984                         else if (t == TypeManager.intptr_type) {
7985                                 has_type_arg = true;
7986                                 is_stobj = true;
7987                                 return OpCodes.Stobj;
7988                         } else if (t.IsValueType) {
7989                                 has_type_arg = true;
7990                                 is_stobj = true;
7991                                 return OpCodes.Stobj;
7992                         } else if (t.IsGenericParameter) {
7993                                 has_type_arg = true;
7994                                 return OpCodes.Stelem_Any;
7995                         } else
7996                                 return OpCodes.Stelem_Ref;
7997                 }
7998
7999                 MethodInfo FetchGetMethod ()
8000                 {
8001                         ModuleBuilder mb = CodeGen.Module.Builder;
8002                         int arg_count = ea.Arguments.Count;
8003                         Type [] args = new Type [arg_count];
8004                         MethodInfo get;
8005                         
8006                         for (int i = 0; i < arg_count; i++){
8007                                 //args [i++] = a.Type;
8008                                 args [i] = TypeManager.int32_type;
8009                         }
8010                         
8011                         get = mb.GetArrayMethod (
8012                                 ea.Expr.Type, "Get",
8013                                 CallingConventions.HasThis |
8014                                 CallingConventions.Standard,
8015                                 type, args);
8016                         return get;
8017                 }
8018                                 
8019
8020                 MethodInfo FetchAddressMethod ()
8021                 {
8022                         ModuleBuilder mb = CodeGen.Module.Builder;
8023                         int arg_count = ea.Arguments.Count;
8024                         Type [] args = new Type [arg_count];
8025                         MethodInfo address;
8026                         Type ret_type;
8027                         
8028                         ret_type = TypeManager.GetReferenceType (type);
8029                         
8030                         for (int i = 0; i < arg_count; i++){
8031                                 //args [i++] = a.Type;
8032                                 args [i] = TypeManager.int32_type;
8033                         }
8034                         
8035                         address = mb.GetArrayMethod (
8036                                 ea.Expr.Type, "Address",
8037                                 CallingConventions.HasThis |
8038                                 CallingConventions.Standard,
8039                                 ret_type, args);
8040
8041                         return address;
8042                 }
8043
8044                 //
8045                 // Load the array arguments into the stack.
8046                 //
8047                 // If we have been requested to cache the values (cached_locations array
8048                 // initialized), then load the arguments the first time and store them
8049                 // in locals.  otherwise load from local variables.
8050                 //
8051                 void LoadArrayAndArguments (EmitContext ec)
8052                 {
8053                         ILGenerator ig = ec.ig;
8054                         
8055                         if (cached_locations == null){
8056                                 ea.Expr.Emit (ec);
8057                                 foreach (Argument a in ea.Arguments){
8058                                         Type argtype = a.Expr.Type;
8059                                         
8060                                         a.Expr.Emit (ec);
8061                                         
8062                                         if (argtype == TypeManager.int64_type)
8063                                                 ig.Emit (OpCodes.Conv_Ovf_I);
8064                                         else if (argtype == TypeManager.uint64_type)
8065                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
8066                                 }
8067                                 return;
8068                         }
8069
8070                         if (cached_locations [0] == null){
8071                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
8072                                 ea.Expr.Emit (ec);
8073                                 ig.Emit (OpCodes.Dup);
8074                                 cached_locations [0].Store (ec);
8075                                 
8076                                 int j = 1;
8077                                 
8078                                 foreach (Argument a in ea.Arguments){
8079                                         Type argtype = a.Expr.Type;
8080                                         
8081                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
8082                                         a.Expr.Emit (ec);
8083                                         if (argtype == TypeManager.int64_type)
8084                                                 ig.Emit (OpCodes.Conv_Ovf_I);
8085                                         else if (argtype == TypeManager.uint64_type)
8086                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
8087
8088                                         ig.Emit (OpCodes.Dup);
8089                                         cached_locations [j].Store (ec);
8090                                         j++;
8091                                 }
8092                                 return;
8093                         }
8094
8095                         foreach (LocalTemporary lt in cached_locations)
8096                                 lt.Emit (ec);
8097                 }
8098
8099                 public new void CacheTemporaries (EmitContext ec)
8100                 {
8101                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
8102                 }
8103                 
8104                 public override void Emit (EmitContext ec)
8105                 {
8106                         int rank = ea.Expr.Type.GetArrayRank ();
8107                         ILGenerator ig = ec.ig;
8108
8109                         LoadArrayAndArguments (ec);
8110                         
8111                         if (rank == 1)
8112                                 EmitLoadOpcode (ig, type);
8113                         else {
8114                                 MethodInfo method;
8115                                 
8116                                 method = FetchGetMethod ();
8117                                 ig.Emit (OpCodes.Call, method);
8118                         }
8119                 }
8120
8121                 public void EmitAssign (EmitContext ec, Expression source)
8122                 {
8123                         int rank = ea.Expr.Type.GetArrayRank ();
8124                         ILGenerator ig = ec.ig;
8125                         Type t = source.Type;
8126
8127                         LoadArrayAndArguments (ec);
8128
8129                         //
8130                         // The stobj opcode used by value types will need
8131                         // an address on the stack, not really an array/array
8132                         // pair
8133                         //
8134                         if (rank == 1){
8135                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
8136                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
8137                                         ig.Emit (OpCodes.Ldelema, t);
8138                         }
8139                         
8140                         source.Emit (ec);
8141
8142                         if (rank == 1)
8143                                 EmitStoreOpcode (ig, t);
8144                         else {
8145                                 ModuleBuilder mb = CodeGen.Module.Builder;
8146                                 int arg_count = ea.Arguments.Count;
8147                                 Type [] args = new Type [arg_count + 1];
8148                                 MethodInfo set;
8149                                 
8150                                 for (int i = 0; i < arg_count; i++){
8151                                         //args [i++] = a.Type;
8152                                         args [i] = TypeManager.int32_type;
8153                                 }
8154
8155                                 args [arg_count] = type;
8156                                 
8157                                 set = mb.GetArrayMethod (
8158                                         ea.Expr.Type, "Set",
8159                                         CallingConventions.HasThis |
8160                                         CallingConventions.Standard,
8161                                         TypeManager.void_type, args);
8162                                 
8163                                 ig.Emit (OpCodes.Call, set);
8164                         }
8165                 }
8166
8167                 public void AddressOf (EmitContext ec, AddressOp mode)
8168                 {
8169                         int rank = ea.Expr.Type.GetArrayRank ();
8170                         ILGenerator ig = ec.ig;
8171
8172                         LoadArrayAndArguments (ec);
8173
8174                         if (rank == 1){
8175                                 ig.Emit (OpCodes.Ldelema, type);
8176                         } else {
8177                                 MethodInfo address = FetchAddressMethod ();
8178                                 ig.Emit (OpCodes.Call, address);
8179                         }
8180                 }
8181         }
8182
8183         
8184         class Indexers {
8185                 public ArrayList Properties;
8186                 static Hashtable map;
8187
8188                 public struct Indexer {
8189                         public readonly Type Type;
8190                         public readonly MethodInfo Getter, Setter;
8191
8192                         public Indexer (Type type, MethodInfo get, MethodInfo set)
8193                         {
8194                                 this.Type = type;
8195                                 this.Getter = get;
8196                                 this.Setter = set;
8197                         }
8198                 }
8199
8200                 static Indexers ()
8201                 {
8202                         map = new Hashtable ();
8203                 }
8204
8205                 Indexers ()
8206                 {
8207                         Properties = new ArrayList ();
8208                 }
8209                                 
8210                 void Append (MemberInfo [] mi)
8211                 {
8212                         foreach (PropertyInfo property in mi){
8213                                 MethodInfo get, set;
8214                                 
8215                                 get = property.GetGetMethod (true);
8216                                 set = property.GetSetMethod (true);
8217                                 Properties.Add (new Indexer (property.PropertyType, get, set));
8218                         }
8219                 }
8220
8221                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8222                 {
8223                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8224
8225                         MemberInfo [] mi = TypeManager.MemberLookup (
8226                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8227                                 BindingFlags.Public | BindingFlags.Instance |
8228                                 BindingFlags.DeclaredOnly, p_name, null);
8229
8230                         if (mi == null || mi.Length == 0)
8231                                 return null;
8232
8233                         return mi;
8234                 }
8235                 
8236                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8237                 {
8238                         Indexers ix = (Indexers) map [lookup_type];
8239
8240                         if (ix != null)
8241                                 return ix;
8242
8243                         Type copy = lookup_type;
8244                         while (copy != TypeManager.object_type && copy != null){
8245                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8246
8247                                 if (mi != null){
8248                                         if (ix == null)
8249                                                 ix = new Indexers ();
8250
8251                                         ix.Append (mi);
8252                                 }
8253                                         
8254                                 copy = copy.BaseType;
8255                         }
8256
8257                         if (!lookup_type.IsInterface)
8258                                 return ix;
8259
8260                         TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
8261                         if (ifaces != null) {
8262                                 foreach (TypeExpr iface in ifaces) {
8263                                         Type itype = iface.Type;
8264                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8265                                         if (mi != null){
8266                                                 if (ix == null)
8267                                                         ix = new Indexers ();
8268                                         
8269                                                 ix.Append (mi);
8270                                         }
8271                                 }
8272                         }
8273
8274                         return ix;
8275                 }
8276         }
8277
8278         /// <summary>
8279         ///   Expressions that represent an indexer call.
8280         /// </summary>
8281         public class IndexerAccess : Expression, IAssignMethod {
8282                 //
8283                 // Points to our "data" repository
8284                 //
8285                 MethodInfo get, set;
8286                 ArrayList set_arguments;
8287                 bool is_base_indexer;
8288
8289                 protected Type indexer_type;
8290                 protected Type current_type;
8291                 protected Expression instance_expr;
8292                 protected ArrayList arguments;
8293                 
8294                 public IndexerAccess (ElementAccess ea, Location loc)
8295                         : this (ea.Expr, false, loc)
8296                 {
8297                         this.arguments = ea.Arguments;
8298                 }
8299
8300                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8301                                          Location loc)
8302                 {
8303                         this.instance_expr = instance_expr;
8304                         this.is_base_indexer = is_base_indexer;
8305                         this.eclass = ExprClass.Value;
8306                         this.loc = loc;
8307                 }
8308
8309                 protected virtual bool CommonResolve (EmitContext ec)
8310                 {
8311                         indexer_type = instance_expr.Type;
8312                         current_type = ec.ContainerType;
8313
8314                         return true;
8315                 }
8316
8317                 public override Expression DoResolve (EmitContext ec)
8318                 {
8319                         ArrayList AllGetters = new ArrayList();
8320                         if (!CommonResolve (ec))
8321                                 return null;
8322
8323                         //
8324                         // Step 1: Query for all `Item' *properties*.  Notice
8325                         // that the actual methods are pointed from here.
8326                         //
8327                         // This is a group of properties, piles of them.  
8328
8329                         bool found_any = false, found_any_getters = false;
8330                         Type lookup_type = indexer_type;
8331
8332                         Indexers ilist;
8333                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8334                         if (ilist != null) {
8335                                 found_any = true;
8336                                 if (ilist.Properties != null) {
8337                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8338                                                 if (ix.Getter != null)
8339                                                         AllGetters.Add(ix.Getter);
8340                                         }
8341                                 }
8342                         }
8343
8344                         if (AllGetters.Count > 0) {
8345                                 found_any_getters = true;
8346                                 get = (MethodInfo) Invocation.OverloadResolve (
8347                                         ec, new MethodGroupExpr (AllGetters, loc),
8348                                         arguments, false, loc);
8349                         }
8350
8351                         if (!found_any) {
8352                                 Report.Error (21, loc,
8353                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8354                                               "' does not have any indexers defined");
8355                                 return null;
8356                         }
8357
8358                         if (!found_any_getters) {
8359                                 Error (154, "indexer can not be used in this context, because " +
8360                                        "it lacks a `get' accessor");
8361                                 return null;
8362                         }
8363
8364                         if (get == null) {
8365                                 Error (1501, "No Overload for method `this' takes `" +
8366                                        arguments.Count + "' arguments");
8367                                 return null;
8368                         }
8369
8370                         //
8371                         // Only base will allow this invocation to happen.
8372                         //
8373                         if (get.IsAbstract && this is BaseIndexerAccess){
8374                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8375                                 return null;
8376                         }
8377
8378                         type = get.ReturnType;
8379                         if (type.IsPointer && !ec.InUnsafe){
8380                                 UnsafeError (loc);
8381                                 return null;
8382                         }
8383                         
8384                         eclass = ExprClass.IndexerAccess;
8385                         return this;
8386                 }
8387
8388                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8389                 {
8390                         ArrayList AllSetters = new ArrayList();
8391                         if (!CommonResolve (ec))
8392                                 return null;
8393
8394                         bool found_any = false, found_any_setters = false;
8395
8396                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8397                         if (ilist != null) {
8398                                 found_any = true;
8399                                 if (ilist.Properties != null) {
8400                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8401                                                 if (ix.Setter != null)
8402                                                         AllSetters.Add(ix.Setter);
8403                                         }
8404                                 }
8405                         }
8406                         if (AllSetters.Count > 0) {
8407                                 found_any_setters = true;
8408                                 set_arguments = (ArrayList) arguments.Clone ();
8409                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8410                                 set = (MethodInfo) Invocation.OverloadResolve (
8411                                         ec, new MethodGroupExpr (AllSetters, loc),
8412                                         set_arguments, false, loc);
8413                         }
8414
8415                         if (!found_any) {
8416                                 Report.Error (21, loc,
8417                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8418                                               "' does not have any indexers defined");
8419                                 return null;
8420                         }
8421
8422                         if (!found_any_setters) {
8423                                 Error (154, "indexer can not be used in this context, because " +
8424                                        "it lacks a `set' accessor");
8425                                 return null;
8426                         }
8427
8428                         if (set == null) {
8429                                 Error (1501, "No Overload for method `this' takes `" +
8430                                        arguments.Count + "' arguments");
8431                                 return null;
8432                         }
8433
8434                         //
8435                         // Only base will allow this invocation to happen.
8436                         //
8437                         if (set.IsAbstract && this is BaseIndexerAccess){
8438                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8439                                 return null;
8440                         }
8441
8442                         //
8443                         // Now look for the actual match in the list of indexers to set our "return" type
8444                         //
8445                         type = TypeManager.void_type;   // default value
8446                         foreach (Indexers.Indexer ix in ilist.Properties){
8447                                 if (ix.Setter == set){
8448                                         type = ix.Type;
8449                                         break;
8450                                 }
8451                         }
8452                         
8453                         eclass = ExprClass.IndexerAccess;
8454                         return this;
8455                 }
8456                 
8457                 public override void Emit (EmitContext ec)
8458                 {
8459                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
8460                 }
8461
8462                 //
8463                 // source is ignored, because we already have a copy of it from the
8464                 // LValue resolution and we have already constructed a pre-cached
8465                 // version of the arguments (ea.set_arguments);
8466                 //
8467                 public void EmitAssign (EmitContext ec, Expression source)
8468                 {
8469                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
8470                 }
8471         }
8472
8473         /// <summary>
8474         ///   The base operator for method names
8475         /// </summary>
8476         public class BaseAccess : Expression {
8477                 string member;
8478                 
8479                 public BaseAccess (string member, Location l)
8480                 {
8481                         this.member = member;
8482                         loc = l;
8483                 }
8484
8485                 public override Expression DoResolve (EmitContext ec)
8486                 {
8487                         Expression c = CommonResolve (ec);
8488
8489                         if (c == null)
8490                                 return null;
8491
8492                         //
8493                         // MethodGroups use this opportunity to flag an error on lacking ()
8494                         //
8495                         if (!(c is MethodGroupExpr))
8496                                 return c.Resolve (ec);
8497                         return c;
8498                 }
8499
8500                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8501                 {
8502                         Expression c = CommonResolve (ec);
8503
8504                         if (c == null)
8505                                 return null;
8506
8507                         //
8508                         // MethodGroups use this opportunity to flag an error on lacking ()
8509                         //
8510                         if (! (c is MethodGroupExpr))
8511                                 return c.DoResolveLValue (ec, right_side);
8512
8513                         return c;
8514                 }
8515
8516                 Expression CommonResolve (EmitContext ec)
8517                 {
8518                         Expression member_lookup;
8519                         Type current_type = ec.ContainerType;
8520                         Type base_type = current_type.BaseType;
8521                         Expression e;
8522
8523                         if (ec.IsStatic){
8524                                 Error (1511, "Keyword base is not allowed in static method");
8525                                 return null;
8526                         }
8527
8528                         if (ec.IsFieldInitializer){
8529                                 Error (1512, "Keyword base is not available in the current context");
8530                                 return null;
8531                         }
8532                         
8533                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
8534                                                       member, AllMemberTypes, AllBindingFlags,
8535                                                       loc);
8536                         if (member_lookup == null) {
8537                                 MemberLookupFailed (
8538                                         ec, base_type, base_type, member, null, loc);
8539                                 return null;
8540                         }
8541
8542                         Expression left;
8543                         
8544                         if (ec.IsStatic)
8545                                 left = new TypeExpression (base_type, loc);
8546                         else
8547                                 left = ec.GetThis (loc);
8548                         
8549                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8550
8551                         if (e is PropertyExpr){
8552                                 PropertyExpr pe = (PropertyExpr) e;
8553
8554                                 pe.IsBase = true;
8555                         }
8556
8557                         return e;
8558                 }
8559
8560                 public override void Emit (EmitContext ec)
8561                 {
8562                         throw new Exception ("Should never be called"); 
8563                 }
8564         }
8565
8566         /// <summary>
8567         ///   The base indexer operator
8568         /// </summary>
8569         public class BaseIndexerAccess : IndexerAccess {
8570                 public BaseIndexerAccess (ArrayList args, Location loc)
8571                         : base (null, true, loc)
8572                 {
8573                         arguments = new ArrayList ();
8574                         foreach (Expression tmp in args)
8575                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8576                 }
8577
8578                 protected override bool CommonResolve (EmitContext ec)
8579                 {
8580                         instance_expr = ec.GetThis (loc);
8581
8582                         current_type = ec.ContainerType.BaseType;
8583                         indexer_type = current_type;
8584
8585                         foreach (Argument a in arguments){
8586                                 if (!a.Resolve (ec, loc))
8587                                         return false;
8588                         }
8589
8590                         return true;
8591                 }
8592         }
8593         
8594         /// <summary>
8595         ///   This class exists solely to pass the Type around and to be a dummy
8596         ///   that can be passed to the conversion functions (this is used by
8597         ///   foreach implementation to typecast the object return value from
8598         ///   get_Current into the proper type.  All code has been generated and
8599         ///   we only care about the side effect conversions to be performed
8600         ///
8601         ///   This is also now used as a placeholder where a no-action expression
8602         ///   is needed (the `New' class).
8603         /// </summary>
8604         public class EmptyExpression : Expression {
8605                 public EmptyExpression ()
8606                 {
8607                         type = TypeManager.object_type;
8608                         eclass = ExprClass.Value;
8609                         loc = Location.Null;
8610                 }
8611
8612                 public EmptyExpression (Type t)
8613                 {
8614                         type = t;
8615                         eclass = ExprClass.Value;
8616                         loc = Location.Null;
8617                 }
8618                 
8619                 public override Expression DoResolve (EmitContext ec)
8620                 {
8621                         return this;
8622                 }
8623
8624                 public override void Emit (EmitContext ec)
8625                 {
8626                         // nothing, as we only exist to not do anything.
8627                 }
8628
8629                 //
8630                 // This is just because we might want to reuse this bad boy
8631                 // instead of creating gazillions of EmptyExpressions.
8632                 // (CanImplicitConversion uses it)
8633                 //
8634                 public void SetType (Type t)
8635                 {
8636                         type = t;
8637                 }
8638         }
8639
8640         public class UserCast : Expression {
8641                 MethodBase method;
8642                 Expression source;
8643                 
8644                 public UserCast (MethodInfo method, Expression source, Location l)
8645                 {
8646                         this.method = method;
8647                         this.source = source;
8648                         type = method.ReturnType;
8649                         eclass = ExprClass.Value;
8650                         loc = l;
8651                 }
8652
8653                 public override Expression DoResolve (EmitContext ec)
8654                 {
8655                         //
8656                         // We are born fully resolved
8657                         //
8658                         return this;
8659                 }
8660
8661                 public override void Emit (EmitContext ec)
8662                 {
8663                         ILGenerator ig = ec.ig;
8664
8665                         source.Emit (ec);
8666                         
8667                         if (method is MethodInfo)
8668                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8669                         else
8670                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8671
8672                 }
8673         }
8674
8675         // <summary>
8676         //   This class is used to "construct" the type during a typecast
8677         //   operation.  Since the Type.GetType class in .NET can parse
8678         //   the type specification, we just use this to construct the type
8679         //   one bit at a time.
8680         // </summary>
8681         public class ComposedCast : TypeExpr {
8682                 Expression left;
8683                 string dim;
8684                 
8685                 public ComposedCast (Expression left, string dim, Location l)
8686                 {
8687                         this.left = left;
8688                         this.dim = dim;
8689                         loc = l;
8690                 }
8691
8692                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8693                 {
8694                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
8695                         if (ltype == null)
8696                                 return null;
8697
8698                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8699                                 Report.Error (1547, Location,
8700                                               "Keyword 'void' cannot be used in this context");
8701                                 return null;
8702                         }
8703
8704                         int pos = 0;
8705                         while ((pos < dim.Length) && (dim [pos] == '[')) {
8706                                 pos++;
8707
8708                                 if (dim [pos] == ']') {
8709                                         ltype = ltype.MakeArrayType ();
8710                                         pos++;
8711
8712                                         if (pos < dim.Length)
8713                                                 continue;
8714
8715                                         type = ltype;
8716                                         eclass = ExprClass.Type;
8717                                         return this;
8718                                 }
8719
8720                                 int rank = 0;
8721                                 while (dim [pos] == ',') {
8722                                         pos++; rank++;
8723                                 }
8724
8725                                 if ((dim [pos] != ']') || (pos != dim.Length-1))
8726                                         return null;
8727                                                 
8728                                 type = ltype.MakeArrayType (rank + 1);
8729                                 eclass = ExprClass.Type;
8730                                 return this;
8731                         }
8732
8733                         //
8734                         // ltype.Fullname is already fully qualified, so we can skip
8735                         // a lot of probes, and go directly to TypeManager.LookupType
8736                         //
8737                         string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
8738                         string cname = fname + dim;
8739                         type = TypeManager.LookupTypeDirect (cname);
8740                         if (type == null){
8741                                 //
8742                                 // For arrays of enumerations we are having a problem
8743                                 // with the direct lookup.  Need to investigate.
8744                                 //
8745                                 // For now, fall back to the full lookup in that case.
8746                                 //
8747                                 TypeExpr texpr = RootContext.LookupType (
8748                                         ec.DeclSpace, cname, false, loc);
8749
8750                                 if (texpr == null)
8751                                         return null;
8752
8753                                 type = texpr.ResolveType (ec);
8754                                 if (type == null)
8755                                         return null;
8756                         }
8757
8758                         if (!ec.ResolvingTypeTree){
8759                                 //
8760                                 // If the above flag is set, this is being invoked from the ResolveType function.
8761                                 // Upper layers take care of the type validity in this context.
8762                                 //
8763                         if (!ec.InUnsafe && type.IsPointer){
8764                                 UnsafeError (loc);
8765                                 return null;
8766                         }
8767                         }
8768                         
8769                         eclass = ExprClass.Type;
8770                         return this;
8771                 }
8772
8773                 public override string Name {
8774                         get {
8775                                 return left + dim;
8776                         }
8777                 }
8778         }
8779
8780         //
8781         // This class is used to represent the address of an array, used
8782         // only by the Fixed statement, this is like the C "&a [0]" construct.
8783         //
8784         public class ArrayPtr : Expression {
8785                 Expression array;
8786                 
8787                 public ArrayPtr (Expression array, Location l)
8788                 {
8789                         Type array_type = TypeManager.GetElementType (array.Type);
8790
8791                         this.array = array;
8792
8793                         type = TypeManager.GetPointerType (array_type);
8794                         eclass = ExprClass.Value;
8795                         loc = l;
8796                 }
8797
8798                 public override void Emit (EmitContext ec)
8799                 {
8800                         ILGenerator ig = ec.ig;
8801                         
8802                         array.Emit (ec);
8803                         IntLiteral.EmitInt (ig, 0);
8804                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8805                 }
8806
8807                 public override Expression DoResolve (EmitContext ec)
8808                 {
8809                         //
8810                         // We are born fully resolved
8811                         //
8812                         return this;
8813                 }
8814         }
8815
8816         //
8817         // Used by the fixed statement
8818         //
8819         public class StringPtr : Expression {
8820                 LocalBuilder b;
8821                 
8822                 public StringPtr (LocalBuilder b, Location l)
8823                 {
8824                         this.b = b;
8825                         eclass = ExprClass.Value;
8826                         type = TypeManager.char_ptr_type;
8827                         loc = l;
8828                 }
8829
8830                 public override Expression DoResolve (EmitContext ec)
8831                 {
8832                         // This should never be invoked, we are born in fully
8833                         // initialized state.
8834
8835                         return this;
8836                 }
8837
8838                 public override void Emit (EmitContext ec)
8839                 {
8840                         ILGenerator ig = ec.ig;
8841
8842                         ig.Emit (OpCodes.Ldloc, b);
8843                         ig.Emit (OpCodes.Conv_I);
8844                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8845                         ig.Emit (OpCodes.Add);
8846                 }
8847         }
8848         
8849         //
8850         // Implements the `stackalloc' keyword
8851         //
8852         public class StackAlloc : Expression {
8853                 Type otype;
8854                 Expression t;
8855                 Expression count;
8856                 
8857                 public StackAlloc (Expression type, Expression count, Location l)
8858                 {
8859                         t = type;
8860                         this.count = count;
8861                         loc = l;
8862                 }
8863
8864                 public override Expression DoResolve (EmitContext ec)
8865                 {
8866                         count = count.Resolve (ec);
8867                         if (count == null)
8868                                 return null;
8869                         
8870                         if (count.Type != TypeManager.int32_type){
8871                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8872                                 if (count == null)
8873                                         return null;
8874                         }
8875
8876                         if (ec.CurrentBranching.InCatch () ||
8877                             ec.CurrentBranching.InFinally (true)) {
8878                                 Error (255,
8879                                               "stackalloc can not be used in a catch or finally block");
8880                                 return null;
8881                         }
8882
8883                         otype = ec.DeclSpace.ResolveType (t, false, loc);
8884
8885                         if (otype == null)
8886                                 return null;
8887
8888                         if (!TypeManager.VerifyUnManaged (otype, loc))
8889                                 return null;
8890
8891                         type = TypeManager.GetPointerType (otype);
8892                         eclass = ExprClass.Value;
8893
8894                         return this;
8895                 }
8896
8897                 public override void Emit (EmitContext ec)
8898                 {
8899                         int size = GetTypeSize (otype);
8900                         ILGenerator ig = ec.ig;
8901                                 
8902                         if (size == 0)
8903                                 ig.Emit (OpCodes.Sizeof, otype);
8904                         else
8905                                 IntConstant.EmitInt (ig, size);
8906                         count.Emit (ec);
8907                         ig.Emit (OpCodes.Mul);
8908                         ig.Emit (OpCodes.Localloc);
8909                 }
8910         }
8911 }