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