2004-07-13 Martin Baulig <martin@ximian.com>
[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                                 else {
2143                                         left = ForceConversion (ec, left, TypeManager.uint64_type);
2144                                         right = ForceConversion (ec, right, TypeManager.uint64_type);
2145                                 }
2146                                 type = TypeManager.uint64_type;
2147                         } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2148                                 //
2149                                 // If either operand is of type long, the other operand is converted
2150                                 // to type long.
2151                                 //
2152                                 if (l != TypeManager.int64_type)
2153                                         left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2154                                 if (r != TypeManager.int64_type)
2155                                         right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2156                                 
2157                                 type = TypeManager.int64_type;
2158                         } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2159                                 //
2160                                 // If either operand is of type uint, and the other
2161                                 // operand is of type sbyte, short or int, othe operands are
2162                                 // converted to type long (unless we have an int constant).
2163                                 //
2164                                 Type other = null;
2165                                 
2166                                 if (l == TypeManager.uint32_type){
2167                                         if (right is IntConstant){
2168                                                 IntConstant ic = (IntConstant) right;
2169                                                 int val = ic.Value;
2170                                                 
2171                                                 if (val >= 0){
2172                                                         right = new UIntConstant ((uint) val);
2173                                                         type = l;
2174                                                         
2175                                                         return true;
2176                                                 }
2177                                         }
2178                                         other = r;
2179                                 } else if (r == TypeManager.uint32_type){
2180                                         if (left is IntConstant){
2181                                                 IntConstant ic = (IntConstant) left;
2182                                                 int val = ic.Value;
2183                                                 
2184                                                 if (val >= 0){
2185                                                         left = new UIntConstant ((uint) val);
2186                                                         type = r;
2187                                                         return true;
2188                                                 }
2189                                         }
2190                                         
2191                                         other = l;
2192                                 }
2193
2194                                 if ((other == TypeManager.sbyte_type) ||
2195                                     (other == TypeManager.short_type) ||
2196                                     (other == TypeManager.int32_type)){
2197                                         left = ForceConversion (ec, left, TypeManager.int64_type);
2198                                         right = ForceConversion (ec, right, TypeManager.int64_type);
2199                                         type = TypeManager.int64_type;
2200                                 } else {
2201                                         //
2202                                         // if either operand is of type uint, the other
2203                                         // operand is converd to type uint
2204                                         //
2205                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
2206                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
2207                                         type = TypeManager.uint32_type;
2208                                 } 
2209                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2210                                 if (l != TypeManager.decimal_type)
2211                                         left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2212
2213                                 if (r != TypeManager.decimal_type)
2214                                         right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2215                                 type = TypeManager.decimal_type;
2216                         } else {
2217                                 left = ForceConversion (ec, left, TypeManager.int32_type);
2218                                 right = ForceConversion (ec, right, TypeManager.int32_type);
2219
2220                                 type = TypeManager.int32_type;
2221                         }
2222
2223                         return (left != null) && (right != null);
2224                 }
2225
2226                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2227                 {
2228                         Report.Error (19, loc,
2229                                "Operator " + name + " cannot be applied to operands of type `" +
2230                                TypeManager.CSharpName (l) + "' and `" +
2231                                TypeManager.CSharpName (r) + "'");
2232                 }
2233                 
2234                 void Error_OperatorCannotBeApplied ()
2235                 {
2236                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2237                 }
2238
2239                 static bool is_unsigned (Type t)
2240                 {
2241                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2242                                 t == TypeManager.short_type || t == TypeManager.byte_type);
2243                 }
2244
2245                 static bool is_user_defined (Type t)
2246                 {
2247                         if (t.IsSubclassOf (TypeManager.value_type) &&
2248                             (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2249                                 return true;
2250                         else
2251                                 return false;
2252                 }
2253
2254                 Expression Make32or64 (EmitContext ec, Expression e)
2255                 {
2256                         Type t= e.Type;
2257                         
2258                         if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2259                             t == TypeManager.int64_type || t == TypeManager.uint64_type)
2260                                 return e;
2261                         Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
2262                         if (ee != null)
2263                                 return ee;
2264                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
2265                         if (ee != null)
2266                                 return ee;
2267                         ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
2268                         if (ee != null)
2269                                 return ee;
2270                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
2271                         if (ee != null)
2272                                 return ee;
2273                         return null;
2274                 }
2275                                         
2276                 Expression CheckShiftArguments (EmitContext ec)
2277                 {
2278                         Expression e;
2279
2280                         e = ForceConversion (ec, right, TypeManager.int32_type);
2281                         if (e == null){
2282                                 Error_OperatorCannotBeApplied ();
2283                                 return null;
2284                         }
2285                         right = e;
2286
2287                         if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2288                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2289                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2290                             ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2291                                 left = e;
2292                                 type = e.Type;
2293
2294                                 if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
2295                                         right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31), loc);
2296                                         right = right.DoResolve (ec);
2297                                 } else {
2298                                         right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc);
2299                                         right = right.DoResolve (ec);
2300                                 }
2301
2302                                 return this;
2303                         }
2304                         Error_OperatorCannotBeApplied ();
2305                         return null;
2306                 }
2307
2308                 Expression ResolveOperator (EmitContext ec)
2309                 {
2310                         Type l = left.Type;
2311                         Type r = right.Type;
2312
2313                         bool overload_failed = false;
2314
2315                         //
2316                         // Special cases: string or type parameter comapred to null
2317                         //
2318                         if (oper == Operator.Equality || oper == Operator.Inequality){
2319                                 if ((l == TypeManager.string_type && (right is NullLiteral)) ||
2320                                     (r == TypeManager.string_type && (left is NullLiteral))){
2321                                         Type = TypeManager.bool_type;
2322                                         
2323                                         return this;
2324                                 }
2325
2326                                 if (l.IsGenericParameter && (right is NullLiteral)) {
2327                                         if (l.BaseType == TypeManager.value_type) {
2328                                                 Error_OperatorCannotBeApplied ();
2329                                                 return null;
2330                                         }
2331
2332                                         left = new BoxedCast (left);
2333                                         Type = TypeManager.bool_type;
2334                                         return this;
2335                                 }
2336
2337                                 if (r.IsGenericParameter && (left is NullLiteral)) {
2338                                         if (r.BaseType == TypeManager.value_type) {
2339                                                 Error_OperatorCannotBeApplied ();
2340                                                 return null;
2341                                         }
2342
2343                                         right = new BoxedCast (right);
2344                                         Type = TypeManager.bool_type;
2345                                         return this;
2346                                 }
2347                                 
2348                                 // IntPtr equality
2349                                 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
2350                                         Type = TypeManager.bool_type;
2351                                         
2352                                         return this;
2353                                 }
2354                         }
2355
2356                         //
2357                         // Do not perform operator overload resolution when both sides are
2358                         // built-in types
2359                         //
2360                         if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
2361                                 //
2362                                 // Step 1: Perform Operator Overload location
2363                                 //
2364                                 Expression left_expr, right_expr;
2365                                 
2366                                 string op = oper_names [(int) oper];
2367                                 
2368                                 MethodGroupExpr union;
2369                                 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2370                                 if (r != l){
2371                                         right_expr = MemberLookup (
2372                                                 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2373                                         union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2374                                 } else
2375                                         union = (MethodGroupExpr) left_expr;
2376                                 
2377                                 if (union != null) {
2378                                         ArrayList args = new ArrayList (2);
2379                                         args.Add (new Argument (left, Argument.AType.Expression));
2380                                         args.Add (new Argument (right, Argument.AType.Expression));
2381                                         
2382                                         MethodBase method = Invocation.OverloadResolve (
2383                                                 ec, union, args, true, Location.Null);
2384
2385                                         if (method != null) {
2386                                                 MethodInfo mi = (MethodInfo) method;
2387                                                 
2388                                                 return new BinaryMethod (mi.ReturnType, method, args);
2389                                         } else {
2390                                                 overload_failed = true;
2391                                         }
2392                                 }
2393                         }
2394                         
2395                         //
2396                         // Step 0: String concatenation (because overloading will get this wrong)
2397                         //
2398                         if (oper == Operator.Addition){
2399                                 //
2400                                 // If any of the arguments is a string, cast to string
2401                                 //
2402                                 
2403                                 // Simple constant folding
2404                                 if (left is StringConstant && right is StringConstant)
2405                                         return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
2406
2407                                 if (l == TypeManager.string_type || r == TypeManager.string_type) {
2408
2409                                         if (r == TypeManager.void_type || l == TypeManager.void_type) {
2410                                                 Error_OperatorCannotBeApplied ();
2411                                                 return null;
2412                                         }
2413                                         
2414                                         // try to fold it in on the left
2415                                         if (left is StringConcat) {
2416
2417                                                 //
2418                                                 // We have to test here for not-null, since we can be doubly-resolved
2419                                                 // take care of not appending twice
2420                                                 //
2421                                                 if (type == null){
2422                                                         type = TypeManager.string_type;
2423                                                         ((StringConcat) left).Append (ec, right);
2424                                                         return left.Resolve (ec);
2425                                                 } else {
2426                                                         return left;
2427                                                 }
2428                                         }
2429
2430                                         // Otherwise, start a new concat expression
2431                                         return new StringConcat (ec, loc, left, right).Resolve (ec);
2432                                 }
2433
2434                                 //
2435                                 // Transform a + ( - b) into a - b
2436                                 //
2437                                 if (right is Unary){
2438                                         Unary right_unary = (Unary) right;
2439
2440                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
2441                                                 oper = Operator.Subtraction;
2442                                                 right = right_unary.Expr;
2443                                                 r = right.Type;
2444                                         }
2445                                 }
2446                         }
2447
2448                         if (oper == Operator.Equality || oper == Operator.Inequality){
2449                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2450                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2451                                                 Error_OperatorCannotBeApplied ();
2452                                                 return null;
2453                                         }
2454                                         
2455                                         type = TypeManager.bool_type;
2456                                         return this;
2457                                 }
2458
2459                                 //
2460                                 // operator != (object a, object b)
2461                                 // operator == (object a, object b)
2462                                 //
2463                                 // For this to be used, both arguments have to be reference-types.
2464                                 // Read the rationale on the spec (14.9.6)
2465                                 //
2466                                 // Also, if at compile time we know that the classes do not inherit
2467                                 // one from the other, then we catch the error there.
2468                                 //
2469                                 if (!(l.IsValueType || r.IsValueType)){
2470                                         type = TypeManager.bool_type;
2471
2472                                         if (l == r)
2473                                                 return this;
2474                                         
2475                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2476                                                 return this;
2477
2478                                         //
2479                                         // Also, a standard conversion must exist from either one
2480                                         //
2481                                         if (!(Convert.ImplicitStandardConversionExists (left, r) ||
2482                                               Convert.ImplicitStandardConversionExists (right, l))){
2483                                                 Error_OperatorCannotBeApplied ();
2484                                                 return null;
2485                                         }
2486                                         //
2487                                         // We are going to have to convert to an object to compare
2488                                         //
2489                                         if (l != TypeManager.object_type)
2490                                                 left = new EmptyCast (left, TypeManager.object_type);
2491                                         if (r != TypeManager.object_type)
2492                                                 right = new EmptyCast (right, TypeManager.object_type);
2493
2494                                         //
2495                                         // FIXME: CSC here catches errors cs254 and cs252
2496                                         //
2497                                         return this;
2498                                 }
2499
2500                                 //
2501                                 // One of them is a valuetype, but the other one is not.
2502                                 //
2503                                 if (!l.IsValueType || !r.IsValueType) {
2504                                         Error_OperatorCannotBeApplied ();
2505                                         return null;
2506                                 }
2507                         }
2508
2509                         // Only perform numeric promotions on:
2510                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2511                         //
2512                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2513                                 if (TypeManager.IsDelegateType (l)){
2514                                         if (right.eclass == ExprClass.MethodGroup && RootContext.V2){
2515                                                 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2516                                                 if (tmp == null)
2517                                                         return null;
2518                                                 right = tmp;
2519                                                 r = right.Type;
2520                                         }
2521                                 
2522                                         if (TypeManager.IsDelegateType (r)){
2523                                         MethodInfo method;
2524                                         ArrayList args = new ArrayList (2);
2525                                         
2526                                         args = new ArrayList (2);
2527                                         args.Add (new Argument (left, Argument.AType.Expression));
2528                                         args.Add (new Argument (right, Argument.AType.Expression));
2529                                         
2530                                         if (oper == Operator.Addition)
2531                                                 method = TypeManager.delegate_combine_delegate_delegate;
2532                                         else
2533                                                 method = TypeManager.delegate_remove_delegate_delegate;
2534
2535                                         if (l != r) {
2536                                                 Error_OperatorCannotBeApplied ();
2537                                                 return null;
2538                                         }
2539
2540                                         return new BinaryDelegate (l, method, args);
2541                                 }
2542                                 }
2543
2544                                 //
2545                                 // Pointer arithmetic:
2546                                 //
2547                                 // T* operator + (T* x, int y);
2548                                 // T* operator + (T* x, uint y);
2549                                 // T* operator + (T* x, long y);
2550                                 // T* operator + (T* x, ulong y);
2551                                 //
2552                                 // T* operator + (int y,   T* x);
2553                                 // T* operator + (uint y,  T *x);
2554                                 // T* operator + (long y,  T *x);
2555                                 // T* operator + (ulong y, T *x);
2556                                 //
2557                                 // T* operator - (T* x, int y);
2558                                 // T* operator - (T* x, uint y);
2559                                 // T* operator - (T* x, long y);
2560                                 // T* operator - (T* x, ulong y);
2561                                 //
2562                                 // long operator - (T* x, T *y)
2563                                 //
2564                                 if (l.IsPointer){
2565                                         if (r.IsPointer && oper == Operator.Subtraction){
2566                                                 if (r == l)
2567                                                         return new PointerArithmetic (
2568                                                                 false, left, right, TypeManager.int64_type,
2569                                                                 loc);
2570                                         } else {
2571                                                 Expression t = Make32or64 (ec, right);
2572                                                 if (t != null)
2573                                                         return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc);
2574                                         }
2575                                 } else if (r.IsPointer && oper == Operator.Addition){
2576                                         Expression t = Make32or64 (ec, left);
2577                                         if (t != null)
2578                                                 return new PointerArithmetic (true, right, t, r, loc);
2579                                 }
2580                         }
2581                         
2582                         //
2583                         // Enumeration operators
2584                         //
2585                         bool lie = TypeManager.IsEnumType (l);
2586                         bool rie = TypeManager.IsEnumType (r);
2587                         if (lie || rie){
2588                                 Expression temp;
2589
2590                                 // U operator - (E e, E f)
2591                                 if (lie && rie){
2592                                         if (oper == Operator.Subtraction){
2593                                         if (l == r){
2594                                                 type = TypeManager.EnumToUnderlying (l);
2595                                                 return this;
2596                                         } 
2597                                         Error_OperatorCannotBeApplied ();
2598                                         return null;
2599                                 }
2600                                 }
2601                                         
2602                                 //
2603                                 // operator + (E e, U x)
2604                                 // operator - (E e, U x)
2605                                 //
2606                                 if (oper == Operator.Addition || oper == Operator.Subtraction){
2607                                         Type enum_type = lie ? l : r;
2608                                         Type other_type = lie ? r : l;
2609                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2610                                         
2611                                         if (underlying_type != other_type){
2612                                                 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2613                                                 if (temp != null){
2614                                                         if (lie)
2615                                                                 right = temp;
2616                                                         else
2617                                                                 left = temp;
2618                                                         type = enum_type;
2619                                                         return this;
2620                                                 }
2621                                                         
2622                                                 Error_OperatorCannotBeApplied ();
2623                                                 return null;
2624                                         }
2625
2626                                         type = enum_type;
2627                                         return this;
2628                                 }
2629                                 
2630                                 if (!rie){
2631                                         temp = Convert.ImplicitConversion (ec, right, l, loc);
2632                                         if (temp != null)
2633                                                 right = temp;
2634                                         else {
2635                                                 Error_OperatorCannotBeApplied ();
2636                                                 return null;
2637                                         }
2638                                 } if (!lie){
2639                                         temp = Convert.ImplicitConversion (ec, left, r, loc);
2640                                         if (temp != null){
2641                                                 left = temp;
2642                                                 l = r;
2643                                         } else {
2644                                                 Error_OperatorCannotBeApplied ();
2645                                                 return null;
2646                                         }
2647                                 }
2648
2649                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2650                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2651                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2652                                         if (left.Type != right.Type){
2653                                                 Error_OperatorCannotBeApplied ();
2654                                                 return null;
2655                                         }
2656                                         type = TypeManager.bool_type;
2657                                         return this;
2658                                 }
2659
2660                                 if (oper == Operator.BitwiseAnd ||
2661                                     oper == Operator.BitwiseOr ||
2662                                     oper == Operator.ExclusiveOr){
2663                                         type = l;
2664                                         return this;
2665                                 }
2666                                 Error_OperatorCannotBeApplied ();
2667                                 return null;
2668                         }
2669                         
2670                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2671                                 return CheckShiftArguments (ec);
2672
2673                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2674                                 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2675                                         type = TypeManager.bool_type;
2676                                         return this;
2677                                 }
2678
2679                                 if (l != r) {
2680                                         Error_OperatorCannotBeApplied ();
2681                                         return null;
2682                                 }
2683
2684                                 Expression e = new ConditionalLogicalOperator (
2685                                         oper == Operator.LogicalAnd, left, right, l, loc);
2686                                 return e.Resolve (ec);
2687                         } 
2688
2689                         //
2690                         // operator & (bool x, bool y)
2691                         // operator | (bool x, bool y)
2692                         // operator ^ (bool x, bool y)
2693                         //
2694                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2695                                 if (oper == Operator.BitwiseAnd ||
2696                                     oper == Operator.BitwiseOr ||
2697                                     oper == Operator.ExclusiveOr){
2698                                         type = l;
2699                                         return this;
2700                                 }
2701                         }
2702                         
2703                         //
2704                         // Pointer comparison
2705                         //
2706                         if (l.IsPointer && r.IsPointer){
2707                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2708                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2709                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2710                                         type = TypeManager.bool_type;
2711                                         return this;
2712                                 }
2713                         }
2714                         
2715                         //
2716                         // We are dealing with numbers
2717                         //
2718                         if (overload_failed){
2719                                 Error_OperatorCannotBeApplied ();
2720                                 return null;
2721                         }
2722
2723                         //
2724                         // This will leave left or right set to null if there is an error
2725                         //
2726                         bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2727                         DoNumericPromotions (ec, l, r, check_user_conv);
2728                         if (left == null || right == null){
2729                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2730                                 return null;
2731                         }
2732
2733                         //
2734                         // reload our cached types if required
2735                         //
2736                         l = left.Type;
2737                         r = right.Type;
2738                         
2739                         if (oper == Operator.BitwiseAnd ||
2740                             oper == Operator.BitwiseOr ||
2741                             oper == Operator.ExclusiveOr){
2742                                 if (l == r){
2743                                         if (((l == TypeManager.int32_type) ||
2744                                              (l == TypeManager.uint32_type) ||
2745                                              (l == TypeManager.short_type) ||
2746                                              (l == TypeManager.ushort_type) ||
2747                                              (l == TypeManager.int64_type) ||
2748                                              (l == TypeManager.uint64_type))){
2749                                                 type = l;
2750                                         } else {
2751                                                 Error_OperatorCannotBeApplied ();
2752                                                 return null;
2753                                         }
2754                                 } else {
2755                                         Error_OperatorCannotBeApplied ();
2756                                         return null;
2757                                 }
2758                         }
2759
2760                         if (oper == Operator.Equality ||
2761                             oper == Operator.Inequality ||
2762                             oper == Operator.LessThanOrEqual ||
2763                             oper == Operator.LessThan ||
2764                             oper == Operator.GreaterThanOrEqual ||
2765                             oper == Operator.GreaterThan){
2766                                 type = TypeManager.bool_type;
2767                         }
2768
2769                         return this;
2770                 }
2771
2772                 public override Expression DoResolve (EmitContext ec)
2773                 {
2774                         if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2775                                 left = ((ParenthesizedExpression) left).Expr;
2776                                 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2777                                 if (left == null)
2778                                         return null;
2779
2780                                 if (left.eclass == ExprClass.Type) {
2781                                         Error (75, "Casting a negative value needs to have the value in parentheses.");
2782                                         return null;
2783                                 }
2784                         } else
2785                                 left = left.Resolve (ec);
2786                         right = right.Resolve (ec);
2787
2788                         if (left == null || right == null)
2789                                 return null;
2790
2791                         eclass = ExprClass.Value;
2792
2793                         Constant rc = right as Constant;
2794                         Constant lc = left as Constant;
2795
2796                         if (rc != null & lc != null){
2797                                 Expression e = ConstantFold.BinaryFold (
2798                                         ec, oper, lc, rc, loc);
2799                                         if (e != null)
2800                                                 return e;
2801                         }
2802
2803                         return ResolveOperator (ec);
2804                 }
2805
2806                 /// <remarks>
2807                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2808                 ///   context of a conditional bool expression.  This function will return
2809                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2810                 ///
2811                 ///   The expression's code is generated, and we will generate a branch to `target'
2812                 ///   if the resulting expression value is equal to isTrue
2813                 /// </remarks>
2814                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2815                 {
2816                         ILGenerator ig = ec.ig;
2817
2818                         //
2819                         // This is more complicated than it looks, but its just to avoid
2820                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2821                         // but on top of that we want for == and != to use a special path
2822                         // if we are comparing against null
2823                         //
2824                         if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2825                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2826
2827                                 //
2828                                 // put the constant on the rhs, for simplicity
2829                                 //
2830                                 if (left is Constant) {
2831                                         Expression swap = right;
2832                                         right = left;
2833                                         left = swap;
2834                                 }
2835                                         
2836                                 if (((Constant) right).IsZeroInteger) {
2837                                         left.Emit (ec);
2838                                         if (my_on_true)
2839                                                 ig.Emit (OpCodes.Brtrue, target);
2840                                         else
2841                                                 ig.Emit (OpCodes.Brfalse, target);
2842                                         
2843                                         return;
2844                                 } else if (right is BoolConstant){
2845                                         left.Emit (ec);
2846                                         if (my_on_true != ((BoolConstant) right).Value)
2847                                                 ig.Emit (OpCodes.Brtrue, target);
2848                                         else
2849                                                 ig.Emit (OpCodes.Brfalse, target);
2850                                         
2851                                         return;
2852                                 }
2853
2854                         } else if (oper == Operator.LogicalAnd) {
2855
2856                                 if (onTrue) {
2857                                                 Label tests_end = ig.DefineLabel ();
2858                                                 
2859                                         left.EmitBranchable (ec, tests_end, false);
2860                                         right.EmitBranchable (ec, target, true);
2861                                                         ig.MarkLabel (tests_end);
2862                                         } else {
2863                                         left.EmitBranchable (ec, target, false);
2864                                         right.EmitBranchable (ec, target, false);
2865                                         }
2866
2867                                 return;
2868                                                                 
2869                         } else if (oper == Operator.LogicalOr){
2870                                 if (onTrue) {
2871                                         left.EmitBranchable (ec, target, true);
2872                                         right.EmitBranchable (ec, target, true);
2873                                                 
2874                                         } else {
2875                                                 Label tests_end = ig.DefineLabel ();
2876                                         left.EmitBranchable (ec, tests_end, true);
2877                                         right.EmitBranchable (ec, target, false);
2878                                         ig.MarkLabel (tests_end);
2879                                 }
2880                                                 
2881                                 return;
2882
2883                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
2884                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2885                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
2886                                 base.EmitBranchable (ec, target, onTrue);
2887                                 return;
2888                                 }
2889                                 
2890                         left.Emit (ec);
2891                         right.Emit (ec);
2892
2893                         Type t = left.Type;
2894                         bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2895
2896                         switch (oper){
2897                         case Operator.Equality:
2898                                 if (onTrue)
2899                                         ig.Emit (OpCodes.Beq, target);
2900                                 else
2901                                         ig.Emit (OpCodes.Bne_Un, target);
2902                                 break;
2903
2904                         case Operator.Inequality:
2905                                 if (onTrue)
2906                                         ig.Emit (OpCodes.Bne_Un, target);
2907                                 else
2908                                         ig.Emit (OpCodes.Beq, target);
2909                                 break;
2910
2911                         case Operator.LessThan:
2912                                 if (onTrue)
2913                                         if (isUnsigned)
2914                                                 ig.Emit (OpCodes.Blt_Un, target);
2915                                         else
2916                                                 ig.Emit (OpCodes.Blt, target);
2917                                 else
2918                                         if (isUnsigned)
2919                                                 ig.Emit (OpCodes.Bge_Un, target);
2920                                         else
2921                                                 ig.Emit (OpCodes.Bge, target);
2922                                 break;
2923
2924                         case Operator.GreaterThan:
2925                                 if (onTrue)
2926                                         if (isUnsigned)
2927                                                 ig.Emit (OpCodes.Bgt_Un, target);
2928                                         else
2929                                                 ig.Emit (OpCodes.Bgt, target);
2930                                 else
2931                                         if (isUnsigned)
2932                                                 ig.Emit (OpCodes.Ble_Un, target);
2933                                         else
2934                                                 ig.Emit (OpCodes.Ble, target);
2935                                 break;
2936
2937                         case Operator.LessThanOrEqual:
2938                                 if (onTrue)
2939                                         if (isUnsigned)
2940                                                 ig.Emit (OpCodes.Ble_Un, target);
2941                                         else
2942                                                 ig.Emit (OpCodes.Ble, target);
2943                                 else
2944                                         if (isUnsigned)
2945                                                 ig.Emit (OpCodes.Bgt_Un, target);
2946                                         else
2947                                                 ig.Emit (OpCodes.Bgt, target);
2948                                 break;
2949
2950
2951                         case Operator.GreaterThanOrEqual:
2952                                 if (onTrue)
2953                                         if (isUnsigned)
2954                                                 ig.Emit (OpCodes.Bge_Un, target);
2955                                         else
2956                                                 ig.Emit (OpCodes.Bge, target);
2957                                 else
2958                                         if (isUnsigned)
2959                                                 ig.Emit (OpCodes.Blt_Un, target);
2960                                         else
2961                                                 ig.Emit (OpCodes.Blt, target);
2962                                 break;
2963                         default:
2964                                 Console.WriteLine (oper);
2965                                 throw new Exception ("what is THAT");
2966                         }
2967                 }
2968                 
2969                 public override void Emit (EmitContext ec)
2970                 {
2971                         ILGenerator ig = ec.ig;
2972                         Type l = left.Type;
2973                         OpCode opcode;
2974
2975                         //
2976                         // Handle short-circuit operators differently
2977                         // than the rest
2978                         //
2979                         if (oper == Operator.LogicalAnd) {
2980                                 Label load_zero = ig.DefineLabel ();
2981                                 Label end = ig.DefineLabel ();
2982
2983                                 left.EmitBranchable (ec, load_zero, false);
2984                                                 right.Emit (ec);
2985                                                 ig.Emit (OpCodes.Br, end);
2986
2987                                 ig.MarkLabel (load_zero);
2988                                 ig.Emit (OpCodes.Ldc_I4_0);
2989                                 ig.MarkLabel (end);
2990                                 return;
2991                         } else if (oper == Operator.LogicalOr) {
2992                                 Label load_one = ig.DefineLabel ();
2993                                 Label end = ig.DefineLabel ();
2994                                 
2995                                 left.EmitBranchable (ec, load_one, true);
2996                                                 right.Emit (ec);
2997                                                 ig.Emit (OpCodes.Br, end);
2998
2999                                 ig.MarkLabel (load_one);
3000                                 ig.Emit (OpCodes.Ldc_I4_1);
3001                                 ig.MarkLabel (end);
3002                                 return;
3003                         }
3004
3005                         left.Emit (ec);
3006                         right.Emit (ec);
3007
3008                         bool isUnsigned = is_unsigned (left.Type);
3009                         
3010                         switch (oper){
3011                         case Operator.Multiply:
3012                                 if (ec.CheckState){
3013                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3014                                                 opcode = OpCodes.Mul_Ovf;
3015                                         else if (isUnsigned)
3016                                                 opcode = OpCodes.Mul_Ovf_Un;
3017                                         else
3018                                                 opcode = OpCodes.Mul;
3019                                 } else
3020                                         opcode = OpCodes.Mul;
3021
3022                                 break;
3023
3024                         case Operator.Division:
3025                                 if (isUnsigned)
3026                                         opcode = OpCodes.Div_Un;
3027                                 else
3028                                         opcode = OpCodes.Div;
3029                                 break;
3030
3031                         case Operator.Modulus:
3032                                 if (isUnsigned)
3033                                         opcode = OpCodes.Rem_Un;
3034                                 else
3035                                         opcode = OpCodes.Rem;
3036                                 break;
3037
3038                         case Operator.Addition:
3039                                 if (ec.CheckState){
3040                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3041                                                 opcode = OpCodes.Add_Ovf;
3042                                         else if (isUnsigned)
3043                                                 opcode = OpCodes.Add_Ovf_Un;
3044                                         else
3045                                                 opcode = OpCodes.Add;
3046                                 } else
3047                                         opcode = OpCodes.Add;
3048                                 break;
3049
3050                         case Operator.Subtraction:
3051                                 if (ec.CheckState){
3052                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3053                                                 opcode = OpCodes.Sub_Ovf;
3054                                         else if (isUnsigned)
3055                                                 opcode = OpCodes.Sub_Ovf_Un;
3056                                         else
3057                                                 opcode = OpCodes.Sub;
3058                                 } else
3059                                         opcode = OpCodes.Sub;
3060                                 break;
3061
3062                         case Operator.RightShift:
3063                                 if (isUnsigned)
3064                                         opcode = OpCodes.Shr_Un;
3065                                 else
3066                                         opcode = OpCodes.Shr;
3067                                 break;
3068                                 
3069                         case Operator.LeftShift:
3070                                 opcode = OpCodes.Shl;
3071                                 break;
3072
3073                         case Operator.Equality:
3074                                 opcode = OpCodes.Ceq;
3075                                 break;
3076
3077                         case Operator.Inequality:
3078                                 ig.Emit (OpCodes.Ceq);
3079                                 ig.Emit (OpCodes.Ldc_I4_0);
3080                                 
3081                                 opcode = OpCodes.Ceq;
3082                                 break;
3083
3084                         case Operator.LessThan:
3085                                 if (isUnsigned)
3086                                         opcode = OpCodes.Clt_Un;
3087                                 else
3088                                         opcode = OpCodes.Clt;
3089                                 break;
3090
3091                         case Operator.GreaterThan:
3092                                 if (isUnsigned)
3093                                         opcode = OpCodes.Cgt_Un;
3094                                 else
3095                                         opcode = OpCodes.Cgt;
3096                                 break;
3097
3098                         case Operator.LessThanOrEqual:
3099                                 Type lt = left.Type;
3100                                 
3101                                 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3102                                         ig.Emit (OpCodes.Cgt_Un);
3103                                 else
3104                                         ig.Emit (OpCodes.Cgt);
3105                                 ig.Emit (OpCodes.Ldc_I4_0);
3106                                 
3107                                 opcode = OpCodes.Ceq;
3108                                 break;
3109
3110                         case Operator.GreaterThanOrEqual:
3111                                 Type le = left.Type;
3112                                 
3113                                 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3114                                         ig.Emit (OpCodes.Clt_Un);
3115                                 else
3116                                         ig.Emit (OpCodes.Clt);
3117                                 
3118                                 ig.Emit (OpCodes.Ldc_I4_0);
3119                                 
3120                                 opcode = OpCodes.Ceq;
3121                                 break;
3122
3123                         case Operator.BitwiseOr:
3124                                 opcode = OpCodes.Or;
3125                                 break;
3126
3127                         case Operator.BitwiseAnd:
3128                                 opcode = OpCodes.And;
3129                                 break;
3130
3131                         case Operator.ExclusiveOr:
3132                                 opcode = OpCodes.Xor;
3133                                 break;
3134
3135                         default:
3136                                 throw new Exception ("This should not happen: Operator = "
3137                                                      + oper.ToString ());
3138                         }
3139
3140                         ig.Emit (opcode);
3141                 }
3142         }
3143
3144         //
3145         // Object created by Binary when the binary operator uses an method instead of being
3146         // a binary operation that maps to a CIL binary operation.
3147         //
3148         public class BinaryMethod : Expression {
3149                 public MethodBase method;
3150                 public ArrayList  Arguments;
3151                 
3152                 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3153                 {
3154                         method = m;
3155                         Arguments = args;
3156                         type = t;
3157                         eclass = ExprClass.Value;
3158                 }
3159
3160                 public override Expression DoResolve (EmitContext ec)
3161                 {
3162                         return this;
3163                 }
3164
3165                 public override void Emit (EmitContext ec)
3166                 {
3167                         ILGenerator ig = ec.ig;
3168                         
3169                         if (Arguments != null) 
3170                                 Invocation.EmitArguments (ec, method, Arguments);
3171                         
3172                         if (method is MethodInfo)
3173                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
3174                         else
3175                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3176                 }
3177         }
3178
3179         //
3180         // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3181         // b, c, d... may be strings or objects.
3182         //
3183         public class StringConcat : Expression {
3184                 ArrayList operands;
3185                 bool invalid = false;
3186                 
3187                 
3188                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3189                 {
3190                         this.loc = loc;
3191                         type = TypeManager.string_type;
3192                         eclass = ExprClass.Value;
3193                 
3194                         operands = new ArrayList (2);
3195                         Append (ec, left);
3196                         Append (ec, right);
3197                 }
3198                 
3199                 public override Expression DoResolve (EmitContext ec)
3200                 {
3201                         if (invalid)
3202                                 return null;
3203                         
3204                         return this;
3205                 }
3206                 
3207                 public void Append (EmitContext ec, Expression operand)
3208                 {
3209                         //
3210                         // Constant folding
3211                         //
3212                         if (operand is StringConstant && operands.Count != 0) {
3213                                 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3214                                 if (last_operand != null) {
3215                                         operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
3216                                         return;
3217                                 }
3218                         }
3219                         
3220                         //
3221                         // Conversion to object
3222                         //
3223                         if (operand.Type != TypeManager.string_type) {
3224                                 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3225                                 
3226                                 if (no == null) {
3227                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3228                                         invalid = true;
3229                                 }
3230                                 operand = no;
3231                         }
3232                         
3233                         operands.Add (operand);
3234                 }
3235
3236                 public override void Emit (EmitContext ec)
3237                 {
3238                         MethodInfo concat_method = null;
3239                         
3240                         //
3241                         // Are we also concating objects?
3242                         //
3243                         bool is_strings_only = true;
3244                         
3245                         //
3246                         // Do conversion to arguments; check for strings only
3247                         //
3248                         for (int i = 0; i < operands.Count; i ++) {
3249                                 Expression e = (Expression) operands [i];
3250                                 is_strings_only &= e.Type == TypeManager.string_type;
3251                         }
3252                         
3253                         for (int i = 0; i < operands.Count; i ++) {
3254                                 Expression e = (Expression) operands [i];
3255                                 
3256                                 if (! is_strings_only && e.Type == TypeManager.string_type) {
3257                                         // need to make sure this is an object, because the EmitParams
3258                                         // method might look at the type of this expression, see it is a
3259                                         // string and emit a string [] when we want an object [];
3260                                         
3261                                         e = Convert.ImplicitConversion (ec, e, TypeManager.object_type, loc);
3262                                 }
3263                                 operands [i] = new Argument (e, Argument.AType.Expression);
3264                         }
3265                         
3266                         //
3267                         // Find the right method
3268                         //
3269                         switch (operands.Count) {
3270                         case 1:
3271                                 //
3272                                 // This should not be possible, because simple constant folding
3273                                 // is taken care of in the Binary code.
3274                                 //
3275                                 throw new Exception ("how did you get here?");
3276                         
3277                         case 2:
3278                                 concat_method = is_strings_only ? 
3279                                         TypeManager.string_concat_string_string :
3280                                         TypeManager.string_concat_object_object ;
3281                                 break;
3282                         case 3:
3283                                 concat_method = is_strings_only ? 
3284                                         TypeManager.string_concat_string_string_string :
3285                                         TypeManager.string_concat_object_object_object ;
3286                                 break;
3287                         case 4:
3288                                 //
3289                                 // There is not a 4 param overlaod for object (the one that there is
3290                                 // is actually a varargs methods, and is only in corlib because it was
3291                                 // introduced there before.).
3292                                 //
3293                                 if (!is_strings_only)
3294                                         goto default;
3295                                 
3296                                 concat_method = TypeManager.string_concat_string_string_string_string;
3297                                 break;
3298                         default:
3299                                 concat_method = is_strings_only ? 
3300                                         TypeManager.string_concat_string_dot_dot_dot :
3301                                         TypeManager.string_concat_object_dot_dot_dot ;
3302                                 break;
3303                         }
3304                         
3305                         Invocation.EmitArguments (ec, concat_method, operands);
3306                         ec.ig.Emit (OpCodes.Call, concat_method);
3307                 }
3308         }
3309
3310         //
3311         // Object created with +/= on delegates
3312         //
3313         public class BinaryDelegate : Expression {
3314                 MethodInfo method;
3315                 ArrayList  args;
3316
3317                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3318                 {
3319                         method = mi;
3320                         this.args = args;
3321                         type = t;
3322                         eclass = ExprClass.Value;
3323                 }
3324
3325                 public override Expression DoResolve (EmitContext ec)
3326                 {
3327                         return this;
3328                 }
3329
3330                 public override void Emit (EmitContext ec)
3331                 {
3332                         ILGenerator ig = ec.ig;
3333                         
3334                         Invocation.EmitArguments (ec, method, args);
3335                         
3336                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3337                         ig.Emit (OpCodes.Castclass, type);
3338                 }
3339
3340                 public Expression Right {
3341                         get {
3342                                 Argument arg = (Argument) args [1];
3343                                 return arg.Expr;
3344                         }
3345                 }
3346
3347                 public bool IsAddition {
3348                         get {
3349                                 return method == TypeManager.delegate_combine_delegate_delegate;
3350                         }
3351                 }
3352         }
3353         
3354         //
3355         // User-defined conditional logical operator
3356         public class ConditionalLogicalOperator : Expression {
3357                 Expression left, right;
3358                 bool is_and;
3359
3360                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3361                 {
3362                         type = t;
3363                         eclass = ExprClass.Value;
3364                         this.loc = loc;
3365                         this.left = left;
3366                         this.right = right;
3367                         this.is_and = is_and;
3368                 }
3369
3370                 protected void Error19 ()
3371                 {
3372                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3373                 }
3374
3375                 protected void Error218 ()
3376                 {
3377                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3378                                "declarations of operator true and operator false");
3379                 }
3380
3381                 Expression op_true, op_false, op;
3382                 LocalTemporary left_temp;
3383
3384                 public override Expression DoResolve (EmitContext ec)
3385                 {
3386                         MethodInfo method;
3387                         Expression operator_group;
3388
3389                         operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3390                         if (operator_group == null) {
3391                                 Error19 ();
3392                                 return null;
3393                         }
3394
3395                         left_temp = new LocalTemporary (ec, type);
3396
3397                         ArrayList arguments = new ArrayList ();
3398                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3399                         arguments.Add (new Argument (right, Argument.AType.Expression));
3400                         method = Invocation.OverloadResolve (
3401                                 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3402                                 as MethodInfo;
3403                         if ((method == null) || (method.ReturnType != type)) {
3404                                 Error19 ();
3405                                 return null;
3406                         }
3407
3408                         op = new StaticCallExpr (method, arguments, loc);
3409
3410                         op_true = GetOperatorTrue (ec, left_temp, loc);
3411                         op_false = GetOperatorFalse (ec, left_temp, loc);
3412                         if ((op_true == null) || (op_false == null)) {
3413                                 Error218 ();
3414                                 return null;
3415                         }
3416
3417                         return this;
3418                 }
3419
3420                 public override void Emit (EmitContext ec)
3421                 {
3422                         ILGenerator ig = ec.ig;
3423                         Label false_target = ig.DefineLabel ();
3424                         Label end_target = ig.DefineLabel ();
3425
3426                         ig.Emit (OpCodes.Nop);
3427
3428                         left.Emit (ec);
3429                         left_temp.Store (ec);
3430
3431                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3432                         left_temp.Emit (ec);
3433                         ig.Emit (OpCodes.Br, end_target);
3434                         ig.MarkLabel (false_target);
3435                         op.Emit (ec);
3436                         ig.MarkLabel (end_target);
3437
3438                         ig.Emit (OpCodes.Nop);
3439                 }
3440         }
3441
3442         public class PointerArithmetic : Expression {
3443                 Expression left, right;
3444                 bool is_add;
3445
3446                 //
3447                 // We assume that `l' is always a pointer
3448                 //
3449                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3450                 {
3451                         type = t;
3452                         eclass = ExprClass.Variable;
3453                         this.loc = loc;
3454                         left = l;
3455                         right = r;
3456                         is_add = is_addition;
3457                 }
3458
3459                 public override Expression DoResolve (EmitContext ec)
3460                 {
3461                         //
3462                         // We are born fully resolved
3463                         //
3464                         return this;
3465                 }
3466
3467                 public override void Emit (EmitContext ec)
3468                 {
3469                         Type op_type = left.Type;
3470                         ILGenerator ig = ec.ig;
3471                         int size = GetTypeSize (TypeManager.GetElementType (op_type));
3472                         Type rtype = right.Type;
3473                         
3474                         if (rtype.IsPointer){
3475                                 //
3476                                 // handle (pointer - pointer)
3477                                 //
3478                                 left.Emit (ec);
3479                                 right.Emit (ec);
3480                                 ig.Emit (OpCodes.Sub);
3481
3482                                 if (size != 1){
3483                                         if (size == 0)
3484                                                 ig.Emit (OpCodes.Sizeof, op_type);
3485                                         else 
3486                                                 IntLiteral.EmitInt (ig, size);
3487                                         ig.Emit (OpCodes.Div);
3488                                 }
3489                                 ig.Emit (OpCodes.Conv_I8);
3490                         } else {
3491                                 //
3492                                 // handle + and - on (pointer op int)
3493                                 //
3494                                 left.Emit (ec);
3495                                 ig.Emit (OpCodes.Conv_I);
3496                                 right.Emit (ec);
3497                                 if (size != 1){
3498                                         if (size == 0)
3499                                                 ig.Emit (OpCodes.Sizeof, op_type);
3500                                         else 
3501                                                 IntLiteral.EmitInt (ig, size);
3502                                         if (rtype == TypeManager.int64_type)
3503                                                 ig.Emit (OpCodes.Conv_I8);
3504                                         else if (rtype == TypeManager.uint64_type)
3505                                                 ig.Emit (OpCodes.Conv_U8);
3506                                         ig.Emit (OpCodes.Mul);
3507                                         ig.Emit (OpCodes.Conv_I);
3508                                 }
3509                                 if (is_add)
3510                                         ig.Emit (OpCodes.Add);
3511                                 else
3512                                         ig.Emit (OpCodes.Sub);
3513                         }
3514                 }
3515         }
3516         
3517         /// <summary>
3518         ///   Implements the ternary conditional operator (?:)
3519         /// </summary>
3520         public class Conditional : Expression {
3521                 Expression expr, trueExpr, falseExpr;
3522                 
3523                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3524                 {
3525                         this.expr = expr;
3526                         this.trueExpr = trueExpr;
3527                         this.falseExpr = falseExpr;
3528                         this.loc = l;
3529                 }
3530
3531                 public Expression Expr {
3532                         get {
3533                                 return expr;
3534                         }
3535                 }
3536
3537                 public Expression TrueExpr {
3538                         get {
3539                                 return trueExpr;
3540                         }
3541                 }
3542
3543                 public Expression FalseExpr {
3544                         get {
3545                                 return falseExpr;
3546                         }
3547                 }
3548
3549                 public override Expression DoResolve (EmitContext ec)
3550                 {
3551                         expr = expr.Resolve (ec);
3552
3553                         if (expr == null)
3554                                 return null;
3555                         
3556                         if (expr.Type != TypeManager.bool_type){
3557                                 expr = Expression.ResolveBoolean (
3558                                         ec, expr, loc);
3559                                 
3560                                 if (expr == null)
3561                                         return null;
3562                         }
3563                         
3564                         trueExpr = trueExpr.Resolve (ec);
3565                         falseExpr = falseExpr.Resolve (ec);
3566
3567                         if (trueExpr == null || falseExpr == null)
3568                                 return null;
3569
3570                         eclass = ExprClass.Value;
3571                         if (trueExpr.Type == falseExpr.Type)
3572                                 type = trueExpr.Type;
3573                         else {
3574                                 Expression conv;
3575                                 Type true_type = trueExpr.Type;
3576                                 Type false_type = falseExpr.Type;
3577
3578                                 if (trueExpr is NullLiteral){
3579                                         type = false_type;
3580                                         return this;
3581                                 } else if (falseExpr is NullLiteral){
3582                                         type = true_type;
3583                                         return this;
3584                                 }
3585                                 
3586                                 //
3587                                 // First, if an implicit conversion exists from trueExpr
3588                                 // to falseExpr, then the result type is of type falseExpr.Type
3589                                 //
3590                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3591                                 if (conv != null){
3592                                         //
3593                                         // Check if both can convert implicitl to each other's type
3594                                         //
3595                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3596                                                 Error (172,
3597                                                        "Can not compute type of conditional expression " +
3598                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3599                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3600                                                        "' convert implicitly to each other");
3601                                                 return null;
3602                                         }
3603                                         type = false_type;
3604                                         trueExpr = conv;
3605                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3606                                         type = true_type;
3607                                         falseExpr = conv;
3608                                 } else {
3609                                         Error (173, "The type of the conditional expression can " +
3610                                                "not be computed because there is no implicit conversion" +
3611                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3612                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3613                                         return null;
3614                                 }
3615                         }
3616
3617                         if (expr is BoolConstant){
3618                                 BoolConstant bc = (BoolConstant) expr;
3619
3620                                 if (bc.Value)
3621                                         return trueExpr;
3622                                 else
3623                                         return falseExpr;
3624                         }
3625
3626                         return this;
3627                 }
3628
3629                 public override void Emit (EmitContext ec)
3630                 {
3631                         ILGenerator ig = ec.ig;
3632                         Label false_target = ig.DefineLabel ();
3633                         Label end_target = ig.DefineLabel ();
3634
3635                         expr.EmitBranchable (ec, false_target, false);
3636                         trueExpr.Emit (ec);
3637                         ig.Emit (OpCodes.Br, end_target);
3638                         ig.MarkLabel (false_target);
3639                         falseExpr.Emit (ec);
3640                         ig.MarkLabel (end_target);
3641                 }
3642
3643         }
3644
3645         /// <summary>
3646         ///   Local variables
3647         /// </summary>
3648         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3649                 public readonly string Name;
3650                 public readonly Block Block;
3651                 LocalInfo local_info;
3652                 bool is_readonly;
3653                 
3654                 public LocalVariableReference (Block block, string name, Location l)
3655                 {
3656                         Block = block;
3657                         Name = name;
3658                         loc = l;
3659                         eclass = ExprClass.Variable;
3660                 }
3661
3662                 // Setting `is_readonly' to false will allow you to create a writable
3663                 // reference to a read-only variable.  This is used by foreach and using.
3664                 public LocalVariableReference (Block block, string name, Location l,
3665                                                LocalInfo local_info, bool is_readonly)
3666                         : this (block, name, l)
3667                 {
3668                         this.local_info = local_info;
3669                         this.is_readonly = is_readonly;
3670                 }
3671
3672                 public VariableInfo VariableInfo {
3673                         get { return local_info.VariableInfo; }
3674                 }
3675
3676                 public bool IsReadOnly {
3677                         get {
3678                                 return is_readonly;
3679                         }
3680                 }
3681
3682                 protected void DoResolveBase (EmitContext ec)
3683                 {
3684                         if (local_info == null) {
3685                                 local_info = Block.GetLocalInfo (Name);
3686                                 is_readonly = local_info.ReadOnly;
3687                         }
3688
3689                         type = local_info.VariableType;
3690 #if false
3691                         if (ec.InAnonymousMethod)
3692                                 Block.LiftVariable (local_info);
3693 #endif
3694                 }
3695                 
3696                 protected Expression DoResolve (EmitContext ec, bool is_lvalue)
3697                 {
3698                         Expression e = Block.GetConstantExpression (Name);
3699                         if (e != null) {
3700                                 local_info.Used = true;
3701                                 eclass = ExprClass.Value;
3702                                 return e;
3703                         }
3704
3705                         VariableInfo variable_info = local_info.VariableInfo; 
3706                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3707                                 return null;
3708
3709                         if (!is_lvalue)
3710                                 local_info.Used = true;
3711
3712                         if (local_info.LocalBuilder == null)
3713                                 return ec.RemapLocal (local_info);
3714                         
3715                         return this;
3716                 }
3717
3718                 public override Expression DoResolve (EmitContext ec)
3719                 {
3720                         DoResolveBase (ec);
3721
3722                         return DoResolve (ec, false);
3723                 }
3724
3725                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3726                 {
3727                         DoResolveBase (ec);
3728
3729                         VariableInfo variable_info = local_info.VariableInfo; 
3730                         if (variable_info != null)
3731                                 variable_info.SetAssigned (ec);
3732
3733                         Expression e = DoResolve (ec, true);
3734
3735                         if (e == null)
3736                                 return null;
3737
3738                         if (is_readonly){
3739                                 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3740                                 return null;
3741                         }
3742
3743                         CheckObsoleteAttribute (e.Type);
3744
3745                         if (local_info.LocalBuilder == null)
3746                                 return ec.RemapLocalLValue (local_info, right_side);
3747                         
3748                         return this;
3749                 }
3750
3751                 public bool VerifyFixed (bool is_expression)
3752                 {
3753                         return !is_expression || local_info.IsFixed;
3754                 }
3755
3756                 public override void Emit (EmitContext ec)
3757                 {
3758                         ILGenerator ig = ec.ig;
3759
3760                         ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3761                 }
3762                 
3763                 public void EmitAssign (EmitContext ec, Expression source)
3764                 {
3765                         ILGenerator ig = ec.ig;
3766
3767                         source.Emit (ec);
3768                         ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3769                 }
3770                 
3771                 public void AddressOf (EmitContext ec, AddressOp mode)
3772                 {
3773                         ILGenerator ig = ec.ig;
3774                         
3775                         ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3776                 }
3777
3778                 public override string ToString ()
3779                 {
3780                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3781                 }
3782         }
3783
3784         /// <summary>
3785         ///   This represents a reference to a parameter in the intermediate
3786         ///   representation.
3787         /// </summary>
3788         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3789                 Parameters pars;
3790                 String name;
3791                 int idx;
3792                 Block block;
3793                 VariableInfo vi;
3794                 public Parameter.Modifier mod;
3795                 public bool is_ref, is_out;
3796                 
3797                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3798                 {
3799                         this.pars = pars;
3800                         this.block = block;
3801                         this.idx  = idx;
3802                         this.name = name;
3803                         this.loc = loc;
3804                         eclass = ExprClass.Variable;
3805                 }
3806
3807                 public VariableInfo VariableInfo {
3808                         get { return vi; }
3809                 }
3810
3811                 public bool VerifyFixed (bool is_expression)
3812                 {
3813                         return !is_expression || TypeManager.IsValueType (type);
3814                 }
3815
3816                 public bool IsAssigned (EmitContext ec, Location loc)
3817                 {
3818                         if (!ec.DoFlowAnalysis || !is_out ||
3819                             ec.CurrentBranching.IsAssigned (vi))
3820                                 return true;
3821
3822                         Report.Error (165, loc,
3823                                       "Use of unassigned parameter `" + name + "'");
3824                         return false;
3825                 }
3826
3827                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3828                 {
3829                         if (!ec.DoFlowAnalysis || !is_out ||
3830                             ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3831                                 return true;
3832
3833                         Report.Error (170, loc,
3834                                       "Use of possibly unassigned field `" + field_name + "'");
3835                         return false;
3836                 }
3837
3838                 public void SetAssigned (EmitContext ec)
3839                 {
3840                         if (is_out && ec.DoFlowAnalysis)
3841                                 ec.CurrentBranching.SetAssigned (vi);
3842                 }
3843
3844                 public void SetFieldAssigned (EmitContext ec, string field_name)
3845                 {
3846                         if (is_out && ec.DoFlowAnalysis)
3847                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3848                 }
3849
3850                 protected void DoResolveBase (EmitContext ec)
3851                 {
3852                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3853                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3854                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3855                         eclass = ExprClass.Variable;
3856
3857                         if (is_out)
3858                                 vi = block.ParameterMap [idx];
3859                 }
3860
3861                 //
3862                 // Notice that for ref/out parameters, the type exposed is not the
3863                 // same type exposed externally.
3864                 //
3865                 // for "ref int a":
3866                 //   externally we expose "int&"
3867                 //   here we expose       "int".
3868                 //
3869                 // We record this in "is_ref".  This means that the type system can treat
3870                 // the type as it is expected, but when we generate the code, we generate
3871                 // the alternate kind of code.
3872                 //
3873                 public override Expression DoResolve (EmitContext ec)
3874                 {
3875                         DoResolveBase (ec);
3876
3877                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3878                                 return null;
3879
3880                         if (ec.RemapToProxy)
3881                                 return ec.RemapParameter (idx);
3882                         
3883                         return this;
3884                 }
3885
3886                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3887                 {
3888                         DoResolveBase (ec);
3889
3890                         SetAssigned (ec);
3891
3892                         if (ec.RemapToProxy)
3893                                 return ec.RemapParameterLValue (idx, right_side);
3894                         
3895                         return this;
3896                 }
3897
3898                 static public void EmitLdArg (ILGenerator ig, int x)
3899                 {
3900                         if (x <= 255){
3901                                 switch (x){
3902                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3903                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3904                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3905                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3906                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3907                                 }
3908                         } else
3909                                 ig.Emit (OpCodes.Ldarg, x);
3910                 }
3911                 
3912                 //
3913                 // This method is used by parameters that are references, that are
3914                 // being passed as references:  we only want to pass the pointer (that
3915                 // is already stored in the parameter, not the address of the pointer,
3916                 // and not the value of the variable).
3917                 //
3918                 public void EmitLoad (EmitContext ec)
3919                 {
3920                         ILGenerator ig = ec.ig;
3921                         int arg_idx = idx;
3922
3923                         if (!ec.IsStatic)
3924                                 arg_idx++;
3925
3926                         EmitLdArg (ig, arg_idx);
3927                 }
3928                 
3929                 public override void Emit (EmitContext ec)
3930                 {
3931                         ILGenerator ig = ec.ig;
3932                         
3933                         int arg_idx = idx;
3934
3935                         if (!ec.IsStatic)
3936                                 arg_idx++;
3937
3938                         EmitLdArg (ig, arg_idx);
3939
3940                         if (!is_ref)
3941                                 return;
3942
3943                         //
3944                         // If we are a reference, we loaded on the stack a pointer
3945                         // Now lets load the real value
3946                         //
3947                         LoadFromPtr (ig, type);
3948                 }
3949
3950                 public void EmitAssign (EmitContext ec, Expression source)
3951                 {
3952                         ILGenerator ig = ec.ig;
3953                         
3954                         int arg_idx = idx;
3955
3956                         if (!ec.IsStatic)
3957                                 arg_idx++;
3958
3959                         if (is_ref)
3960                                 EmitLdArg (ig, arg_idx);
3961                         
3962                         source.Emit (ec);
3963
3964                         if (is_ref)
3965                                 StoreFromPtr (ig, type);
3966                         else {
3967                                 if (arg_idx <= 255)
3968                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3969                                 else
3970                                         ig.Emit (OpCodes.Starg, arg_idx);
3971                         }
3972                 }
3973
3974                 public void AddressOf (EmitContext ec, AddressOp mode)
3975                 {
3976                         int arg_idx = idx;
3977
3978                         if (!ec.IsStatic)
3979                                 arg_idx++;
3980
3981                         if (is_ref){
3982                                 if (arg_idx <= 255)
3983                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3984                                 else
3985                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3986                         } else {
3987                                 if (arg_idx <= 255)
3988                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3989                                 else
3990                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3991                         }
3992                 }
3993
3994         }
3995         
3996         /// <summary>
3997         ///   Used for arguments to New(), Invocation()
3998         /// </summary>
3999         public class Argument {
4000                 public enum AType : byte {
4001                         Expression,
4002                         Ref,
4003                         Out,
4004                         ArgList
4005                 };
4006
4007                 public readonly AType ArgType;
4008                 public Expression Expr;
4009                 
4010                 public Argument (Expression expr, AType type)
4011                 {
4012                         this.Expr = expr;
4013                         this.ArgType = type;
4014                 }
4015
4016                 public Type Type {
4017                         get {
4018                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4019                                         return TypeManager.GetReferenceType (Expr.Type);
4020                                 else
4021                                         return Expr.Type;
4022                         }
4023                 }
4024
4025                 public Parameter.Modifier GetParameterModifier ()
4026                 {
4027                         switch (ArgType) {
4028                         case AType.Out:
4029                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4030
4031                         case AType.Ref:
4032                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4033
4034                         default:
4035                                 return Parameter.Modifier.NONE;
4036                         }
4037                 }
4038
4039                 public static string FullDesc (Argument a)
4040                 {
4041                         if (a.ArgType == AType.ArgList)
4042                                 return "__arglist";
4043
4044                         return (a.ArgType == AType.Ref ? "ref " :
4045                                 (a.ArgType == AType.Out ? "out " : "")) +
4046                                 TypeManager.CSharpName (a.Expr.Type);
4047                 }
4048
4049                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4050                 {
4051                         ConstructedType ctype = Expr as ConstructedType;
4052                         if (ctype != null)
4053                                 Expr = ctype.GetSimpleName (ec);
4054
4055                         // FIXME: csc doesn't report any error if you try to use `ref' or
4056                         //        `out' in a delegate creation expression.
4057                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4058                         if (Expr == null)
4059                                 return false;
4060
4061                         return true;
4062                 }
4063                 
4064                 public bool Resolve (EmitContext ec, Location loc)
4065                 {
4066                         if (ArgType == AType.Ref) {
4067                                 Expr = Expr.Resolve (ec);
4068                                 if (Expr == null)
4069                                         return false;
4070
4071                                 Expr = Expr.ResolveLValue (ec, Expr);
4072                         } else if (ArgType == AType.Out)
4073                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
4074                         else
4075                                 Expr = Expr.Resolve (ec);
4076
4077                         if (Expr == null)
4078                                 return false;
4079
4080                         if (ArgType == AType.Expression)
4081                                 return true;
4082                         else {
4083                                 //
4084                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4085                                 // This is only allowed for `this'
4086                                 //
4087                                 FieldExpr fe = Expr as FieldExpr;
4088                                 if (fe != null && !fe.IsStatic){
4089                                         Expression instance = fe.InstanceExpression;
4090
4091                                         if (instance.GetType () != typeof (This)){
4092                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4093                                                         Report.Error (197, loc,
4094                                                                       "Can not pass a type that derives from MarshalByRefObject with out or ref");
4095                                                         return false;
4096                                                 }
4097                                         }
4098                                 }
4099                         }
4100
4101                         if (Expr.eclass != ExprClass.Variable){
4102                                 //
4103                                 // We just probe to match the CSC output
4104                                 //
4105                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4106                                     Expr.eclass == ExprClass.IndexerAccess){
4107                                         Report.Error (
4108                                                 206, loc,
4109                                                 "A property or indexer can not be passed as an out or ref " +
4110                                                 "parameter");
4111                                 } else {
4112                                         Report.Error (
4113                                                 1510, loc,
4114                                                 "An lvalue is required as an argument to out or ref");
4115                                 }
4116                                 return false;
4117                         }
4118                                 
4119                         return true;
4120                 }
4121
4122                 public void Emit (EmitContext ec)
4123                 {
4124                         //
4125                         // Ref and Out parameters need to have their addresses taken.
4126                         //
4127                         // ParameterReferences might already be references, so we want
4128                         // to pass just the value
4129                         //
4130                         if (ArgType == AType.Ref || ArgType == AType.Out){
4131                                 AddressOp mode = AddressOp.Store;
4132
4133                                 if (ArgType == AType.Ref)
4134                                         mode |= AddressOp.Load;
4135                                 
4136                                 if (Expr is ParameterReference){
4137                                         ParameterReference pr = (ParameterReference) Expr;
4138
4139                                         if (pr.is_ref)
4140                                                 pr.EmitLoad (ec);
4141                                         else {
4142                                                 
4143                                                 pr.AddressOf (ec, mode);
4144                                         }
4145                                 } else {
4146                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
4147                                 }
4148                         } else
4149                                 Expr.Emit (ec);
4150                 }
4151         }
4152
4153         /// <summary>
4154         ///   Invocation of methods or delegates.
4155         /// </summary>
4156         public class Invocation : ExpressionStatement {
4157                 public readonly ArrayList Arguments;
4158
4159                 Expression expr;
4160                 MethodBase method = null;
4161                 bool is_base;
4162                 
4163                 static Hashtable method_parameter_cache;
4164
4165                 static Invocation ()
4166                 {
4167                         method_parameter_cache = new PtrHashtable ();
4168                 }
4169                         
4170                 //
4171                 // arguments is an ArrayList, but we do not want to typecast,
4172                 // as it might be null.
4173                 //
4174                 // FIXME: only allow expr to be a method invocation or a
4175                 // delegate invocation (7.5.5)
4176                 //
4177                 public Invocation (Expression expr, ArrayList arguments, Location l)
4178                 {
4179                         this.expr = expr;
4180                         Arguments = arguments;
4181                         loc = l;
4182                 }
4183
4184                 public Expression Expr {
4185                         get {
4186                                 return expr;
4187                         }
4188                 }
4189
4190                 /// <summary>
4191                 ///   Returns the Parameters (a ParameterData interface) for the
4192                 ///   Method `mb'
4193                 /// </summary>
4194                 public static ParameterData GetParameterData (MethodBase mb)
4195                 {
4196                         object pd = method_parameter_cache [mb];
4197                         object ip;
4198                         
4199                         if (pd != null)
4200                                 return (ParameterData) pd;
4201
4202                         ip = TypeManager.LookupParametersByBuilder (mb);
4203                         if (ip != null){
4204                                 method_parameter_cache [mb] = ip;
4205
4206                                 return (ParameterData) ip;
4207                         } else {
4208                                 ReflectionParameters rp = new ReflectionParameters (mb);
4209                                 method_parameter_cache [mb] = rp;
4210
4211                                 return (ParameterData) rp;
4212                         }
4213                 }
4214
4215                 /// <summary>
4216                 ///   Determines "better conversion" as specified in 7.4.2.3
4217                 ///
4218                 ///    Returns : 1 if a->p is better
4219                 ///              0 if a->q or neither is better 
4220                 /// </summary>
4221                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4222                 {
4223                         Type argument_type = a.Type;
4224                         Expression argument_expr = a.Expr;
4225
4226                         if (argument_type == null)
4227                                 throw new Exception ("Expression of type " + a.Expr +
4228                                                      " does not resolve its type");
4229
4230                         //
4231                         // This is a special case since csc behaves this way.
4232                         //
4233                         if (argument_expr is NullLiteral &&
4234                             p == TypeManager.string_type &&
4235                             q == TypeManager.object_type)
4236                                 return 1;
4237                         else if (argument_expr is NullLiteral &&
4238                                  p == TypeManager.object_type &&
4239                                  q == TypeManager.string_type)
4240                                 return 0;
4241                         
4242                         //
4243                         // csc behaves this way so we emulate it. Basically, if the argument
4244                         // is null and one of the types to compare is 'object' and the other
4245                         // is a reference type, we prefer the other.
4246                         //
4247                         // I can't find this anywhere in the spec but we can interpret this
4248                         // to mean that null can be of any type you wish in such a context
4249                         //
4250                         if (p != null && q != null) {
4251                                 if (argument_expr is NullLiteral &&
4252                                     !p.IsValueType &&
4253                                     q == TypeManager.object_type)
4254                                         return 1;
4255                                 else if (argument_expr is NullLiteral &&
4256                                          !q.IsValueType &&
4257                                          p == TypeManager.object_type)
4258                                         return 0;
4259                         }
4260                                 
4261                         if (p == q)
4262                                 return 0;
4263                         
4264                         if (argument_type == p)
4265                                 return 1;
4266
4267                         if (argument_type == q)
4268                                 return 0;
4269
4270                         if (q == null) {
4271                                 Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
4272                                 
4273                                 if (tmp != null)
4274                                         return 1;
4275                                 else
4276                                         return 0;
4277                         }
4278
4279                         Expression p_tmp = new EmptyExpression (p);
4280                         Expression q_tmp = new EmptyExpression (q);
4281                         
4282                         if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true &&
4283                             Convert.ImplicitConversionExists (ec, q_tmp, p) == false)
4284                                 return 1;
4285
4286                         if (p == TypeManager.sbyte_type)
4287                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4288                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4289                                         return 1;
4290
4291                         if (p == TypeManager.short_type)
4292                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4293                                     q == TypeManager.uint64_type)
4294                                         return 1;
4295
4296                         if (p == TypeManager.int32_type)
4297                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4298                                         return 1;
4299
4300                         if (p == TypeManager.int64_type)
4301                                 if (q == TypeManager.uint64_type)
4302                                         return 1;
4303
4304                         return 0;
4305                 }
4306                 
4307                 /// <summary>
4308                 ///   Determines "Better function" between candidate
4309                 ///   and the current best match
4310                 /// </summary>
4311                 /// <remarks>
4312                 ///    Returns an integer indicating :
4313                 ///     0 if candidate ain't better
4314                 ///     1 if candidate is better than the current best match
4315                 /// </remarks>
4316                 static int BetterFunction (EmitContext ec, ArrayList args,
4317                                            MethodBase candidate, bool candidate_params,
4318                                            MethodBase best, bool best_params,
4319                                            Location loc)
4320                 {
4321                         ParameterData candidate_pd = GetParameterData (candidate);
4322                         ParameterData best_pd;
4323                         int argument_count;
4324                 
4325                         if (args == null)
4326                                 argument_count = 0;
4327                         else
4328                                 argument_count = args.Count;
4329
4330                         int cand_count = candidate_pd.Count;
4331
4332                         //
4333                         // If there is no best method, than this one
4334                         // is better, however, if we already found a
4335                         // best method, we cant tell. This happens
4336                         // if we have:
4337                         // 
4338                         //      interface IFoo {
4339                         //              void DoIt ();
4340                         //      }
4341                         //      
4342                         //      interface IBar {
4343                         //              void DoIt ();
4344                         //      }
4345                         //      
4346                         //      interface IFooBar : IFoo, IBar {}
4347                         //
4348                         // We cant tell if IFoo.DoIt is better than IBar.DoIt
4349                         //
4350                         // However, we have to consider that
4351                         // Trim (); is better than Trim (params char[] chars);
4352                         //
4353                         if (cand_count == 0 && argument_count == 0)
4354                                 return best == null || best_params ? 1 : 0;
4355
4356                         if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
4357                             (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
4358                                 if (cand_count != argument_count)
4359                                         return 0;
4360
4361                         if (best == null) {
4362                                 int x = 0;
4363
4364                                 if (argument_count == 0 && cand_count == 1 &&
4365                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
4366                                         return 1;
4367                                 
4368                                 for (int j = 0; j < argument_count; ++j) {
4369
4370                                         Argument a = (Argument) args [j];
4371                                         Type t = candidate_pd.ParameterType (j);
4372
4373                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4374                                                 if (candidate_params)
4375                                                         t = TypeManager.GetElementType (t);
4376
4377                                         x = BetterConversion (ec, a, t, null, loc);
4378                                         
4379                                         if (x <= 0)
4380                                                 break;
4381                                 }
4382
4383                                 if (x > 0)
4384                                         return 1;
4385                                 else
4386                                         return 0;
4387                         }
4388
4389                         best_pd = GetParameterData (best);
4390
4391                         int rating1 = 0, rating2 = 0;
4392                         
4393                         for (int j = 0; j < argument_count; ++j) {
4394                                 int x, y;
4395                                 
4396                                 Argument a = (Argument) args [j];
4397
4398                                 Type ct = candidate_pd.ParameterType (j);
4399                                 Type bt = best_pd.ParameterType (j);
4400
4401                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4402                                         if (candidate_params)
4403                                                 ct = TypeManager.GetElementType (ct);
4404
4405                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4406                                         if (best_params)
4407                                                 bt = TypeManager.GetElementType (bt);
4408
4409                                 x = BetterConversion (ec, a, ct, bt, loc);
4410                                 y = BetterConversion (ec, a, bt, ct, loc);
4411
4412                                 if (x < y)
4413                                         return 0;
4414                                 
4415                                 rating1 += x;
4416                                 rating2 += y;
4417                         }
4418
4419                         //
4420                         // If a method (in the normal form) with the
4421                         // same signature as the expanded form of the
4422                         // current best params method already exists,
4423                         // the expanded form is not applicable so we
4424                         // force it to select the candidate
4425                         //
4426                         if (!candidate_params && best_params && cand_count == argument_count)
4427                                 return 1;
4428
4429                         if (rating1 > rating2)
4430                                 return 1;
4431                         else
4432                                 return 0;
4433                 }
4434
4435                 public static string FullMethodDesc (MethodBase mb)
4436                 {
4437                         string ret_type = "";
4438
4439                         if (mb == null)
4440                                 return "";
4441
4442                         if (mb is MethodInfo)
4443                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4444                         
4445                         StringBuilder sb = new StringBuilder (ret_type);
4446                         sb.Append (" ");
4447                         sb.Append (mb.ReflectedType.ToString ());
4448                         sb.Append (".");
4449                         sb.Append (mb.Name);
4450                         
4451                         ParameterData pd = GetParameterData (mb);
4452
4453                         int count = pd.Count;
4454                         sb.Append (" (");
4455                         
4456                         for (int i = count; i > 0; ) {
4457                                 i--;
4458
4459                                 sb.Append (pd.ParameterDesc (count - i - 1));
4460                                 if (i != 0)
4461                                         sb.Append (", ");
4462                         }
4463                         
4464                         sb.Append (")");
4465                         return sb.ToString ();
4466                 }
4467
4468                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4469                 {
4470                         MemberInfo [] miset;
4471                         MethodGroupExpr union;
4472
4473                         if (mg1 == null) {
4474                                 if (mg2 == null)
4475                                         return null;
4476                                 return (MethodGroupExpr) mg2;
4477                         } else {
4478                                 if (mg2 == null)
4479                                         return (MethodGroupExpr) mg1;
4480                         }
4481                         
4482                         MethodGroupExpr left_set = null, right_set = null;
4483                         int length1 = 0, length2 = 0;
4484                         
4485                         left_set = (MethodGroupExpr) mg1;
4486                         length1 = left_set.Methods.Length;
4487                         
4488                         right_set = (MethodGroupExpr) mg2;
4489                         length2 = right_set.Methods.Length;
4490                         
4491                         ArrayList common = new ArrayList ();
4492
4493                         foreach (MethodBase r in right_set.Methods){
4494                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4495                                         common.Add (r);
4496                         }
4497
4498                         miset = new MemberInfo [length1 + length2 - common.Count];
4499                         left_set.Methods.CopyTo (miset, 0);
4500                         
4501                         int k = length1;
4502
4503                         foreach (MethodBase r in right_set.Methods) {
4504                                 if (!common.Contains (r))
4505                                         miset [k++] = r;
4506                         }
4507
4508                         union = new MethodGroupExpr (miset, loc);
4509                         
4510                         return union;
4511                 }
4512
4513                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4514                                                       ArrayList arguments, bool do_varargs,
4515                                                       ref MethodBase candidate)
4516                 {
4517                         if (!me.HasTypeArguments &&
4518                             !InferParamsTypeArguments (ec, arguments, ref candidate))
4519                                 return false;
4520
4521                         return IsParamsMethodApplicable (ec, arguments, candidate, do_varargs);
4522                 }
4523
4524                 /// <summary>
4525                 ///   Determines if the candidate method, if a params method, is applicable
4526                 ///   in its expanded form to the given set of arguments
4527                 /// </summary>
4528                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4529                                                       MethodBase candidate, bool do_varargs)
4530                 {
4531                         int arg_count;
4532                         
4533                         if (arguments == null)
4534                                 arg_count = 0;
4535                         else
4536                                 arg_count = arguments.Count;
4537                         
4538                         ParameterData pd = GetParameterData (candidate);
4539                         
4540                         int pd_count = pd.Count;
4541
4542                         if (pd_count == 0)
4543                                 return false;
4544                         
4545                         int count = pd_count - 1;
4546                         if (do_varargs) {
4547                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4548                                         return false;
4549                                 if (pd_count != arg_count)
4550                                         return false;
4551                         } else {
4552                                 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4553                                 return false;
4554                         }
4555                         
4556                         if (count > arg_count)
4557                                 return false;
4558                         
4559                         if (pd_count == 1 && arg_count == 0)
4560                                 return true;
4561
4562                         //
4563                         // If we have come this far, the case which
4564                         // remains is when the number of parameters is
4565                         // less than or equal to the argument count.
4566                         //
4567                         for (int i = 0; i < count; ++i) {
4568
4569                                 Argument a = (Argument) arguments [i];
4570
4571                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4572                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4573                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4574                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4575
4576                                 if (a_mod == p_mod) {
4577
4578                                         if (a_mod == Parameter.Modifier.NONE)
4579                                                 if (!Convert.ImplicitConversionExists (ec,
4580                                                                                        a.Expr,
4581                                                                                        pd.ParameterType (i)))
4582                                                         return false;
4583                                                                                 
4584                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4585                                                 Type pt = pd.ParameterType (i);
4586
4587                                                 if (!pt.IsByRef)
4588                                                         pt = TypeManager.GetReferenceType (pt);
4589                                                 
4590                                                 if (pt != a.Type)
4591                                                         return false;
4592                                         }
4593                                 } else
4594                                         return false;
4595                                 
4596                         }
4597
4598                         if (do_varargs) {
4599                                 Argument a = (Argument) arguments [count];
4600                                 if (!(a.Expr is Arglist))
4601                                         return false;
4602
4603                                 return true;
4604                         }
4605
4606                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4607
4608                         for (int i = pd_count - 1; i < arg_count; i++) {
4609                                 Argument a = (Argument) arguments [i];
4610                                 
4611                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4612                                         return false;
4613                         }
4614                         
4615                         return true;
4616                 }
4617
4618                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4619                                           ArrayList arguments, ref MethodBase candidate)
4620                 {
4621                         if (!me.HasTypeArguments &&
4622                             !InferTypeArguments (ec, arguments, ref candidate))
4623                                 return false;
4624
4625                         return IsApplicable (ec, arguments, candidate);
4626                 }
4627
4628                 /// <summary>
4629                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4630                 ///   to the given set of arguments
4631                 /// </summary>
4632                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4633                 {
4634                         int arg_count;
4635
4636                         if (arguments == null)
4637                                 arg_count = 0;
4638                         else
4639                                 arg_count = arguments.Count;
4640
4641
4642                         ParameterData pd = GetParameterData (candidate);
4643
4644                         if (arg_count != pd.Count)
4645                                 return false;
4646
4647                         for (int i = arg_count; i > 0; ) {
4648                                 i--;
4649
4650                                 Argument a = (Argument) arguments [i];
4651
4652                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4653                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4654                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4655                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4656
4657
4658                                 if (a_mod == p_mod ||
4659                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4660                                         if (a_mod == Parameter.Modifier.NONE) {
4661                                                 if (!Convert.ImplicitConversionExists (ec,
4662                                                                                        a.Expr,
4663                                                                                        pd.ParameterType (i)))
4664                                                         return false;
4665                                         }
4666                                         
4667                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4668                                                 Type pt = pd.ParameterType (i);
4669
4670                                                 if (!pt.IsByRef)
4671                                                         pt = TypeManager.GetReferenceType (pt);
4672                                                 
4673                                                 if (pt != a.Type)
4674                                                         return false;
4675                                         }
4676                                 } else
4677                                         return false;
4678                         }
4679
4680                         return true;
4681                 }
4682                 
4683                 /// <summary>
4684                 ///   Find the Applicable Function Members (7.4.2.1)
4685                 ///
4686                 ///   me: Method Group expression with the members to select.
4687                 ///       it might contain constructors or methods (or anything
4688                 ///       that maps to a method).
4689                 ///
4690                 ///   Arguments: ArrayList containing resolved Argument objects.
4691                 ///
4692                 ///   loc: The location if we want an error to be reported, or a Null
4693                 ///        location for "probing" purposes.
4694                 ///
4695                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4696                 ///            that is the best match of me on Arguments.
4697                 ///
4698                 /// </summary>
4699                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4700                                                           ArrayList Arguments, bool may_fail,
4701                                                           Location loc)
4702                 {
4703                         MethodBase method = null;
4704                         Type applicable_type = null;
4705                         int argument_count;
4706                         ArrayList candidates = new ArrayList ();
4707
4708                         //
4709                         // Used to keep a map between the candidate
4710                         // and whether it is being considered in its
4711                         // normal or expanded form
4712                         //
4713                         // false is normal form, true is expanded form
4714                         //
4715                         Hashtable candidate_to_form = new PtrHashtable ();
4716
4717
4718                         //
4719                         // First we construct the set of applicable methods
4720                         //
4721                         // We start at the top of the type hierarchy and
4722                         // go down to find applicable methods
4723                         //
4724                         applicable_type = me.DeclaringType;
4725                         
4726                         if (me.Name == "Invoke" && TypeManager.IsDelegateType (applicable_type)) {
4727                                 Error_InvokeOnDelegate (loc);
4728                                 return null;
4729                         }
4730
4731                         bool found_applicable = false;
4732
4733                         MethodBase[] methods = me.Methods;
4734
4735                         for (int i = 0; i < methods.Length; i++) {
4736                                 Type decl_type = methods [i].DeclaringType;
4737
4738                                 //
4739                                 // If we have already found an applicable method
4740                                 // we eliminate all base types (Section 14.5.5.1)
4741                                 //
4742                                 if (decl_type != applicable_type &&
4743                                     (applicable_type.IsSubclassOf (decl_type) ||
4744                                      TypeManager.ImplementsInterface (applicable_type, decl_type)) &&
4745                                     found_applicable)
4746                                         continue;
4747
4748                                 // Check if candidate is applicable (section 14.4.2.1)
4749                                 if (IsApplicable (ec, me, Arguments, ref methods [i])) {
4750                                         // Candidate is applicable in normal form
4751                                         MethodBase candidate = methods [i];
4752                                         candidates.Add (candidate);
4753                                         applicable_type = candidate.DeclaringType;
4754                                         found_applicable = true;
4755                                         candidate_to_form [candidate] = false;
4756                                 } else if (IsParamsMethodApplicable (
4757                                                    ec, me, Arguments,false, ref methods [i])) {
4758                                         // Candidate is applicable in expanded form
4759                                         MethodBase candidate = methods [i];
4760                                         candidates.Add (candidate);
4761                                         applicable_type = candidate.DeclaringType;
4762                                         found_applicable = true; 
4763                                         candidate_to_form [candidate] = true;
4764                                 } else if (IsParamsMethodApplicable (
4765                                                    ec, me, Arguments,true, ref methods [i])) {
4766                                         // Candidate is applicable in expanded form
4767                                         MethodBase candidate = methods [i];
4768                                         candidates.Add (candidate);
4769                                         applicable_type = candidate.DeclaringType;
4770                                         found_applicable = true; 
4771                                         candidate_to_form [candidate] = true;
4772                                 }
4773                         }
4774
4775                         if (Arguments == null)
4776                                 argument_count = 0;
4777                         else
4778                                 argument_count = Arguments.Count;
4779
4780                         //
4781                         // Now we actually find the best method
4782                         //
4783                         int candidate_top = candidates.Count;
4784                         for (int ix = 0; ix < candidate_top; ix++){
4785                                 MethodBase candidate = (MethodBase) candidates [ix];
4786                                 
4787                                 bool cand_params = (bool) candidate_to_form [candidate];
4788                                 bool method_params = false;
4789                                 
4790                                 if (method != null)
4791                                         method_params = (bool) candidate_to_form [method];
4792                                 
4793                                 int x = BetterFunction (ec, Arguments,
4794                                                         candidate, cand_params,
4795                                                         method, method_params,
4796                                                         loc);
4797                                 if (x == 0)
4798                                         continue;
4799                                 
4800                                 method = candidate;
4801                         }
4802
4803                         if (method == null) {
4804                                 int errors = Report.Errors;
4805
4806                                 //
4807                                 // Okay so we have failed to find anything so we
4808                                 // return by providing info about the closest match
4809                                 //
4810                                 for (int i = 0; i < methods.Length; ++i) {
4811
4812                                         MethodBase c = methods [i];
4813                                         if (c == null)
4814                                                 continue;
4815
4816                                         ParameterData pd = GetParameterData (c);
4817                                         if (pd.Count != argument_count)
4818                                                 continue;
4819
4820                                         if (!InferTypeArguments (ec, Arguments, ref c))
4821                                                 continue;
4822
4823                                         VerifyArgumentsCompat (ec, Arguments, argument_count,
4824                                                                c, false, null, loc);
4825                                         break;
4826                                 }
4827
4828                                 if (Report.Errors > errors)
4829                                         return null;
4830
4831                                 string report_name = me.Name;
4832                                 if (report_name == ".ctor")
4833                                         report_name = me.DeclaringType.ToString ();
4834                                         
4835                                 for (int i = 0; i < methods.Length; ++i) {
4836
4837                                         MethodBase c = methods [i];
4838                                         if (c == null)
4839                                                 continue;
4840
4841                                         ParameterData pd = GetParameterData (c);
4842                                         if (pd.Count != argument_count)
4843                                                 continue;
4844
4845                                         if (InferTypeArguments (ec, Arguments, ref c))
4846                                                 continue;
4847
4848                                         Report.Error (411, loc, "The type arguments for " +
4849                                                       "method `{0}' cannot be infered from " +
4850                                                       "the usage. Try specifying the type " +
4851                                                       "arguments explicitly.", report_name);
4852                                         break;
4853                                 }
4854
4855                                 if (!may_fail && (errors == Report.Errors))
4856                                         Error_WrongNumArguments (loc, report_name,
4857                                                                  argument_count);
4858                                 
4859                                 return null;
4860                         }
4861
4862                         //
4863                         // Now check that there are no ambiguities i.e the selected method
4864                         // should be better than all the others
4865                         //
4866                         bool best_params = (bool) candidate_to_form [method];
4867
4868                         for (int ix = 0; ix < candidate_top; ix++){
4869                                 MethodBase candidate = (MethodBase) candidates [ix];
4870
4871                                 if (candidate == method)
4872                                         continue;
4873                                                
4874                                 //
4875                                 // If a normal method is applicable in
4876                                 // the sense that it has the same
4877                                 // number of arguments, then the
4878                                 // expanded params method is never
4879                                 // applicable so we debar the params
4880                                 // method.
4881                                 //
4882                                 // if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
4883 //                                      IsApplicable (ec, Arguments, method)))
4884 //                                         continue;
4885                                 
4886                                 bool cand_params = (bool) candidate_to_form [candidate];
4887                                 int x = BetterFunction (ec, Arguments,
4888                                                         method, best_params,
4889                                                         candidate, cand_params,
4890                                                         loc);
4891
4892                                 if (x != 1) {
4893                                         Report.Error (
4894                                                 121, loc,
4895                                                 "Ambiguous call when selecting function due to implicit casts");
4896                                         return null;
4897                                 }
4898                         }
4899
4900                         //
4901                         // And now check if the arguments are all
4902                         // compatible, perform conversions if
4903                         // necessary etc. and return if everything is
4904                         // all right
4905                         //
4906                         if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4907                                                     best_params, null, loc))
4908                                 return null;
4909
4910                         return method;
4911                 }
4912
4913                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4914                 {
4915                         Report.Error (1501, loc,
4916                                       "No overload for method `" + name + "' takes `" +
4917                                       arg_count + "' arguments");
4918                 }
4919
4920                 static void Error_InvokeOnDelegate (Location loc)
4921                 {
4922                         Report.Error (1533, loc,
4923                                       "Invoke cannot be called directly on a delegate");
4924                 }
4925                         
4926                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4927                                                     Type delegate_type, string arg_sig, string par_desc)
4928                 {
4929                         if (delegate_type == null) 
4930                                 Report.Error (1502, loc,
4931                                               "The best overloaded match for method '" +
4932                                               FullMethodDesc (method) +
4933                                               "' has some invalid arguments");
4934                         else
4935                                 Report.Error (1594, loc,
4936                                               "Delegate '" + delegate_type.ToString () +
4937                                               "' has some invalid arguments.");
4938                         Report.Error (1503, loc,
4939                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4940                                                      idx, arg_sig, par_desc));
4941                 }
4942                 
4943                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4944                                                           int argument_count,
4945                                                           MethodBase method, 
4946                                                           bool chose_params_expanded,
4947                                                           Type delegate_type,
4948                                                           Location loc)
4949                 {
4950                         ParameterData pd = GetParameterData (method);
4951                         int pd_count = pd.Count;
4952                         
4953                         for (int j = 0; j < argument_count; j++) {
4954                                 Argument a = (Argument) Arguments [j];
4955                                 Expression a_expr = a.Expr;
4956                                 Type parameter_type = pd.ParameterType (j);
4957                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4958                                 
4959                                 if (pm == Parameter.Modifier.PARAMS){
4960                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4961                                                 if (!Location.IsNull (loc))
4962                                                         Error_InvalidArguments (
4963                                                                 loc, j, method, delegate_type,
4964                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4965                                                 return false;
4966                                         }
4967
4968                                         if (chose_params_expanded)
4969                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4970                                 } else if (pm == Parameter.Modifier.ARGLIST){
4971                                         continue;
4972                                 } else {
4973                                         //
4974                                         // Check modifiers
4975                                         //
4976                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4977                                                 if (!Location.IsNull (loc))
4978                                                         Error_InvalidArguments (
4979                                                                 loc, j, method, delegate_type,
4980                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4981                                                 return false;
4982                                         }
4983                                 }
4984
4985                                 //
4986                                 // Check Type
4987                                 //
4988                                 if (a.Type != parameter_type){
4989                                         Expression conv;
4990                                         
4991                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
4992
4993                                         if (conv == null) {
4994                                                 if (!Location.IsNull (loc)) 
4995                                                         Error_InvalidArguments (
4996                                                                 loc, j, method, delegate_type,
4997                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4998                                                 return false;
4999                                         }
5000                                         
5001                                         //
5002                                         // Update the argument with the implicit conversion
5003                                         //
5004                                         if (a_expr != conv)
5005                                                 a.Expr = conv;
5006                                 }
5007
5008                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
5009                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
5010                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5011                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
5012                                 
5013                                 if (a_mod != p_mod &&
5014                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5015                                         if (!Location.IsNull (loc)) {
5016                                                 Report.Error (1502, loc,
5017                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
5018                                                        "' has some invalid arguments");
5019                                                 Report.Error (1503, loc,
5020                                                        "Argument " + (j+1) +
5021                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
5022                                                        + "' to '" + pd.ParameterDesc (j) + "'");
5023                                         }
5024                                         
5025                                         return false;
5026                                 }
5027                         }
5028
5029                         return true;
5030                 }
5031
5032                 static bool InferType (Type pt, Type at, ref Type[] infered)
5033                 {
5034                         if (pt.IsGenericParameter) {
5035                                 int pos = pt.GenericParameterPosition;
5036
5037                                 if (infered [pos] == null) {
5038                                         Type check = at;
5039                                         while (check.IsArray)
5040                                                 check = check.GetElementType ();
5041
5042                                         if (pt.Equals (check))
5043                                                 return false;
5044
5045                                         infered [pos] = at;
5046                                         return true;
5047                                 }
5048
5049                                 if (infered [pos] != at)
5050                                         return false;
5051
5052                                 return true;
5053                         }
5054
5055                         if (!pt.ContainsGenericParameters)
5056                                 return true;
5057
5058                         if (at.IsArray) {
5059                                 if (!pt.IsArray ||
5060                                     (at.GetArrayRank () != pt.GetArrayRank ()))
5061                                         return false;
5062
5063                                 return InferType (pt.GetElementType (), at.GetElementType (),
5064                                                   ref infered);
5065                         }
5066
5067                         if (pt.IsArray) {
5068                                 if (!at.IsArray ||
5069                                     (pt.GetArrayRank () != at.GetArrayRank ()))
5070                                         return false;
5071
5072                                 return InferType (pt.GetElementType (), at.GetElementType (),
5073                                                   ref infered);
5074                         }
5075
5076                         if (!at.IsGenericInstance)
5077                                 return false;
5078
5079                         Type[] at_args = at.GetGenericArguments ();
5080                         Type[] pt_args = pt.GetGenericArguments ();
5081
5082                         if (at_args.Length != pt_args.Length)
5083                                 return false;
5084
5085                         Type[] infered_types = new Type [at_args.Length];
5086
5087                         for (int i = 0; i < at_args.Length; i++)
5088                                 if (!InferType (pt_args [i], at_args [i], ref infered_types))
5089                                         return false;
5090
5091                         for (int i = 0; i < infered_types.Length; i++)
5092                                 if (infered_types [i] == null)
5093                                         return false;
5094
5095                         for (int i = 0; i < infered_types.Length; i++) {
5096                                 if (infered [i] == null) {
5097                                         infered [i] = infered_types [i];
5098                                         continue;
5099                                 }
5100
5101                                 if (infered [i] != infered_types [i])
5102                                         return false;
5103                         }
5104
5105                         return true;
5106                 }
5107
5108                 static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
5109                                                       ref MethodBase method)
5110                 {
5111                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
5112                                 return true;
5113
5114                         int arg_count;
5115                         
5116                         if (arguments == null)
5117                                 arg_count = 0;
5118                         else
5119                                 arg_count = arguments.Count;
5120                         
5121                         ParameterData pd = GetParameterData (method);
5122
5123                         int pd_count = pd.Count;
5124
5125                         if (pd_count == 0)
5126                                 return false;
5127                         
5128                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
5129                                 return false;
5130                         
5131                         if (pd_count - 1 > arg_count)
5132                                 return false;
5133                         
5134                         if (pd_count == 1 && arg_count == 0)
5135                                 return true;
5136
5137                         Type[] method_args = method.GetGenericArguments ();
5138                         Type[] infered_types = new Type [method_args.Length];
5139
5140                         //
5141                         // If we have come this far, the case which
5142                         // remains is when the number of parameters is
5143                         // less than or equal to the argument count.
5144                         //
5145                         for (int i = 0; i < pd_count - 1; ++i) {
5146                                 Argument a = (Argument) arguments [i];
5147
5148                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5149                                         continue;
5150
5151                                 Type pt = pd.ParameterType (i);
5152                                 Type at = a.Type;
5153
5154                                 if (!InferType (pt, at, ref infered_types))
5155                                         return false;
5156                         }
5157
5158                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
5159
5160                         for (int i = pd_count - 1; i < arg_count; i++) {
5161                                 Argument a = (Argument) arguments [i];
5162
5163                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5164                                         continue;
5165
5166                                 if (!InferType (element_type, a.Type, ref infered_types))
5167                                         return false;
5168                         }
5169
5170                         for (int i = 0; i < infered_types.Length; i++)
5171                                 if (infered_types [i] == null)
5172                                         return false;
5173
5174                         method = method.BindGenericParameters (infered_types);
5175                         return true;
5176                 }
5177
5178                 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types,
5179                                                        ref Type[] infered_types)
5180                 {
5181                         for (int i = 0; i < arg_types.Length; i++) {
5182                                 if (arg_types [i] == null)
5183                                         continue;
5184
5185                                 if (!InferType (param_types [i], arg_types [i],
5186                                                 ref infered_types))
5187                                         return false;
5188                         }
5189
5190                         for (int i = 0; i < infered_types.Length; i++)
5191                                 if (infered_types [i] == null)
5192                                         return false;
5193
5194                         return true;
5195                 }
5196
5197                 static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
5198                                                 ref MethodBase method)
5199                 {
5200                         if (!TypeManager.IsGenericMethod (method))
5201                                 return true;
5202
5203                         int arg_count;
5204                         if (arguments != null)
5205                                 arg_count = arguments.Count;
5206                         else
5207                                 arg_count = 0;
5208
5209                         ParameterData pd = GetParameterData (method);
5210                         if (arg_count != pd.Count)
5211                                 return false;
5212
5213                         Type[] method_args = method.GetGenericArguments ();
5214                         Type[] infered_types = new Type [method_args.Length];
5215
5216                         Type[] param_types = new Type [pd.Count];
5217                         Type[] arg_types = new Type [pd.Count];
5218
5219                         for (int i = 0; i < arg_count; i++) {
5220                                 param_types [i] = pd.ParameterType (i);
5221
5222                                 Argument a = (Argument) arguments [i];
5223                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
5224                                         continue;
5225
5226                                 arg_types [i] = a.Type;
5227                         }
5228
5229                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5230                                 return false;
5231
5232                         method = method.BindGenericParameters (infered_types);
5233                         return true;
5234                 }
5235
5236                 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
5237                                                        ref MethodBase method)
5238                 {
5239                         if (!TypeManager.IsGenericMethod (method))
5240                                 return true;
5241
5242                         ParameterData pd = GetParameterData (method);
5243                         if (apd.Count != pd.Count)
5244                                 return false;
5245
5246                         Type[] method_args = method.GetGenericArguments ();
5247                         Type[] infered_types = new Type [method_args.Length];
5248
5249                         Type[] param_types = new Type [pd.Count];
5250                         Type[] arg_types = new Type [pd.Count];
5251
5252                         for (int i = 0; i < apd.Count; i++) {
5253                                 param_types [i] = pd.ParameterType (i);
5254                                 arg_types [i] = apd.ParameterType (i);
5255                         }
5256
5257                         if (!InferTypeArguments (param_types, arg_types, ref infered_types))
5258                                 return false;
5259
5260                         method = method.BindGenericParameters (infered_types);
5261                         return true;
5262                 }
5263
5264                 public override Expression DoResolve (EmitContext ec)
5265                 {
5266                         //
5267                         // First, resolve the expression that is used to
5268                         // trigger the invocation
5269                         //
5270                         if (expr is BaseAccess)
5271                                 is_base = true;
5272
5273                         if (expr is ConstructedType)
5274                                 expr = ((ConstructedType) expr).GetSimpleName (ec);
5275
5276                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5277                         if (expr == null)
5278                                 return null;
5279
5280                         if (!(expr is MethodGroupExpr)) {
5281                                 Type expr_type = expr.Type;
5282
5283                                 if (expr_type != null){
5284                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5285                                         if (IsDelegate)
5286                                                 return (new DelegateInvocation (
5287                                                         this.expr, Arguments, loc)).Resolve (ec);
5288                                 }
5289                         }
5290
5291                         if (!(expr is MethodGroupExpr)){
5292                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
5293                                 return null;
5294                         }
5295
5296                         //
5297                         // Next, evaluate all the expressions in the argument list
5298                         //
5299                         if (Arguments != null){
5300                                 foreach (Argument a in Arguments){
5301                                         if (!a.Resolve (ec, loc))
5302                                                 return null;
5303                                 }
5304                         }
5305
5306                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5307                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5308
5309                         if (method == null)
5310                                 return null;
5311
5312                         MethodInfo mi = method as MethodInfo;
5313                         if (mi != null) {
5314                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5315                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5316                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5317                                         return null;
5318                                 }
5319
5320                                 Expression iexpr = mg.InstanceExpression;
5321                                 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5322                                         if (mg.IdenticalTypeName)
5323                                                 mg.InstanceExpression = null;
5324                                         else {
5325                                                 MemberAccess.error176 (loc, mi.Name);
5326                                                 return null;
5327                                         }
5328                                 }
5329                         }
5330
5331                         if (type.IsPointer){
5332                                 if (!ec.InUnsafe){
5333                                         UnsafeError (loc);
5334                                         return null;
5335                                 }
5336                         }
5337                         
5338                         //
5339                         // Only base will allow this invocation to happen.
5340                         //
5341                         if (is_base && method.IsAbstract){
5342                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5343                                               FullMethodDesc (method));
5344                                 return null;
5345                         }
5346
5347                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
5348                                 if (TypeManager.IsSpecialMethod (method))
5349                                         Report.Error (571, loc, method.Name + ": can not call operator or accessor");
5350                         }
5351                         
5352                         eclass = ExprClass.Value;
5353                         return this;
5354                 }
5355
5356                 // <summary>
5357                 //   Emits the list of arguments as an array
5358                 // </summary>
5359                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5360                 {
5361                         ILGenerator ig = ec.ig;
5362                         int count = arguments.Count - idx;
5363                         Argument a = (Argument) arguments [idx];
5364                         Type t = a.Expr.Type;
5365
5366                         IntConstant.EmitInt (ig, count);
5367                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5368
5369                         int top = arguments.Count;
5370                         for (int j = idx; j < top; j++){
5371                                 a = (Argument) arguments [j];
5372                                 
5373                                 ig.Emit (OpCodes.Dup);
5374                                 IntConstant.EmitInt (ig, j - idx);
5375
5376                                 bool is_stobj, has_type_arg;
5377                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5378                                 if (is_stobj)
5379                                         ig.Emit (OpCodes.Ldelema, t);
5380
5381                                 a.Emit (ec);
5382
5383                                 if (has_type_arg)
5384                                         ig.Emit (op, t);
5385                                 else
5386                                         ig.Emit (op);
5387                         }
5388                 }
5389                 
5390                 /// <summary>
5391                 ///   Emits a list of resolved Arguments that are in the arguments
5392                 ///   ArrayList.
5393                 /// 
5394                 ///   The MethodBase argument might be null if the
5395                 ///   emission of the arguments is known not to contain
5396                 ///   a `params' field (for example in constructors or other routines
5397                 ///   that keep their arguments in this structure)
5398                 /// </summary>
5399                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
5400                 {
5401                         ParameterData pd;
5402                         if (mb != null)
5403                                 pd = GetParameterData (mb);
5404                         else
5405                                 pd = null;
5406
5407                         //
5408                         // If we are calling a params method with no arguments, special case it
5409                         //
5410                         if (arguments == null){
5411                                 if (pd != null && pd.Count > 0 &&
5412                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5413                                         ILGenerator ig = ec.ig;
5414
5415                                         IntConstant.EmitInt (ig, 0);
5416                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5417                                 }
5418
5419                                 return;
5420                         }
5421
5422                         int top = arguments.Count;
5423
5424                         for (int i = 0; i < top; i++){
5425                                 Argument a = (Argument) arguments [i];
5426
5427                                 if (pd != null){
5428                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5429                                                 //
5430                                                 // Special case if we are passing the same data as the
5431                                                 // params argument, do not put it in an array.
5432                                                 //
5433                                                 if (pd.ParameterType (i) == a.Type)
5434                                                         a.Emit (ec);
5435                                                 else
5436                                                         EmitParams (ec, i, arguments);
5437                                                 return;
5438                                         }
5439                                 }
5440                                             
5441                                 a.Emit (ec);
5442                         }
5443
5444                         if (pd != null && pd.Count > top &&
5445                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5446                                 ILGenerator ig = ec.ig;
5447
5448                                 IntConstant.EmitInt (ig, 0);
5449                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5450                         }
5451                 }
5452
5453                 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5454                                                ArrayList arguments)
5455                 {
5456                         ParameterData pd = GetParameterData (mb);
5457
5458                         if (arguments == null)
5459                                 return new Type [0];
5460
5461                         Argument a = (Argument) arguments [pd.Count - 1];
5462                         Arglist list = (Arglist) a.Expr;
5463
5464                         return list.ArgumentTypes;
5465                 }
5466
5467                 /// <summary>
5468                 /// This checks the ConditionalAttribute on the method 
5469                 /// </summary>
5470                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5471                 {
5472                         if (method.IsConstructor)
5473                                 return false;
5474
5475                         IMethodData md = TypeManager.GetMethod (method);
5476                         if (md != null)
5477                                 return md.IsExcluded (ec);
5478
5479                         // For some methods (generated by delegate class) GetMethod returns null
5480                         // because they are not included in builder_to_method table
5481                         if (method.DeclaringType is TypeBuilder)
5482                                 return false;
5483
5484                         return AttributeTester.IsConditionalMethodExcluded (method);
5485                 }
5486
5487                 /// <remarks>
5488                 ///   is_base tells whether we want to force the use of the `call'
5489                 ///   opcode instead of using callvirt.  Call is required to call
5490                 ///   a specific method, while callvirt will always use the most
5491                 ///   recent method in the vtable.
5492                 ///
5493                 ///   is_static tells whether this is an invocation on a static method
5494                 ///
5495                 ///   instance_expr is an expression that represents the instance
5496                 ///   it must be non-null if is_static is false.
5497                 ///
5498                 ///   method is the method to invoke.
5499                 ///
5500                 ///   Arguments is the list of arguments to pass to the method or constructor.
5501                 /// </remarks>
5502                 public static void EmitCall (EmitContext ec, bool is_base,
5503                                              bool is_static, Expression instance_expr,
5504                                              MethodBase method, ArrayList Arguments, Location loc)
5505                 {
5506                         ILGenerator ig = ec.ig;
5507                         bool struct_call = false;
5508                         bool this_call = false;
5509
5510                         Type decl_type = method.DeclaringType;
5511
5512                         if (!RootContext.StdLib) {
5513                                 // Replace any calls to the system's System.Array type with calls to
5514                                 // the newly created one.
5515                                 if (method == TypeManager.system_int_array_get_length)
5516                                         method = TypeManager.int_array_get_length;
5517                                 else if (method == TypeManager.system_int_array_get_rank)
5518                                         method = TypeManager.int_array_get_rank;
5519                                 else if (method == TypeManager.system_object_array_clone)
5520                                         method = TypeManager.object_array_clone;
5521                                 else if (method == TypeManager.system_int_array_get_length_int)
5522                                         method = TypeManager.int_array_get_length_int;
5523                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5524                                         method = TypeManager.int_array_get_lower_bound_int;
5525                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5526                                         method = TypeManager.int_array_get_upper_bound_int;
5527                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5528                                         method = TypeManager.void_array_copyto_array_int;
5529                         }
5530
5531                         //
5532                         // This checks ObsoleteAttribute on the method and on the declaring type
5533                         //
5534                         ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5535                         if (oa != null)
5536                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5537
5538                         oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5539                         if (oa != null) {
5540                                 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5541                         }
5542
5543
5544                         oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5545                         if (oa != null) {
5546                                 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5547                         }
5548
5549                         if (IsMethodExcluded (method, ec))
5550                                 return;
5551                         
5552                         if (!is_static){
5553                                 if (TypeManager.IsValueType (decl_type))
5554                                         struct_call = true;
5555                                 //
5556                                 // If this is ourselves, push "this"
5557                                 //
5558                                 if (instance_expr == null){
5559                                         this_call = true;
5560                                         ig.Emit (OpCodes.Ldarg_0);
5561                                 } else {
5562                                         Type itype = instance_expr.Type;
5563
5564                                         //
5565                                         // Push the instance expression
5566                                         //
5567                                         if (TypeManager.IsValueType (itype)){
5568                                                 //
5569                                                 // Special case: calls to a function declared in a 
5570                                                 // reference-type with a value-type argument need
5571                                                 // to have their value boxed.  
5572                                                 if (decl_type.IsValueType || itype.IsGenericParameter){
5573                                                         //
5574                                                         // If the expression implements IMemoryLocation, then
5575                                                         // we can optimize and use AddressOf on the
5576                                                         // return.
5577                                                         //
5578                                                         // If not we have to use some temporary storage for
5579                                                         // it.
5580                                                         if (instance_expr is IMemoryLocation){
5581                                                                 ((IMemoryLocation)instance_expr).
5582                                                                         AddressOf (ec, AddressOp.LoadStore);
5583                                                         }
5584                                                         else {
5585                                                                 instance_expr.Emit (ec);
5586                                                                 LocalBuilder temp = ig.DeclareLocal (itype);
5587                                                                 ig.Emit (OpCodes.Stloc, temp);
5588                                                                 ig.Emit (OpCodes.Ldloca, temp);
5589                                                         }
5590                                                         if (itype.IsGenericParameter)
5591                                                                 ig.Emit (OpCodes.Constrained, itype);
5592                                                         else
5593                                                                 struct_call = true;
5594                                                 } else {
5595                                                         instance_expr.Emit (ec);
5596                                                         ig.Emit (OpCodes.Box, itype);
5597                                                 } 
5598                                         } else
5599                                                 instance_expr.Emit (ec);
5600                                 }
5601                         }
5602
5603                         EmitArguments (ec, method, Arguments);
5604
5605                         OpCode call_op;
5606                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5607                                 call_op = OpCodes.Call;
5608                         else
5609                                 call_op = OpCodes.Callvirt;
5610
5611                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5612                                 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5613                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5614                                 return;
5615                         }
5616
5617                         //
5618                         // If you have:
5619                         // this.DoFoo ();
5620                         // and DoFoo is not virtual, you can omit the callvirt,
5621                         // because you don't need the null checking behavior.
5622                         //
5623                                 if (method is MethodInfo)
5624                                 ig.Emit (call_op, (MethodInfo) method);
5625                                 else
5626                                 ig.Emit (call_op, (ConstructorInfo) method);
5627                 }
5628                 
5629                 public override void Emit (EmitContext ec)
5630                 {
5631                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5632
5633                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5634                 }
5635                 
5636                 public override void EmitStatement (EmitContext ec)
5637                 {
5638                         Emit (ec);
5639
5640                         // 
5641                         // Pop the return value if there is one
5642                         //
5643                         if (method is MethodInfo){
5644                                 Type ret = ((MethodInfo)method).ReturnType;
5645                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5646                                         ec.ig.Emit (OpCodes.Pop);
5647                         }
5648                 }
5649         }
5650
5651         public class InvocationOrCast : ExpressionStatement
5652         {
5653                 Expression expr;
5654                 Expression argument;
5655
5656                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5657                 {
5658                         this.expr = expr;
5659                         this.argument = argument;
5660                         this.loc = loc;
5661                 }
5662
5663                 public override Expression DoResolve (EmitContext ec)
5664                 {
5665                         //
5666                         // First try to resolve it as a cast.
5667                         //
5668                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5669                         if (type != null) {
5670                                 Cast cast = new Cast (new TypeExpression (type, loc), argument, loc);
5671                                 return cast.Resolve (ec);
5672                         }
5673
5674                         //
5675                         // This can either be a type or a delegate invocation.
5676                         // Let's just resolve it and see what we'll get.
5677                         //
5678                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5679                         if (expr == null)
5680                                 return null;
5681
5682                         //
5683                         // Ok, so it's a Cast.
5684                         //
5685                         if (expr.eclass == ExprClass.Type) {
5686                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5687                                 return cast.Resolve (ec);
5688                         }
5689
5690                         //
5691                         // It's a delegate invocation.
5692                         //
5693                         if (!TypeManager.IsDelegateType (expr.Type)) {
5694                                 Error (149, "Method name expected");
5695                                 return null;
5696                         }
5697
5698                         ArrayList args = new ArrayList ();
5699                         args.Add (new Argument (argument, Argument.AType.Expression));
5700                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5701                         return invocation.Resolve (ec);
5702                 }
5703
5704                 void error201 ()
5705                 {
5706                         Error (201, "Only assignment, call, increment, decrement and new object " +
5707                                "expressions can be used as a statement");
5708                 }
5709
5710                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5711                 {
5712                         //
5713                         // First try to resolve it as a cast.
5714                         //
5715                         type = ec.DeclSpace.ResolveType (expr, true, loc);
5716                         if (type != null) {
5717                                 error201 ();
5718                                 return null;
5719                         }
5720
5721                         //
5722                         // This can either be a type or a delegate invocation.
5723                         // Let's just resolve it and see what we'll get.
5724                         //
5725                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5726                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5727                                 error201 ();
5728                                 return null;
5729                         }
5730
5731                         //
5732                         // It's a delegate invocation.
5733                         //
5734                         if (!TypeManager.IsDelegateType (expr.Type)) {
5735                                 Error (149, "Method name expected");
5736                                 return null;
5737                         }
5738
5739                         ArrayList args = new ArrayList ();
5740                         args.Add (new Argument (argument, Argument.AType.Expression));
5741                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5742                         return invocation.ResolveStatement (ec);
5743                 }
5744
5745                 public override void Emit (EmitContext ec)
5746                 {
5747                         throw new Exception ("Cannot happen");
5748                 }
5749
5750                 public override void EmitStatement (EmitContext ec)
5751                 {
5752                         throw new Exception ("Cannot happen");
5753                 }
5754         }
5755
5756         //
5757         // This class is used to "disable" the code generation for the
5758         // temporary variable when initializing value types.
5759         //
5760         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5761                 public void AddressOf (EmitContext ec, AddressOp Mode)
5762                 {
5763                         // nothing
5764                 }
5765         }
5766         
5767         /// <summary>
5768         ///    Implements the new expression 
5769         /// </summary>
5770         public class New : ExpressionStatement, IMemoryLocation {
5771                 public readonly ArrayList Arguments;
5772
5773                 //
5774                 // During bootstrap, it contains the RequestedType,
5775                 // but if `type' is not null, it *might* contain a NewDelegate
5776                 // (because of field multi-initialization)
5777                 //
5778                 public Expression RequestedType;
5779
5780                 MethodBase method = null;
5781
5782                 //
5783                 // If set, the new expression is for a value_target, and
5784                 // we will not leave anything on the stack.
5785                 //
5786                 Expression value_target;
5787                 bool value_target_set = false;
5788                 bool is_type_parameter = false;
5789                 
5790                 public New (Expression requested_type, ArrayList arguments, Location l)
5791                 {
5792                         RequestedType = requested_type;
5793                         Arguments = arguments;
5794                         loc = l;
5795                 }
5796
5797                 public bool SetValueTypeVariable (Expression value)
5798                 {
5799                         value_target = value;
5800                         value_target_set = true;
5801                         if (!(value_target is IMemoryLocation)){
5802                                 Error_UnexpectedKind ("variable");
5803                                 return false;
5804                         }
5805                         return true;
5806                 }
5807
5808                 //
5809                 // This function is used to disable the following code sequence for
5810                 // value type initialization:
5811                 //
5812                 // AddressOf (temporary)
5813                 // Construct/Init
5814                 // LoadTemporary
5815                 //
5816                 // Instead the provide will have provided us with the address on the
5817                 // stack to store the results.
5818                 //
5819                 static Expression MyEmptyExpression;
5820                 
5821                 public void DisableTemporaryValueType ()
5822                 {
5823                         if (MyEmptyExpression == null)
5824                                 MyEmptyExpression = new EmptyAddressOf ();
5825
5826                         //
5827                         // To enable this, look into:
5828                         // test-34 and test-89 and self bootstrapping.
5829                         //
5830                         // For instance, we can avoid a copy by using `newobj'
5831                         // instead of Call + Push-temp on value types.
5832 //                      value_target = MyEmptyExpression;
5833                 }
5834
5835                 public override Expression DoResolve (EmitContext ec)
5836                 {
5837                         //
5838                         // The New DoResolve might be called twice when initializing field
5839                         // expressions (see EmitFieldInitializers, the call to
5840                         // GetInitializerExpression will perform a resolve on the expression,
5841                         // and later the assign will trigger another resolution
5842                         //
5843                         // This leads to bugs (#37014)
5844                         //
5845                         if (type != null){
5846                                 if (RequestedType is NewDelegate)
5847                                         return RequestedType;
5848                                 return this;
5849                         }
5850                         
5851                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5852                         
5853                         if (type == null)
5854                                 return null;
5855                         
5856                         CheckObsoleteAttribute (type);
5857
5858                         bool IsDelegate = TypeManager.IsDelegateType (type);
5859                         
5860                         if (IsDelegate){
5861                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5862                                 if (RequestedType != null)
5863                                         if (!(RequestedType is NewDelegate))
5864                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5865                                 return RequestedType;
5866                         }
5867
5868                         if (type.IsGenericParameter) {
5869                                 if (!TypeManager.HasConstructorConstraint (type)) {
5870                                         Error (304, String.Format (
5871                                                        "Cannot create an instance of the " +
5872                                                        "variable type '{0}' because it " +
5873                                                        "doesn't have the new() constraint",
5874                                                        type));
5875                                         return null;
5876                                 }
5877
5878                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5879                                         Error (417, String.Format (
5880                                                        "`{0}': cannot provide arguments " +
5881                                                        "when creating an instance of a " +
5882                                                        "variable type.", type));
5883                                         return null;
5884                                 }
5885
5886                                 is_type_parameter = true;
5887                                 eclass = ExprClass.Value;
5888                                 return this;
5889                         } else if (type.IsInterface || type.IsAbstract){
5890                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5891                                 return null;
5892                         }
5893                         
5894                         bool is_struct = type.IsValueType;
5895                         eclass = ExprClass.Value;
5896
5897                         //
5898                         // SRE returns a match for .ctor () on structs (the object constructor), 
5899                         // so we have to manually ignore it.
5900                         //
5901                         if (is_struct && Arguments == null)
5902                                 return this;
5903                         
5904                         Expression ml;
5905                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5906                                                 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5907                                                 MemberTypes.Constructor,
5908                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5909
5910                         if (ml == null)
5911                                 return null;
5912                         
5913                         if (! (ml is MethodGroupExpr)){
5914                                 if (!is_struct){
5915                                         ml.Error_UnexpectedKind ("method group");
5916                                         return null;
5917                                 }
5918                         }
5919
5920                         if (ml != null) {
5921                                 if (Arguments != null){
5922                                         foreach (Argument a in Arguments){
5923                                                 if (!a.Resolve (ec, loc))
5924                                                         return null;
5925                                         }
5926                                 }
5927
5928                                 method = Invocation.OverloadResolve (
5929                                         ec, (MethodGroupExpr) ml, Arguments, false, loc);
5930                                 
5931                         }
5932
5933                         if (method == null) { 
5934                                 if (!is_struct || Arguments.Count > 0) {
5935                                         Error (1501, String.Format (
5936                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5937                                             TypeManager.CSharpName (type)));
5938                                         return null;
5939                                 }
5940                         }
5941
5942                         return this;
5943                 }
5944
5945                 bool DoEmitTypeParameter (EmitContext ec)
5946                 {
5947                         ILGenerator ig = ec.ig;
5948
5949                         ig.Emit (OpCodes.Ldtoken, type);
5950                         ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5951                         ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5952                         ig.Emit (OpCodes.Unbox_Any, type);
5953
5954                         return true;
5955                 }
5956
5957                 //
5958                 // This DoEmit can be invoked in two contexts:
5959                 //    * As a mechanism that will leave a value on the stack (new object)
5960                 //    * As one that wont (init struct)
5961                 //
5962                 // You can control whether a value is required on the stack by passing
5963                 // need_value_on_stack.  The code *might* leave a value on the stack
5964                 // so it must be popped manually
5965                 //
5966                 // If we are dealing with a ValueType, we have a few
5967                 // situations to deal with:
5968                 //
5969                 //    * The target is a ValueType, and we have been provided
5970                 //      the instance (this is easy, we are being assigned).
5971                 //
5972                 //    * The target of New is being passed as an argument,
5973                 //      to a boxing operation or a function that takes a
5974                 //      ValueType.
5975                 //
5976                 //      In this case, we need to create a temporary variable
5977                 //      that is the argument of New.
5978                 //
5979                 // Returns whether a value is left on the stack
5980                 //
5981                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5982                 {
5983                         bool is_value_type = type.IsValueType;
5984                         ILGenerator ig = ec.ig;
5985
5986                         if (is_value_type){
5987                                 IMemoryLocation ml;
5988
5989                                 // Allow DoEmit() to be called multiple times.
5990                                 // We need to create a new LocalTemporary each time since
5991                                 // you can't share LocalBuilders among ILGeneators.
5992                                 if (!value_target_set)
5993                                         value_target = new LocalTemporary (ec, type);
5994
5995                                 ml = (IMemoryLocation) value_target;
5996                                 ml.AddressOf (ec, AddressOp.Store);
5997                         }
5998
5999                         if (method != null)
6000                                 Invocation.EmitArguments (ec, method, Arguments);
6001
6002                         if (is_value_type){
6003                                 if (method == null)
6004                                         ig.Emit (OpCodes.Initobj, type);
6005                                 else 
6006                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6007                                 if (need_value_on_stack){
6008                                         value_target.Emit (ec);
6009                                         return true;
6010                                 }
6011                                 return false;
6012                         } else {
6013                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6014                                 return true;
6015                         }
6016                 }
6017
6018                 public override void Emit (EmitContext ec)
6019                 {
6020                         if (is_type_parameter)
6021                                 DoEmitTypeParameter (ec);
6022                         else
6023                                 DoEmit (ec, true);
6024                 }
6025                 
6026                 public override void EmitStatement (EmitContext ec)
6027                 {
6028                         if (is_type_parameter)
6029                                 throw new InvalidOperationException ();
6030
6031                         if (DoEmit (ec, false))
6032                                 ec.ig.Emit (OpCodes.Pop);
6033                 }
6034
6035                 public void AddressOf (EmitContext ec, AddressOp Mode)
6036                 {
6037                         if (is_type_parameter)
6038                                 throw new InvalidOperationException ();
6039
6040                         if (!type.IsValueType){
6041                                 //
6042                                 // We throw an exception.  So far, I believe we only need to support
6043                                 // value types:
6044                                 // foreach (int j in new StructType ())
6045                                 // see bug 42390
6046                                 //
6047                                 throw new Exception ("AddressOf should not be used for classes");
6048                         }
6049
6050                         if (!value_target_set)
6051                                 value_target = new LocalTemporary (ec, type);
6052                                         
6053                         IMemoryLocation ml = (IMemoryLocation) value_target;
6054                         ml.AddressOf (ec, AddressOp.Store);
6055                         if (method != null)
6056                                 Invocation.EmitArguments (ec, method, Arguments);
6057
6058                         if (method == null)
6059                                 ec.ig.Emit (OpCodes.Initobj, type);
6060                         else 
6061                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6062                         
6063                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6064                 }
6065         }
6066
6067         /// <summary>
6068         ///   14.5.10.2: Represents an array creation expression.
6069         /// </summary>
6070         ///
6071         /// <remarks>
6072         ///   There are two possible scenarios here: one is an array creation
6073         ///   expression that specifies the dimensions and optionally the
6074         ///   initialization data and the other which does not need dimensions
6075         ///   specified but where initialization data is mandatory.
6076         /// </remarks>
6077         public class ArrayCreation : Expression {
6078                 Expression requested_base_type;
6079                 ArrayList initializers;
6080
6081                 //
6082                 // The list of Argument types.
6083                 // This is used to construct the `newarray' or constructor signature
6084                 //
6085                 ArrayList arguments;
6086
6087                 //
6088                 // Method used to create the array object.
6089                 //
6090                 MethodBase new_method = null;
6091                 
6092                 Type array_element_type;
6093                 Type underlying_type;
6094                 bool is_one_dimensional = false;
6095                 bool is_builtin_type = false;
6096                 bool expect_initializers = false;
6097                 int num_arguments = 0;
6098                 int dimensions = 0;
6099                 string rank;
6100
6101                 ArrayList array_data;
6102
6103                 Hashtable bounds;
6104
6105                 //
6106                 // The number of array initializers that we can handle
6107                 // via the InitializeArray method - through EmitStaticInitializers
6108                 //
6109                 int num_automatic_initializers;
6110
6111                 const int max_automatic_initializers = 6;
6112                 
6113                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6114                 {
6115                         this.requested_base_type = requested_base_type;
6116                         this.initializers = initializers;
6117                         this.rank = rank;
6118                         loc = l;
6119
6120                         arguments = new ArrayList ();
6121
6122                         foreach (Expression e in exprs) {
6123                                 arguments.Add (new Argument (e, Argument.AType.Expression));
6124                                 num_arguments++;
6125                         }
6126                 }
6127
6128                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6129                 {
6130                         this.requested_base_type = requested_base_type;
6131                         this.initializers = initializers;
6132                         this.rank = rank;
6133                         loc = l;
6134
6135                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6136                         //
6137                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
6138                         //
6139                         //dimensions = tmp.Length - 1;
6140                         expect_initializers = true;
6141                 }
6142
6143                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6144                 {
6145                         StringBuilder sb = new StringBuilder (rank);
6146                         
6147                         sb.Append ("[");
6148                         for (int i = 1; i < idx_count; i++)
6149                                 sb.Append (",");
6150                         
6151                         sb.Append ("]");
6152
6153                         return new ComposedCast (base_type, sb.ToString (), loc);
6154                 }
6155
6156                 void Error_IncorrectArrayInitializer ()
6157                 {
6158                         Error (178, "Incorrectly structured array initializer");
6159                 }
6160                 
6161                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6162                 {
6163                         if (specified_dims) { 
6164                                 Argument a = (Argument) arguments [idx];
6165                                 
6166                                 if (!a.Resolve (ec, loc))
6167                                         return false;
6168                                 
6169                                 if (!(a.Expr is Constant)) {
6170                                         Error (150, "A constant value is expected");
6171                                         return false;
6172                                 }
6173                                 
6174                                 int value = (int) ((Constant) a.Expr).GetValue ();
6175                                 
6176                                 if (value != probe.Count) {
6177                                         Error_IncorrectArrayInitializer ();
6178                                         return false;
6179                                 }
6180                                 
6181                                 bounds [idx] = value;
6182                         }
6183
6184                         int child_bounds = -1;
6185                         foreach (object o in probe) {
6186                                 if (o is ArrayList) {
6187                                         int current_bounds = ((ArrayList) o).Count;
6188                                         
6189                                         if (child_bounds == -1) 
6190                                                 child_bounds = current_bounds;
6191
6192                                         else if (child_bounds != current_bounds){
6193                                                 Error_IncorrectArrayInitializer ();
6194                                                 return false;
6195                                         }
6196                                         if (specified_dims && (idx + 1 >= arguments.Count)){
6197                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6198                                                 return false;
6199                                         }
6200                                         
6201                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
6202                                         if (!ret)
6203                                                 return false;
6204                                 } else {
6205                                         if (child_bounds != -1){
6206                                                 Error_IncorrectArrayInitializer ();
6207                                                 return false;
6208                                         }
6209                                         
6210                                         Expression tmp = (Expression) o;
6211                                         tmp = tmp.Resolve (ec);
6212                                         if (tmp == null)
6213                                                 continue;
6214
6215                                         // Console.WriteLine ("I got: " + tmp);
6216                                         // Handle initialization from vars, fields etc.
6217
6218                                         Expression conv = Convert.ImplicitConversionRequired (
6219                                                 ec, tmp, underlying_type, loc);
6220                                         
6221                                         if (conv == null) 
6222                                                 return false;
6223
6224                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6225                                                 // These are subclasses of Constant that can appear as elements of an
6226                                                 // array that cannot be statically initialized (with num_automatic_initializers
6227                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6228                                                 array_data.Add (conv);
6229                                         } else if (conv is Constant) {
6230                                                 // These are the types of Constant that can appear in arrays that can be
6231                                                 // statically allocated.
6232                                                 array_data.Add (conv);
6233                                                 num_automatic_initializers++;
6234                                         } else
6235                                                 array_data.Add (conv);
6236                                 }
6237                         }
6238
6239                         return true;
6240                 }
6241                 
6242                 public void UpdateIndices (EmitContext ec)
6243                 {
6244                         int i = 0;
6245                         for (ArrayList probe = initializers; probe != null;) {
6246                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6247                                         Expression e = new IntConstant (probe.Count);
6248                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6249
6250                                         bounds [i++] =  probe.Count;
6251                                         
6252                                         probe = (ArrayList) probe [0];
6253                                         
6254                                 } else {
6255                                         Expression e = new IntConstant (probe.Count);
6256                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6257
6258                                         bounds [i++] = probe.Count;
6259                                         probe = null;
6260                                 }
6261                         }
6262
6263                 }
6264                 
6265                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6266                 {
6267                         if (initializers == null) {
6268                                 if (expect_initializers)
6269                                         return false;
6270                                 else
6271                                         return true;
6272                         }
6273                         
6274                         if (underlying_type == null)
6275                                 return false;
6276                         
6277                         //
6278                         // We use this to store all the date values in the order in which we
6279                         // will need to store them in the byte blob later
6280                         //
6281                         array_data = new ArrayList ();
6282                         bounds = new Hashtable ();
6283                         
6284                         bool ret;
6285
6286                         if (arguments != null) {
6287                                 ret = CheckIndices (ec, initializers, 0, true);
6288                                 return ret;
6289                         } else {
6290                                 arguments = new ArrayList ();
6291
6292                                 ret = CheckIndices (ec, initializers, 0, false);
6293                                 
6294                                 if (!ret)
6295                                         return false;
6296                                 
6297                                 UpdateIndices (ec);
6298                                 
6299                                 if (arguments.Count != dimensions) {
6300                                         Error_IncorrectArrayInitializer ();
6301                                         return false;
6302                                 }
6303
6304                                 return ret;
6305                         }
6306                 }
6307
6308                 void Error_NegativeArrayIndex ()
6309                 {
6310                         Error (284, "Can not create array with a negative size");
6311                 }
6312                 
6313                 //
6314                 // Converts `source' to an int, uint, long or ulong.
6315                 //
6316                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6317                 {
6318                         Expression target;
6319                         
6320                         bool old_checked = ec.CheckState;
6321                         ec.CheckState = true;
6322                         
6323                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6324                         if (target == null){
6325                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6326                                 if (target == null){
6327                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6328                                         if (target == null){
6329                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6330                                                 if (target == null)
6331                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6332                                         }
6333                                 }
6334                         } 
6335                         ec.CheckState = old_checked;
6336
6337                         //
6338                         // Only positive constants are allowed at compile time
6339                         //
6340                         if (target is Constant){
6341                                 if (target is IntConstant){
6342                                         if (((IntConstant) target).Value < 0){
6343                                                 Error_NegativeArrayIndex ();
6344                                                 return null;
6345                                         }
6346                                 }
6347
6348                                 if (target is LongConstant){
6349                                         if (((LongConstant) target).Value < 0){
6350                                                 Error_NegativeArrayIndex ();
6351                                                 return null;
6352                                         }
6353                                 }
6354                                 
6355                         }
6356
6357                         return target;
6358                 }
6359
6360                 //
6361                 // Creates the type of the array
6362                 //
6363                 bool LookupType (EmitContext ec)
6364                 {
6365                         StringBuilder array_qualifier = new StringBuilder (rank);
6366
6367                         //
6368                         // `In the first form allocates an array instace of the type that results
6369                         // from deleting each of the individual expression from the expression list'
6370                         //
6371                         if (num_arguments > 0) {
6372                                 array_qualifier.Append ("[");
6373                                 for (int i = num_arguments-1; i > 0; i--)
6374                                         array_qualifier.Append (",");
6375                                 array_qualifier.Append ("]");                           
6376                         }
6377
6378                         //
6379                         // Lookup the type
6380                         //
6381                         Expression array_type_expr;
6382                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6383                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
6384
6385                         if (type == null)
6386                                 return false;
6387
6388                         underlying_type = type;
6389                         if (underlying_type.IsArray)
6390                                 underlying_type = TypeManager.GetElementType (underlying_type);
6391                         dimensions = type.GetArrayRank ();
6392
6393                         return true;
6394                 }
6395                 
6396                 public override Expression DoResolve (EmitContext ec)
6397                 {
6398                         int arg_count;
6399
6400                         if (!LookupType (ec))
6401                                 return null;
6402                         
6403                         //
6404                         // First step is to validate the initializers and fill
6405                         // in any missing bits
6406                         //
6407                         if (!ValidateInitializers (ec, type))
6408                                 return null;
6409
6410                         if (arguments == null)
6411                                 arg_count = 0;
6412                         else {
6413                                 arg_count = arguments.Count;
6414                                 foreach (Argument a in arguments){
6415                                         if (!a.Resolve (ec, loc))
6416                                                 return null;
6417
6418                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6419                                         if (real_arg == null)
6420                                                 return null;
6421
6422                                         a.Expr = real_arg;
6423                                 }
6424                         }
6425                         
6426                         array_element_type = TypeManager.GetElementType (type);
6427
6428                         if (arg_count == 1) {
6429                                 is_one_dimensional = true;
6430                                 eclass = ExprClass.Value;
6431                                 return this;
6432                         }
6433
6434                         is_builtin_type = TypeManager.IsBuiltinType (type);
6435
6436                         if (is_builtin_type) {
6437                                 Expression ml;
6438                                 
6439                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6440                                                    AllBindingFlags, loc);
6441                                 
6442                                 if (!(ml is MethodGroupExpr)) {
6443                                         ml.Error_UnexpectedKind ("method group");
6444                                         return null;
6445                                 }
6446                                 
6447                                 if (ml == null) {
6448                                         Error (-6, "New invocation: Can not find a constructor for " +
6449                                                       "this argument list");
6450                                         return null;
6451                                 }
6452                                 
6453                                 new_method = Invocation.OverloadResolve (
6454                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6455
6456                                 if (new_method == null) {
6457                                         Error (-6, "New invocation: Can not find a constructor for " +
6458                                                       "this argument list");
6459                                         return null;
6460                                 }
6461                                 
6462                                 eclass = ExprClass.Value;
6463                                 return this;
6464                         } else {
6465                                 ModuleBuilder mb = CodeGen.Module.Builder;
6466                                 ArrayList args = new ArrayList ();
6467                                 
6468                                 if (arguments != null) {
6469                                         for (int i = 0; i < arg_count; i++)
6470                                                 args.Add (TypeManager.int32_type);
6471                                 }
6472                                 
6473                                 Type [] arg_types = null;
6474
6475                                 if (args.Count > 0)
6476                                         arg_types = new Type [args.Count];
6477                                 
6478                                 args.CopyTo (arg_types, 0);
6479                                 
6480                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6481                                                             arg_types);
6482
6483                                 if (new_method == null) {
6484                                         Error (-6, "New invocation: Can not find a constructor for " +
6485                                                       "this argument list");
6486                                         return null;
6487                                 }
6488                                 
6489                                 eclass = ExprClass.Value;
6490                                 return this;
6491                         }
6492                 }
6493
6494                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6495                 {
6496                         int factor;
6497                         byte [] data;
6498                         byte [] element;
6499                         int count = array_data.Count;
6500
6501                         if (underlying_type.IsEnum)
6502                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6503                         
6504                         factor = GetTypeSize (underlying_type);
6505                         if (factor == 0)
6506                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6507
6508                         data = new byte [(count * factor + 4) & ~3];
6509                         int idx = 0;
6510                         
6511                         for (int i = 0; i < count; ++i) {
6512                                 object v = array_data [i];
6513
6514                                 if (v is EnumConstant)
6515                                         v = ((EnumConstant) v).Child;
6516                                 
6517                                 if (v is Constant && !(v is StringConstant))
6518                                         v = ((Constant) v).GetValue ();
6519                                 else {
6520                                         idx += factor;
6521                                         continue;
6522                                 }
6523                                 
6524                                 if (underlying_type == TypeManager.int64_type){
6525                                         if (!(v is Expression)){
6526                                                 long val = (long) v;
6527                                                 
6528                                                 for (int j = 0; j < factor; ++j) {
6529                                                         data [idx + j] = (byte) (val & 0xFF);
6530                                                         val = (val >> 8);
6531                                                 }
6532                                         }
6533                                 } else if (underlying_type == TypeManager.uint64_type){
6534                                         if (!(v is Expression)){
6535                                                 ulong val = (ulong) v;
6536
6537                                                 for (int j = 0; j < factor; ++j) {
6538                                                         data [idx + j] = (byte) (val & 0xFF);
6539                                                         val = (val >> 8);
6540                                                 }
6541                                         }
6542                                 } else if (underlying_type == TypeManager.float_type) {
6543                                         if (!(v is Expression)){
6544                                                 element = BitConverter.GetBytes ((float) v);
6545                                                         
6546                                                 for (int j = 0; j < factor; ++j)
6547                                                         data [idx + j] = element [j];
6548                                         }
6549                                 } else if (underlying_type == TypeManager.double_type) {
6550                                         if (!(v is Expression)){
6551                                                 element = BitConverter.GetBytes ((double) v);
6552
6553                                                 for (int j = 0; j < factor; ++j)
6554                                                         data [idx + j] = element [j];
6555                                         }
6556                                 } else if (underlying_type == TypeManager.char_type){
6557                                         if (!(v is Expression)){
6558                                                 int val = (int) ((char) v);
6559                                                 
6560                                                 data [idx] = (byte) (val & 0xff);
6561                                                 data [idx+1] = (byte) (val >> 8);
6562                                         }
6563                                 } else if (underlying_type == TypeManager.short_type){
6564                                         if (!(v is Expression)){
6565                                                 int val = (int) ((short) v);
6566                                         
6567                                                 data [idx] = (byte) (val & 0xff);
6568                                                 data [idx+1] = (byte) (val >> 8);
6569                                         }
6570                                 } else if (underlying_type == TypeManager.ushort_type){
6571                                         if (!(v is Expression)){
6572                                                 int val = (int) ((ushort) v);
6573                                         
6574                                                 data [idx] = (byte) (val & 0xff);
6575                                                 data [idx+1] = (byte) (val >> 8);
6576                                         }
6577                                 } else if (underlying_type == TypeManager.int32_type) {
6578                                         if (!(v is Expression)){
6579                                                 int val = (int) v;
6580                                         
6581                                                 data [idx]   = (byte) (val & 0xff);
6582                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6583                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6584                                                 data [idx+3] = (byte) (val >> 24);
6585                                         }
6586                                 } else if (underlying_type == TypeManager.uint32_type) {
6587                                         if (!(v is Expression)){
6588                                                 uint val = (uint) v;
6589                                         
6590                                                 data [idx]   = (byte) (val & 0xff);
6591                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6592                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6593                                                 data [idx+3] = (byte) (val >> 24);
6594                                         }
6595                                 } else if (underlying_type == TypeManager.sbyte_type) {
6596                                         if (!(v is Expression)){
6597                                                 sbyte val = (sbyte) v;
6598                                                 data [idx] = (byte) val;
6599                                         }
6600                                 } else if (underlying_type == TypeManager.byte_type) {
6601                                         if (!(v is Expression)){
6602                                                 byte val = (byte) v;
6603                                                 data [idx] = (byte) val;
6604                                         }
6605                                 } else if (underlying_type == TypeManager.bool_type) {
6606                                         if (!(v is Expression)){
6607                                                 bool val = (bool) v;
6608                                                 data [idx] = (byte) (val ? 1 : 0);
6609                                         }
6610                                 } else if (underlying_type == TypeManager.decimal_type){
6611                                         if (!(v is Expression)){
6612                                                 int [] bits = Decimal.GetBits ((decimal) v);
6613                                                 int p = idx;
6614
6615                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6616                                                 int [] nbits = new int [4];
6617                                                 nbits [0] = bits [3];
6618                                                 nbits [1] = bits [2];
6619                                                 nbits [2] = bits [0];
6620                                                 nbits [3] = bits [1];
6621                                                 
6622                                                 for (int j = 0; j < 4; j++){
6623                                                         data [p++] = (byte) (nbits [j] & 0xff);
6624                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6625                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6626                                                         data [p++] = (byte) (nbits [j] >> 24);
6627                                                 }
6628                                         }
6629                                 } else
6630                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6631
6632                                 idx += factor;
6633                         }
6634
6635                         return data;
6636                 }
6637
6638                 //
6639                 // Emits the initializers for the array
6640                 //
6641                 void EmitStaticInitializers (EmitContext ec)
6642                 {
6643                         //
6644                         // First, the static data
6645                         //
6646                         FieldBuilder fb;
6647                         ILGenerator ig = ec.ig;
6648                         
6649                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6650
6651                         fb = RootContext.MakeStaticData (data);
6652
6653                         ig.Emit (OpCodes.Dup);
6654                         ig.Emit (OpCodes.Ldtoken, fb);
6655                         ig.Emit (OpCodes.Call,
6656                                  TypeManager.void_initializearray_array_fieldhandle);
6657                 }
6658
6659                 //
6660                 // Emits pieces of the array that can not be computed at compile
6661                 // time (variables and string locations).
6662                 //
6663                 // This always expect the top value on the stack to be the array
6664                 //
6665                 void EmitDynamicInitializers (EmitContext ec)
6666                 {
6667                         ILGenerator ig = ec.ig;
6668                         int dims = bounds.Count;
6669                         int [] current_pos = new int [dims];
6670                         int top = array_data.Count;
6671
6672                         MethodInfo set = null;
6673
6674                         if (dims != 1){
6675                                 Type [] args;
6676                                 ModuleBuilder mb = null;
6677                                 mb = CodeGen.Module.Builder;
6678                                 args = new Type [dims + 1];
6679
6680                                 int j;
6681                                 for (j = 0; j < dims; j++)
6682                                         args [j] = TypeManager.int32_type;
6683
6684                                 args [j] = array_element_type;
6685                                 
6686                                 set = mb.GetArrayMethod (
6687                                         type, "Set",
6688                                         CallingConventions.HasThis | CallingConventions.Standard,
6689                                         TypeManager.void_type, args);
6690                         }
6691                         
6692                         for (int i = 0; i < top; i++){
6693
6694                                 Expression e = null;
6695
6696                                 if (array_data [i] is Expression)
6697                                         e = (Expression) array_data [i];
6698
6699                                 if (e != null) {
6700                                         //
6701                                         // Basically we do this for string literals and
6702                                         // other non-literal expressions
6703                                         //
6704                                         if (e is EnumConstant){
6705                                                 e = ((EnumConstant) e).Child;
6706                                         }
6707                                         
6708                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6709                                             num_automatic_initializers <= max_automatic_initializers) {
6710                                                 Type etype = e.Type;
6711                                                 
6712                                                 ig.Emit (OpCodes.Dup);
6713
6714                                                 for (int idx = 0; idx < dims; idx++) 
6715                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6716
6717                                                 //
6718                                                 // If we are dealing with a struct, get the
6719                                                 // address of it, so we can store it.
6720                                                 //
6721                                                 if ((dims == 1) && 
6722                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6723                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6724                                                      etype == TypeManager.decimal_type)) {
6725                                                         if (e is New){
6726                                                                 New n = (New) e;
6727
6728                                                                 //
6729                                                                 // Let new know that we are providing
6730                                                                 // the address where to store the results
6731                                                                 //
6732                                                                 n.DisableTemporaryValueType ();
6733                                                         }
6734
6735                                                         ig.Emit (OpCodes.Ldelema, etype);
6736                                                 }
6737
6738                                                 e.Emit (ec);
6739
6740                                                 if (dims == 1)
6741                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
6742                                                 else 
6743                                                         ig.Emit (OpCodes.Call, set);
6744                                                 
6745                                         }
6746                                 }
6747                                 
6748                                 //
6749                                 // Advance counter
6750                                 //
6751                                 for (int j = dims - 1; j >= 0; j--){
6752                                         current_pos [j]++;
6753                                         if (current_pos [j] < (int) bounds [j])
6754                                                 break;
6755                                         current_pos [j] = 0;
6756                                 }
6757                         }
6758                 }
6759
6760                 void EmitArrayArguments (EmitContext ec)
6761                 {
6762                         ILGenerator ig = ec.ig;
6763                         
6764                         foreach (Argument a in arguments) {
6765                                 Type atype = a.Type;
6766                                 a.Emit (ec);
6767
6768                                 if (atype == TypeManager.uint64_type)
6769                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6770                                 else if (atype == TypeManager.int64_type)
6771                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6772                         }
6773                 }
6774                 
6775                 public override void Emit (EmitContext ec)
6776                 {
6777                         ILGenerator ig = ec.ig;
6778                         
6779                         EmitArrayArguments (ec);
6780                         if (is_one_dimensional)
6781                                 ig.Emit (OpCodes.Newarr, array_element_type);
6782                         else {
6783                                 if (is_builtin_type) 
6784                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6785                                 else 
6786                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6787                         }
6788                         
6789                         if (initializers != null){
6790                                 //
6791                                 // FIXME: Set this variable correctly.
6792                                 // 
6793                                 bool dynamic_initializers = true;
6794
6795                                 // This will never be true for array types that cannot be statically
6796                                 // initialized. num_automatic_initializers will always be zero.  See
6797                                 // CheckIndices.
6798                                         if (num_automatic_initializers > max_automatic_initializers)
6799                                                 EmitStaticInitializers (ec);
6800                                 
6801                                 if (dynamic_initializers)
6802                                         EmitDynamicInitializers (ec);
6803                         }
6804                 }
6805                 
6806                 public object EncodeAsAttribute ()
6807                 {
6808                         if (!is_one_dimensional){
6809                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6810                                 return null;
6811                         }
6812
6813                         if (array_data == null){
6814                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6815                                 return null;
6816                         }
6817                         
6818                         object [] ret = new object [array_data.Count];
6819                         int i = 0;
6820                         foreach (Expression e in array_data){
6821                                 object v;
6822                                 
6823                                 if (e is NullLiteral)
6824                                         v = null;
6825                                 else {
6826                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
6827                                                 return null;
6828                                 }
6829                                 ret [i++] = v;
6830                         }
6831                         return ret;
6832                 }
6833
6834                 public Expression TurnIntoConstant ()
6835                 {
6836                         //
6837                         // Should use something like the above attribute thing.
6838                         // It should return a subclass of Constant that just returns
6839                         // the computed value of the array
6840                         //
6841                         throw new Exception ("Does not support yet Turning array into a Constant");
6842                 }
6843         }
6844         
6845         /// <summary>
6846         ///   Represents the `this' construct
6847         /// </summary>
6848         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6849
6850                 Block block;
6851                 VariableInfo variable_info;
6852                 
6853                 public This (Block block, Location loc)
6854                 {
6855                         this.loc = loc;
6856                         this.block = block;
6857                 }
6858
6859                 public This (Location loc)
6860                 {
6861                         this.loc = loc;
6862                 }
6863
6864                 public VariableInfo VariableInfo {
6865                         get { return variable_info; }
6866                 }
6867
6868                 public bool VerifyFixed (bool is_expression)
6869                 {
6870                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6871                                 return false;
6872                         else
6873                                 return variable_info.LocalInfo.IsFixed;
6874                 }
6875
6876                 public bool ResolveBase (EmitContext ec)
6877                 {
6878                         eclass = ExprClass.Variable;
6879
6880                         if (ec.TypeContainer.CurrentType != null)
6881                                 type = ec.TypeContainer.CurrentType.ResolveType (ec);
6882                         else
6883                                 type = ec.ContainerType;
6884
6885                         if (ec.IsStatic) {
6886                                 Error (26, "Keyword this not valid in static code");
6887                                 return false;
6888                         }
6889
6890                         if ((block != null) && (block.ThisVariable != null))
6891                                 variable_info = block.ThisVariable.VariableInfo;
6892
6893                         return true;
6894                 }
6895
6896                 public override Expression DoResolve (EmitContext ec)
6897                 {
6898                         if (!ResolveBase (ec))
6899                                 return null;
6900
6901                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6902                                 Error (188, "The this object cannot be used before all " +
6903                                        "of its fields are assigned to");
6904                                 variable_info.SetAssigned (ec);
6905                                 return this;
6906                         }
6907
6908                         if (ec.IsFieldInitializer) {
6909                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6910                                        "a method or a property.");
6911                                 return null;
6912                         }
6913
6914                         return this;
6915                 }
6916
6917                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6918                 {
6919                         if (!ResolveBase (ec))
6920                                 return null;
6921
6922                         if (variable_info != null)
6923                                 variable_info.SetAssigned (ec);
6924                         
6925                         if (ec.TypeContainer is Class){
6926                                 Error (1604, "Cannot assign to `this'");
6927                                 return null;
6928                         }
6929
6930                         return this;
6931                 }
6932
6933                 public override void Emit (EmitContext ec)
6934                 {
6935                         ILGenerator ig = ec.ig;
6936
6937                         ec.EmitThis ();
6938                         if (ec.TypeContainer is Struct)
6939                                 ig.Emit (OpCodes.Ldobj, type);
6940                 }
6941
6942                 public void EmitAssign (EmitContext ec, Expression source)
6943                 {
6944                         ILGenerator ig = ec.ig;
6945                         
6946                         if (ec.TypeContainer is Struct){
6947                                 ec.EmitThis ();
6948                                 source.Emit (ec);
6949                                 ig.Emit (OpCodes.Stobj, type);
6950                         } else {
6951                                 source.Emit (ec);
6952                                 ig.Emit (OpCodes.Starg, 0);
6953                         }
6954                 }
6955
6956                 public void AddressOf (EmitContext ec, AddressOp mode)
6957                 {
6958                         ec.EmitThis ();
6959
6960                         // FIMXE
6961                         // FIGURE OUT WHY LDARG_S does not work
6962                         //
6963                         // consider: struct X { int val; int P { set { val = value; }}}
6964                         //
6965                         // Yes, this looks very bad. Look at `NOTAS' for
6966                         // an explanation.
6967                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6968                 }
6969         }
6970
6971         /// <summary>
6972         ///   Represents the `__arglist' construct
6973         /// </summary>
6974         public class ArglistAccess : Expression
6975         {
6976                 public ArglistAccess (Location loc)
6977                 {
6978                         this.loc = loc;
6979                 }
6980
6981                 public bool ResolveBase (EmitContext ec)
6982                 {
6983                         eclass = ExprClass.Variable;
6984                         type = TypeManager.runtime_argument_handle_type;
6985                         return true;
6986                 }
6987
6988                 public override Expression DoResolve (EmitContext ec)
6989                 {
6990                         if (!ResolveBase (ec))
6991                                 return null;
6992
6993                         if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
6994                                 Error (190, "The __arglist construct is valid only within " +
6995                                        "a variable argument method.");
6996                                 return null;
6997                         }
6998
6999                         return this;
7000                 }
7001
7002                 public override void Emit (EmitContext ec)
7003                 {
7004                         ec.ig.Emit (OpCodes.Arglist);
7005                 }
7006         }
7007
7008         /// <summary>
7009         ///   Represents the `__arglist (....)' construct
7010         /// </summary>
7011         public class Arglist : Expression
7012         {
7013                 public readonly Argument[] Arguments;
7014
7015                 public Arglist (Argument[] args, Location l)
7016                 {
7017                         Arguments = args;
7018                         loc = l;
7019                 }
7020
7021                 public Type[] ArgumentTypes {
7022                         get {
7023                                 Type[] retval = new Type [Arguments.Length];
7024                                 for (int i = 0; i < Arguments.Length; i++)
7025                                         retval [i] = Arguments [i].Type;
7026                                 return retval;
7027                         }
7028                 }
7029
7030                 public override Expression DoResolve (EmitContext ec)
7031                 {
7032                         eclass = ExprClass.Variable;
7033                         type = TypeManager.runtime_argument_handle_type;
7034
7035                         foreach (Argument arg in Arguments) {
7036                                 if (!arg.Resolve (ec, loc))
7037                                         return null;
7038                         }
7039
7040                         return this;
7041                 }
7042
7043                 public override void Emit (EmitContext ec)
7044                 {
7045                         foreach (Argument arg in Arguments)
7046                                 arg.Emit (ec);
7047                 }
7048         }
7049
7050         //
7051         // This produces the value that renders an instance, used by the iterators code
7052         //
7053         public class ProxyInstance : Expression, IMemoryLocation  {
7054                 public override Expression DoResolve (EmitContext ec)
7055                 {
7056                         eclass = ExprClass.Variable;
7057                         type = ec.ContainerType;
7058                         return this;
7059                 }
7060                 
7061                 public override void Emit (EmitContext ec)
7062                 {
7063                         ec.ig.Emit (OpCodes.Ldarg_0);
7064
7065                 }
7066                 
7067                 public void AddressOf (EmitContext ec, AddressOp mode)
7068                 {
7069                         ec.ig.Emit (OpCodes.Ldarg_0);
7070                 }
7071         }
7072
7073         /// <summary>
7074         ///   Implements the typeof operator
7075         /// </summary>
7076         public class TypeOf : Expression {
7077                 public readonly Expression QueriedType;
7078                 protected Type typearg;
7079                 
7080                 public TypeOf (Expression queried_type, Location l)
7081                 {
7082                         QueriedType = queried_type;
7083                         loc = l;
7084                 }
7085
7086                 public override Expression DoResolve (EmitContext ec)
7087                 {
7088                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
7089
7090                         if (typearg == null)
7091                                 return null;
7092
7093                         if (typearg == TypeManager.void_type) {
7094                                 Error (673, "System.Void cannot be used from C# - " +
7095                                        "use typeof (void) to get the void type object");
7096                                 return null;
7097                         }
7098
7099                         CheckObsoleteAttribute (typearg);
7100
7101                         type = TypeManager.type_type;
7102                         eclass = ExprClass.Type;
7103                         return this;
7104                 }
7105
7106                 public override void Emit (EmitContext ec)
7107                 {
7108                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
7109                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7110                 }
7111
7112                 public Type TypeArg { 
7113                         get { return typearg; }
7114                 }
7115         }
7116
7117         /// <summary>
7118         ///   Implements the `typeof (void)' operator
7119         /// </summary>
7120         public class TypeOfVoid : TypeOf {
7121                 public TypeOfVoid (Location l) : base (null, l)
7122                 {
7123                         loc = l;
7124                 }
7125
7126                 public override Expression DoResolve (EmitContext ec)
7127                 {
7128                         type = TypeManager.type_type;
7129                         typearg = TypeManager.void_type;
7130                         eclass = ExprClass.Type;
7131                         return this;
7132                 }
7133         }
7134
7135         /// <summary>
7136         ///   Implements the sizeof expression
7137         /// </summary>
7138         public class SizeOf : Expression {
7139                 public Expression QueriedType;
7140                 Type type_queried;
7141                 
7142                 public SizeOf (Expression queried_type, Location l)
7143                 {
7144                         this.QueriedType = queried_type;
7145                         loc = l;
7146                 }
7147
7148                 public override Expression DoResolve (EmitContext ec)
7149                 {
7150                         if (!ec.InUnsafe) {
7151                                 Report.Error (
7152                                         233, loc, "Sizeof may only be used in an unsafe context " +
7153                                         "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
7154                                 return null;
7155                         }
7156                                 
7157                         QueriedType = ec.DeclSpace.ResolveTypeExpr (QueriedType, false, loc);
7158                         if (QueriedType == null || QueriedType.Type == null)
7159                                 return null;
7160
7161                         if (QueriedType is TypeParameterExpr){
7162                                 ((TypeParameterExpr)QueriedType).Error_CannotUseAsUnmanagedType (loc);
7163                                 return null;
7164                         }
7165
7166                         type_queried = QueriedType.Type;
7167                         if (type_queried == null)
7168                                 return null;
7169
7170                         CheckObsoleteAttribute (type_queried);
7171
7172                         if (!TypeManager.IsUnmanagedType (type_queried)){
7173                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
7174                                 return null;
7175                         }
7176                         
7177                         type = TypeManager.int32_type;
7178                         eclass = ExprClass.Value;
7179                         return this;
7180                 }
7181
7182                 public override void Emit (EmitContext ec)
7183                 {
7184                         int size = GetTypeSize (type_queried);
7185
7186                         if (size == 0)
7187                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7188                         else
7189                                 IntConstant.EmitInt (ec.ig, size);
7190                 }
7191         }
7192
7193         /// <summary>
7194         ///   Implements the member access expression
7195         /// </summary>
7196         public class MemberAccess : Expression {
7197                 public string Identifier;
7198                 protected Expression expr;
7199                 protected TypeArguments args;
7200                 
7201                 public MemberAccess (Expression expr, string id, Location l)
7202                 {
7203                         this.expr = expr;
7204                         Identifier = id;
7205                         loc = l;
7206                 }
7207
7208                 public MemberAccess (Expression expr, string id, TypeArguments args,
7209                                      Location l)
7210                         : this (expr, id, l)
7211                 {
7212                         this.args = args;
7213                 }
7214
7215                 public Expression Expr {
7216                         get {
7217                                 return expr;
7218                         }
7219                 }
7220
7221                 public static void error176 (Location loc, string name)
7222                 {
7223                         Report.Error (176, loc, "Static member `" +
7224                                       name + "' cannot be accessed " +
7225                                       "with an instance reference, qualify with a " +
7226                                       "type name instead");
7227                 }
7228
7229                 public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
7230                 {
7231                         SimpleName sn = left_original as SimpleName;
7232                         if (sn == null || left == null || left.Type.Name != sn.Name)
7233                                 return false;
7234
7235                         return RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc) != null;
7236                 }
7237                 
7238                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7239                                                               Expression left, Location loc,
7240                                                               Expression left_original)
7241                 {
7242                         bool left_is_type, left_is_explicit;
7243
7244                         // If `left' is null, then we're called from SimpleNameResolve and this is
7245                         // a member in the currently defining class.
7246                         if (left == null) {
7247                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7248                                 left_is_explicit = false;
7249
7250                                 // Implicitly default to `this' unless we're static.
7251                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7252                                         left = ec.GetThis (loc);
7253                         } else {
7254                                 left_is_type = left is TypeExpr;
7255                                 left_is_explicit = true;
7256                         }
7257
7258                         if (member_lookup is FieldExpr){
7259                                 FieldExpr fe = (FieldExpr) member_lookup;
7260                                 FieldInfo fi = fe.FieldInfo.Mono_GetGenericFieldDefinition ();
7261                                 Type decl_type = fi.DeclaringType;
7262
7263                                 if (fi is FieldBuilder) {
7264                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7265                                         
7266                                         if (c != null) {
7267                                                 object o;
7268                                                 if (!c.LookupConstantValue (out o))
7269                                                         return null;
7270
7271                                                 object real_value = ((Constant) c.Expr).GetValue ();
7272
7273                                                 return Constantify (real_value, fi.FieldType);
7274                                         }
7275                                 }
7276
7277                                 if (fi.IsLiteral) {
7278                                         Type t = fi.FieldType;
7279                                         
7280                                         object o;
7281
7282                                         if (fi is FieldBuilder)
7283                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
7284                                         else
7285                                                 o = fi.GetValue (fi);
7286                                         
7287                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7288                                                 if (left_is_explicit && !left_is_type &&
7289                                                     !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) {
7290                                                         error176 (loc, fe.FieldInfo.Name);
7291                                                         return null;
7292                                                 }                                       
7293                                                 
7294                                                 Expression enum_member = MemberLookup (
7295                                                         ec, decl_type, "value__", MemberTypes.Field,
7296                                                         AllBindingFlags, loc); 
7297
7298                                                 Enum en = TypeManager.LookupEnum (decl_type);
7299
7300                                                 Constant c;
7301                                                 if (en != null)
7302                                                         c = Constantify (o, en.UnderlyingType);
7303                                                 else 
7304                                                         c = Constantify (o, enum_member.Type);
7305                                                 
7306                                                 return new EnumConstant (c, decl_type);
7307                                         }
7308                                         
7309                                         Expression exp = Constantify (o, t);
7310
7311                                         if (left_is_explicit && !left_is_type) {
7312                                                 error176 (loc, fe.FieldInfo.Name);
7313                                                 return null;
7314                                         }
7315                                         
7316                                         return exp;
7317                                 }
7318
7319                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
7320                                         UnsafeError (loc);
7321                                         return null;
7322                                 }
7323                         }
7324
7325                         if (member_lookup is EventExpr) {
7326                                 EventExpr ee = (EventExpr) member_lookup;
7327                                 
7328                                 //
7329                                 // If the event is local to this class, we transform ourselves into
7330                                 // a FieldExpr
7331                                 //
7332
7333                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7334                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7335                                         MemberInfo mi = GetFieldFromEvent (ee);
7336
7337                                         if (mi == null) {
7338                                                 //
7339                                                 // If this happens, then we have an event with its own
7340                                                 // accessors and private field etc so there's no need
7341                                                 // to transform ourselves.
7342                                                 //
7343                                                 ee.InstanceExpression = left;
7344                                                 return ee;
7345                                         }
7346
7347                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7348                                         
7349                                         if (ml == null) {
7350                                                 Report.Error (-200, loc, "Internal error!!");
7351                                                 return null;
7352                                         }
7353
7354                                         if (!left_is_explicit)
7355                                                 left = null;
7356                                         
7357                                         ee.InstanceExpression = left;
7358
7359                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7360                                 }
7361                         }
7362
7363                         if (member_lookup is IMemberExpr) {
7364                                 IMemberExpr me = (IMemberExpr) member_lookup;
7365                                 MethodGroupExpr mg = me as MethodGroupExpr;
7366
7367                                 if (left_is_type){
7368                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7369                                                 mg.IsExplicitImpl = left_is_explicit;
7370
7371                                         if (!me.IsStatic){
7372                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7373                                                     IdenticalNameAndTypeName (ec, left_original, member_lookup, loc))
7374                                                         return member_lookup;
7375
7376                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7377                                                 return null;
7378                                         }
7379
7380                                 } else {
7381                                         if (!me.IsInstance){
7382                                                 if (IdenticalNameAndTypeName (ec, left_original, left, loc))
7383                                                         return member_lookup;
7384
7385                                                 if (left_is_explicit) {
7386                                                         error176 (loc, me.Name);
7387                                                         return null;
7388                                                 }
7389                                         }
7390
7391                                         //
7392                                         // Since we can not check for instance objects in SimpleName,
7393                                         // becaue of the rule that allows types and variables to share
7394                                         // the name (as long as they can be de-ambiguated later, see 
7395                                         // IdenticalNameAndTypeName), we have to check whether left 
7396                                         // is an instance variable in a static context
7397                                         //
7398                                         // However, if the left-hand value is explicitly given, then
7399                                         // it is already our instance expression, so we aren't in
7400                                         // static context.
7401                                         //
7402
7403                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7404                                                 IMemberExpr mexp = (IMemberExpr) left;
7405
7406                                                 if (!mexp.IsStatic){
7407                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7408                                                         return null;
7409                                                 }
7410                                         }
7411
7412                                         if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc))
7413                                                 mg.IdenticalTypeName = true;
7414
7415                                         me.InstanceExpression = left;
7416                                 }
7417
7418                                 return member_lookup;
7419                         }
7420
7421                         Console.WriteLine ("Left is: " + left);
7422                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7423                         Environment.Exit (1);
7424                         return null;
7425                 }
7426                 
7427                 public virtual Expression DoResolve (EmitContext ec, Expression right_side,
7428                                                      ResolveFlags flags)
7429                 {
7430                         if (type != null)
7431                                 throw new Exception ();
7432
7433                         //
7434                         // Resolve the expression with flow analysis turned off, we'll do the definite
7435                         // assignment checks later.  This is because we don't know yet what the expression
7436                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7437                         // definite assignment check on the actual field and not on the whole struct.
7438                         //
7439
7440                         Expression original = expr;
7441                         expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7442                         if (expr == null)
7443                                 return null;
7444
7445                         if (expr is SimpleName){
7446                                 SimpleName child_expr = (SimpleName) expr;
7447
7448                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7449
7450                                 return new_expr.Resolve (ec, flags);
7451                         }
7452                                         
7453                         //
7454                         // TODO: I mailed Ravi about this, and apparently we can get rid
7455                         // of this and put it in the right place.
7456                         // 
7457                         // Handle enums here when they are in transit.
7458                         // Note that we cannot afford to hit MemberLookup in this case because
7459                         // it will fail to find any members at all
7460                         //
7461
7462                         Type expr_type;
7463                         if (expr is TypeExpr){
7464                                 expr_type = ((TypeExpr) expr).ResolveType (ec);
7465
7466                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7467                                         Report.Error_T (122, loc, expr_type);
7468                                         return null;
7469                                 }
7470
7471                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7472                                         Enum en = TypeManager.LookupEnum (expr_type);
7473
7474                                         if (en != null) {
7475                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7476                                                 
7477                                                 if (value != null){
7478                                                         ObsoleteAttribute oa = en.GetObsoleteAttribute (ec, Identifier);
7479                                                         if (oa != null) {
7480                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7481                                                         }
7482
7483                                                         Constant c = Constantify (value, en.UnderlyingType);
7484                                                         return new EnumConstant (c, expr_type);
7485                                                 }
7486                                         } else {
7487                                                 CheckObsoleteAttribute (expr_type);
7488
7489                                                 FieldInfo fi = expr_type.GetField (Identifier);
7490                                                 if (fi != null) {
7491                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7492                                                         if (oa != null)
7493                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7494                                                 }
7495                                         }
7496                                 }
7497                         } else
7498                                 expr_type = expr.Type;
7499                         
7500                         if (expr_type.IsPointer){
7501                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7502                                        TypeManager.CSharpName (expr_type) + ")");
7503                                 return null;
7504                         }
7505
7506                         int errors = Report.Errors;
7507
7508                         Expression member_lookup;
7509                         member_lookup = MemberLookup (
7510                                 ec, expr_type, expr_type, Identifier, loc);
7511                         if ((member_lookup == null) && (args != null)) {
7512                                 string lookup_id = Identifier + "!" + args.Count;
7513                                 member_lookup = MemberLookup (
7514                                         ec, expr_type, expr_type, lookup_id, loc);
7515                         }
7516                         if (member_lookup == null) {
7517                                 MemberLookupFailed (
7518                                         ec, expr_type, expr_type, Identifier, null, loc);
7519                                 return null;
7520                         }
7521
7522                         if (member_lookup is TypeExpr) {
7523                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7524                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7525                                                member_lookup.Type + "' instead");
7526                                         return null;
7527                                 }
7528
7529                                 return member_lookup;
7530                         }
7531
7532                         if (args != null) {
7533                                 string full_name = expr_type + "." + Identifier;
7534
7535                                 if (member_lookup is FieldExpr) {
7536                                         Report.Error (307, loc, "The field `{0}' cannot " +
7537                                                       "be used with type arguments", full_name);
7538                                         return null;
7539                                 } else if (member_lookup is EventExpr) {
7540                                         Report.Error (307, loc, "The event `{0}' cannot " +
7541                                                       "be used with type arguments", full_name);
7542                                         return null;
7543                                 } else if (member_lookup is PropertyExpr) {
7544                                         Report.Error (307, loc, "The property `{0}' cannot " +
7545                                                       "be used with type arguments", full_name);
7546                                         return null;
7547                                 }
7548                         }
7549                         
7550                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7551                         if (member_lookup == null)
7552                                 return null;
7553
7554                         if (args != null) {
7555                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7556                                 if (mg == null)
7557                                         throw new InternalErrorException ();
7558
7559                                 return mg.ResolveGeneric (ec, args);
7560                         }
7561
7562                         // The following DoResolve/DoResolveLValue will do the definite assignment
7563                         // check.
7564
7565                         if (right_side != null)
7566                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7567                         else
7568                                 member_lookup = member_lookup.DoResolve (ec);
7569
7570                         return member_lookup;
7571                 }
7572
7573                 public override Expression DoResolve (EmitContext ec)
7574                 {
7575                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7576                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7577                 }
7578
7579                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7580                 {
7581                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7582                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7583                 }
7584
7585                 public override Expression ResolveAsTypeStep (EmitContext ec)
7586                 {
7587                         string fname = null;
7588                         MemberAccess full_expr = this;
7589                         while (full_expr != null) {
7590                                 if (fname != null)
7591                                         fname = String.Concat (full_expr.Identifier, ".", fname);
7592                                 else
7593                                         fname = full_expr.Identifier;
7594
7595                                 if (args != null)
7596                                         fname = fname + "!" + args.Count;
7597
7598                                 if (full_expr.Expr is SimpleName) {
7599                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7600                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
7601                                         if (fully_qualified != null)
7602                                                 return new TypeExpression (fully_qualified, loc);
7603                                 }
7604
7605                                 full_expr = full_expr.Expr as MemberAccess;
7606                         }
7607
7608                         Expression new_expr = expr.ResolveAsTypeStep (ec);
7609
7610                         if (new_expr == null)
7611                                 return null;
7612
7613                         if (new_expr is SimpleName){
7614                                 SimpleName child_expr = (SimpleName) new_expr;
7615                                 
7616                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7617
7618                                 return new_expr.ResolveAsTypeStep (ec);
7619                         }
7620
7621                         Type expr_type = ((TypeExpr) new_expr).ResolveType (ec);
7622
7623                         if (expr_type.IsPointer){
7624                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7625                                        TypeManager.CSharpName (expr_type) + ")");
7626                                 return null;
7627                         }
7628
7629                         Expression member_lookup;
7630                         string lookup_id;
7631                         if (args != null)
7632                                 lookup_id = Identifier + "!" + args.Count;
7633                         else
7634                                 lookup_id = Identifier;
7635                         member_lookup = MemberLookupFinal (
7636                                 ec, expr_type, expr_type, lookup_id, loc);
7637                         if (member_lookup == null)
7638                                 return null;
7639
7640                         TypeExpr texpr = member_lookup as TypeExpr;
7641                         if (texpr == null)
7642                                 return null;
7643
7644                         Type t = texpr.ResolveType (ec);
7645                         if (t == null)
7646                                 return null;
7647
7648                         if (TypeManager.HasGenericArguments (expr_type)) {
7649                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7650
7651                                 TypeArguments new_args = new TypeArguments (loc);
7652                                 foreach (Type decl in decl_args)
7653                                         new_args.Add (new TypeExpression (decl, loc));
7654
7655                                 if (args != null)
7656                                         new_args.Add (args);
7657
7658                                 args = new_args;
7659                         }
7660
7661                         if (args != null) {
7662                                 ConstructedType ctype = new ConstructedType (t, args, loc);
7663                                 return ctype.ResolveAsTypeStep (ec);
7664                         }
7665
7666                         return texpr;
7667                 }
7668
7669                 public override void Emit (EmitContext ec)
7670                 {
7671                         throw new Exception ("Should not happen");
7672                 }
7673
7674                 public override string ToString ()
7675                 {
7676                         if (args != null)
7677                                 return expr + "." + Identifier + "!" + args.Count;
7678                         else
7679                                 return expr + "." + Identifier;
7680                 }
7681         }
7682
7683         /// <summary>
7684         ///   Implements checked expressions
7685         /// </summary>
7686         public class CheckedExpr : Expression {
7687
7688                 public Expression Expr;
7689
7690                 public CheckedExpr (Expression e, Location l)
7691                 {
7692                         Expr = e;
7693                         loc = l;
7694                 }
7695
7696                 public override Expression DoResolve (EmitContext ec)
7697                 {
7698                         bool last_check = ec.CheckState;
7699                         bool last_const_check = ec.ConstantCheckState;
7700
7701                         ec.CheckState = true;
7702                         ec.ConstantCheckState = true;
7703                         Expr = Expr.Resolve (ec);
7704                         ec.CheckState = last_check;
7705                         ec.ConstantCheckState = last_const_check;
7706                         
7707                         if (Expr == null)
7708                                 return null;
7709
7710                         if (Expr is Constant)
7711                                 return Expr;
7712                         
7713                         eclass = Expr.eclass;
7714                         type = Expr.Type;
7715                         return this;
7716                 }
7717
7718                 public override void Emit (EmitContext ec)
7719                 {
7720                         bool last_check = ec.CheckState;
7721                         bool last_const_check = ec.ConstantCheckState;
7722                         
7723                         ec.CheckState = true;
7724                         ec.ConstantCheckState = true;
7725                         Expr.Emit (ec);
7726                         ec.CheckState = last_check;
7727                         ec.ConstantCheckState = last_const_check;
7728                 }
7729                 
7730         }
7731
7732         /// <summary>
7733         ///   Implements the unchecked expression
7734         /// </summary>
7735         public class UnCheckedExpr : Expression {
7736
7737                 public Expression Expr;
7738
7739                 public UnCheckedExpr (Expression e, Location l)
7740                 {
7741                         Expr = e;
7742                         loc = l;
7743                 }
7744
7745                 public override Expression DoResolve (EmitContext ec)
7746                 {
7747                         bool last_check = ec.CheckState;
7748                         bool last_const_check = ec.ConstantCheckState;
7749
7750                         ec.CheckState = false;
7751                         ec.ConstantCheckState = false;
7752                         Expr = Expr.Resolve (ec);
7753                         ec.CheckState = last_check;
7754                         ec.ConstantCheckState = last_const_check;
7755
7756                         if (Expr == null)
7757                                 return null;
7758
7759                         if (Expr is Constant)
7760                                 return Expr;
7761                         
7762                         eclass = Expr.eclass;
7763                         type = Expr.Type;
7764                         return this;
7765                 }
7766
7767                 public override void Emit (EmitContext ec)
7768                 {
7769                         bool last_check = ec.CheckState;
7770                         bool last_const_check = ec.ConstantCheckState;
7771                         
7772                         ec.CheckState = false;
7773                         ec.ConstantCheckState = false;
7774                         Expr.Emit (ec);
7775                         ec.CheckState = last_check;
7776                         ec.ConstantCheckState = last_const_check;
7777                 }
7778                 
7779         }
7780
7781         /// <summary>
7782         ///   An Element Access expression.
7783         ///
7784         ///   During semantic analysis these are transformed into 
7785         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7786         /// </summary>
7787         public class ElementAccess : Expression {
7788                 public ArrayList  Arguments;
7789                 public Expression Expr;
7790                 
7791                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7792                 {
7793                         Expr = e;
7794
7795                         loc  = l;
7796                         
7797                         if (e_list == null)
7798                                 return;
7799                         
7800                         Arguments = new ArrayList ();
7801                         foreach (Expression tmp in e_list)
7802                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7803                         
7804                 }
7805
7806                 bool CommonResolve (EmitContext ec)
7807                 {
7808                         Expr = Expr.Resolve (ec);
7809
7810                         if (Expr == null) 
7811                                 return false;
7812
7813                         if (Arguments == null)
7814                                 return false;
7815
7816                         foreach (Argument a in Arguments){
7817                                 if (!a.Resolve (ec, loc))
7818                                         return false;
7819                         }
7820
7821                         return true;
7822                 }
7823
7824                 Expression MakePointerAccess ()
7825                 {
7826                         Type t = Expr.Type;
7827
7828                         if (t == TypeManager.void_ptr_type){
7829                                 Error (242, "The array index operation is not valid for void pointers");
7830                                 return null;
7831                         }
7832                         if (Arguments.Count != 1){
7833                                 Error (196, "A pointer must be indexed by a single value");
7834                                 return null;
7835                         }
7836                         Expression p;
7837
7838                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
7839                         return new Indirection (p, loc);
7840                 }
7841                 
7842                 public override Expression DoResolve (EmitContext ec)
7843                 {
7844                         if (!CommonResolve (ec))
7845                                 return null;
7846
7847                         //
7848                         // We perform some simple tests, and then to "split" the emit and store
7849                         // code we create an instance of a different class, and return that.
7850                         //
7851                         // I am experimenting with this pattern.
7852                         //
7853                         Type t = Expr.Type;
7854
7855                         if (t == TypeManager.array_type){
7856                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7857                                 return null;
7858                         }
7859                         
7860                         if (t.IsArray)
7861                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7862                         else if (t.IsPointer)
7863                                 return MakePointerAccess ();
7864                         else
7865                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7866                 }
7867
7868                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7869                 {
7870                         if (!CommonResolve (ec))
7871                                 return null;
7872
7873                         Type t = Expr.Type;
7874                         if (t.IsArray)
7875                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7876                         else if (t.IsPointer)
7877                                 return MakePointerAccess ();
7878                         else
7879                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7880                 }
7881                 
7882                 public override void Emit (EmitContext ec)
7883                 {
7884                         throw new Exception ("Should never be reached");
7885                 }
7886         }
7887
7888         /// <summary>
7889         ///   Implements array access 
7890         /// </summary>
7891         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7892                 //
7893                 // Points to our "data" repository
7894                 //
7895                 ElementAccess ea;
7896
7897                 LocalTemporary [] cached_locations;
7898                 
7899                 public ArrayAccess (ElementAccess ea_data, Location l)
7900                 {
7901                         ea = ea_data;
7902                         eclass = ExprClass.Variable;
7903                         loc = l;
7904                 }
7905
7906                 public override Expression DoResolve (EmitContext ec)
7907                 {
7908 #if false
7909                         ExprClass eclass = ea.Expr.eclass;
7910
7911                         // As long as the type is valid
7912                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7913                               eclass == ExprClass.Value)) {
7914                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7915                                 return null;
7916                         }
7917 #endif
7918
7919                         Type t = ea.Expr.Type;
7920                         if (t.GetArrayRank () != ea.Arguments.Count){
7921                                 ea.Error (22,
7922                                           "Incorrect number of indexes for array " +
7923                                           " expected: " + t.GetArrayRank () + " got: " +
7924                                           ea.Arguments.Count);
7925                                 return null;
7926                         }
7927
7928                         type = TypeManager.GetElementType (t);
7929                         if (type.IsPointer && !ec.InUnsafe){
7930                                 UnsafeError (ea.Location);
7931                                 return null;
7932                         }
7933
7934                         foreach (Argument a in ea.Arguments){
7935                                 Type argtype = a.Type;
7936
7937                                 if (argtype == TypeManager.int32_type ||
7938                                     argtype == TypeManager.uint32_type ||
7939                                     argtype == TypeManager.int64_type ||
7940                                     argtype == TypeManager.uint64_type)
7941                                         continue;
7942
7943                                 //
7944                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7945                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7946                                 //
7947                                 // Wonder if I will run into trouble for this.
7948                                 //
7949                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7950                                 if (a.Expr == null)
7951                                         return null;
7952                         }
7953                         
7954                         eclass = ExprClass.Variable;
7955
7956                         return this;
7957                 }
7958
7959                 /// <summary>
7960                 ///    Emits the right opcode to load an object of Type `t'
7961                 ///    from an array of T
7962                 /// </summary>
7963                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7964                 {
7965                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7966                                 ig.Emit (OpCodes.Ldelem_U1);
7967                         else if (type == TypeManager.sbyte_type)
7968                                 ig.Emit (OpCodes.Ldelem_I1);
7969                         else if (type == TypeManager.short_type)
7970                                 ig.Emit (OpCodes.Ldelem_I2);
7971                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7972                                 ig.Emit (OpCodes.Ldelem_U2);
7973                         else if (type == TypeManager.int32_type)
7974                                 ig.Emit (OpCodes.Ldelem_I4);
7975                         else if (type == TypeManager.uint32_type)
7976                                 ig.Emit (OpCodes.Ldelem_U4);
7977                         else if (type == TypeManager.uint64_type)
7978                                 ig.Emit (OpCodes.Ldelem_I8);
7979                         else if (type == TypeManager.int64_type)
7980                                 ig.Emit (OpCodes.Ldelem_I8);
7981                         else if (type == TypeManager.float_type)
7982                                 ig.Emit (OpCodes.Ldelem_R4);
7983                         else if (type == TypeManager.double_type)
7984                                 ig.Emit (OpCodes.Ldelem_R8);
7985                         else if (type == TypeManager.intptr_type)
7986                                 ig.Emit (OpCodes.Ldelem_I);
7987                         else if (TypeManager.IsEnumType (type)){
7988                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7989                         } else if (type.IsValueType){
7990                                 ig.Emit (OpCodes.Ldelema, type);
7991                                 ig.Emit (OpCodes.Ldobj, type);
7992                         } else if (type.IsGenericParameter)
7993                                 ig.Emit (OpCodes.Ldelem_Any, type);
7994                         else
7995                                 ig.Emit (OpCodes.Ldelem_Ref);
7996                 }
7997
7998                 /// <summary>
7999                 ///    Emits the right opcode to store an object of Type `t'
8000                 ///    from an array of T.  
8001                 /// </summary>
8002                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
8003                 {
8004                         bool is_stobj, has_type_arg;
8005                         OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8006                         if (has_type_arg)
8007                                 ig.Emit (op, t);
8008                         else
8009                                 ig.Emit (op);
8010                 }
8011
8012                 /// <summary>
8013                 ///    Returns the right opcode to store an object of Type `t'
8014                 ///    from an array of T.  
8015                 /// </summary>
8016                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8017                 {
8018                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
8019                         has_type_arg = false; is_stobj = false;
8020                         t = TypeManager.TypeToCoreType (t);
8021                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
8022                                 t = TypeManager.EnumToUnderlying (t);
8023                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8024                             t == TypeManager.bool_type)
8025                                 return OpCodes.Stelem_I1;
8026                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8027                                  t == TypeManager.char_type)
8028                                 return OpCodes.Stelem_I2;
8029                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8030                                 return OpCodes.Stelem_I4;
8031                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8032                                 return OpCodes.Stelem_I8;
8033                         else if (t == TypeManager.float_type)
8034                                 return OpCodes.Stelem_R4;
8035                         else if (t == TypeManager.double_type)
8036                                 return OpCodes.Stelem_R8;
8037                         else if (t == TypeManager.intptr_type) {
8038                                 has_type_arg = true;
8039                                 is_stobj = true;
8040                                 return OpCodes.Stobj;
8041                         } else if (t.IsValueType) {
8042                                 has_type_arg = true;
8043                                 is_stobj = true;
8044                                 return OpCodes.Stobj;
8045                         } else if (t.IsGenericParameter) {
8046                                 has_type_arg = true;
8047                                 return OpCodes.Stelem_Any;
8048                         } else
8049                                 return OpCodes.Stelem_Ref;
8050                 }
8051
8052                 MethodInfo FetchGetMethod ()
8053                 {
8054                         ModuleBuilder mb = CodeGen.Module.Builder;
8055                         int arg_count = ea.Arguments.Count;
8056                         Type [] args = new Type [arg_count];
8057                         MethodInfo get;
8058                         
8059                         for (int i = 0; i < arg_count; i++){
8060                                 //args [i++] = a.Type;
8061                                 args [i] = TypeManager.int32_type;
8062                         }
8063                         
8064                         get = mb.GetArrayMethod (
8065                                 ea.Expr.Type, "Get",
8066                                 CallingConventions.HasThis |
8067                                 CallingConventions.Standard,
8068                                 type, args);
8069                         return get;
8070                 }
8071                                 
8072
8073                 MethodInfo FetchAddressMethod ()
8074                 {
8075                         ModuleBuilder mb = CodeGen.Module.Builder;
8076                         int arg_count = ea.Arguments.Count;
8077                         Type [] args = new Type [arg_count];
8078                         MethodInfo address;
8079                         Type ret_type;
8080                         
8081                         ret_type = TypeManager.GetReferenceType (type);
8082                         
8083                         for (int i = 0; i < arg_count; i++){
8084                                 //args [i++] = a.Type;
8085                                 args [i] = TypeManager.int32_type;
8086                         }
8087                         
8088                         address = mb.GetArrayMethod (
8089                                 ea.Expr.Type, "Address",
8090                                 CallingConventions.HasThis |
8091                                 CallingConventions.Standard,
8092                                 ret_type, args);
8093
8094                         return address;
8095                 }
8096
8097                 //
8098                 // Load the array arguments into the stack.
8099                 //
8100                 // If we have been requested to cache the values (cached_locations array
8101                 // initialized), then load the arguments the first time and store them
8102                 // in locals.  otherwise load from local variables.
8103                 //
8104                 void LoadArrayAndArguments (EmitContext ec)
8105                 {
8106                         ILGenerator ig = ec.ig;
8107                         
8108                         if (cached_locations == null){
8109                                 ea.Expr.Emit (ec);
8110                                 foreach (Argument a in ea.Arguments){
8111                                         Type argtype = a.Expr.Type;
8112                                         
8113                                         a.Expr.Emit (ec);
8114                                         
8115                                         if (argtype == TypeManager.int64_type)
8116                                                 ig.Emit (OpCodes.Conv_Ovf_I);
8117                                         else if (argtype == TypeManager.uint64_type)
8118                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
8119                                 }
8120                                 return;
8121                         }
8122
8123                         if (cached_locations [0] == null){
8124                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
8125                                 ea.Expr.Emit (ec);
8126                                 ig.Emit (OpCodes.Dup);
8127                                 cached_locations [0].Store (ec);
8128                                 
8129                                 int j = 1;
8130                                 
8131                                 foreach (Argument a in ea.Arguments){
8132                                         Type argtype = a.Expr.Type;
8133                                         
8134                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
8135                                         a.Expr.Emit (ec);
8136                                         if (argtype == TypeManager.int64_type)
8137                                                 ig.Emit (OpCodes.Conv_Ovf_I);
8138                                         else if (argtype == TypeManager.uint64_type)
8139                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
8140
8141                                         ig.Emit (OpCodes.Dup);
8142                                         cached_locations [j].Store (ec);
8143                                         j++;
8144                                 }
8145                                 return;
8146                         }
8147
8148                         foreach (LocalTemporary lt in cached_locations)
8149                                 lt.Emit (ec);
8150                 }
8151
8152                 public new void CacheTemporaries (EmitContext ec)
8153                 {
8154                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
8155                 }
8156                 
8157                 public override void Emit (EmitContext ec)
8158                 {
8159                         int rank = ea.Expr.Type.GetArrayRank ();
8160                         ILGenerator ig = ec.ig;
8161
8162                         LoadArrayAndArguments (ec);
8163                         
8164                         if (rank == 1)
8165                                 EmitLoadOpcode (ig, type);
8166                         else {
8167                                 MethodInfo method;
8168                                 
8169                                 method = FetchGetMethod ();
8170                                 ig.Emit (OpCodes.Call, method);
8171                         }
8172                 }
8173
8174                 public void EmitAssign (EmitContext ec, Expression source)
8175                 {
8176                         int rank = ea.Expr.Type.GetArrayRank ();
8177                         ILGenerator ig = ec.ig;
8178                         Type t = source.Type;
8179
8180                         LoadArrayAndArguments (ec);
8181
8182                         //
8183                         // The stobj opcode used by value types will need
8184                         // an address on the stack, not really an array/array
8185                         // pair
8186                         //
8187                         if (rank == 1){
8188                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
8189                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
8190                                         ig.Emit (OpCodes.Ldelema, t);
8191                         }
8192                         
8193                         source.Emit (ec);
8194
8195                         if (rank == 1)
8196                                 EmitStoreOpcode (ig, t);
8197                         else {
8198                                 ModuleBuilder mb = CodeGen.Module.Builder;
8199                                 int arg_count = ea.Arguments.Count;
8200                                 Type [] args = new Type [arg_count + 1];
8201                                 MethodInfo set;
8202                                 
8203                                 for (int i = 0; i < arg_count; i++){
8204                                         //args [i++] = a.Type;
8205                                         args [i] = TypeManager.int32_type;
8206                                 }
8207
8208                                 args [arg_count] = type;
8209                                 
8210                                 set = mb.GetArrayMethod (
8211                                         ea.Expr.Type, "Set",
8212                                         CallingConventions.HasThis |
8213                                         CallingConventions.Standard,
8214                                         TypeManager.void_type, args);
8215                                 
8216                                 ig.Emit (OpCodes.Call, set);
8217                         }
8218                 }
8219
8220                 public void AddressOf (EmitContext ec, AddressOp mode)
8221                 {
8222                         int rank = ea.Expr.Type.GetArrayRank ();
8223                         ILGenerator ig = ec.ig;
8224
8225                         LoadArrayAndArguments (ec);
8226
8227                         if (rank == 1){
8228                                 ig.Emit (OpCodes.Ldelema, type);
8229                         } else {
8230                                 MethodInfo address = FetchAddressMethod ();
8231                                 ig.Emit (OpCodes.Call, address);
8232                         }
8233                 }
8234         }
8235
8236         
8237         class Indexers {
8238                 public ArrayList Properties;
8239                 static Hashtable map;
8240
8241                 public struct Indexer {
8242                         public readonly Type Type;
8243                         public readonly MethodInfo Getter, Setter;
8244
8245                         public Indexer (Type type, MethodInfo get, MethodInfo set)
8246                         {
8247                                 this.Type = type;
8248                                 this.Getter = get;
8249                                 this.Setter = set;
8250                         }
8251                 }
8252
8253                 static Indexers ()
8254                 {
8255                         map = new Hashtable ();
8256                 }
8257
8258                 Indexers ()
8259                 {
8260                         Properties = new ArrayList ();
8261                 }
8262                                 
8263                 void Append (MemberInfo [] mi)
8264                 {
8265                         foreach (PropertyInfo property in mi){
8266                                 MethodInfo get, set;
8267                                 
8268                                 get = property.GetGetMethod (true);
8269                                 set = property.GetSetMethod (true);
8270                                 Properties.Add (new Indexer (property.PropertyType, get, set));
8271                         }
8272                 }
8273
8274                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8275                 {
8276                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8277
8278                         MemberInfo [] mi = TypeManager.MemberLookup (
8279                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8280                                 BindingFlags.Public | BindingFlags.Instance |
8281                                 BindingFlags.DeclaredOnly, p_name, null);
8282
8283                         if (mi == null || mi.Length == 0)
8284                                 return null;
8285
8286                         return mi;
8287                 }
8288                 
8289                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8290                 {
8291                         Indexers ix = (Indexers) map [lookup_type];
8292
8293                         if (ix != null)
8294                                 return ix;
8295
8296                         Type copy = lookup_type;
8297                         while (copy != TypeManager.object_type && copy != null){
8298                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8299
8300                                 if (mi != null){
8301                                         if (ix == null)
8302                                                 ix = new Indexers ();
8303
8304                                         ix.Append (mi);
8305                                 }
8306                                         
8307                                 copy = copy.BaseType;
8308                         }
8309
8310                         if (!lookup_type.IsInterface)
8311                                 return ix;
8312
8313                         TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type);
8314                         if (ifaces != null) {
8315                                 foreach (TypeExpr iface in ifaces) {
8316                                         Type itype = iface.Type;
8317                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8318                                         if (mi != null){
8319                                                 if (ix == null)
8320                                                         ix = new Indexers ();
8321                                         
8322                                                 ix.Append (mi);
8323                                         }
8324                                 }
8325                         }
8326
8327                         return ix;
8328                 }
8329         }
8330
8331         /// <summary>
8332         ///   Expressions that represent an indexer call.
8333         /// </summary>
8334         public class IndexerAccess : Expression, IAssignMethod {
8335                 //
8336                 // Points to our "data" repository
8337                 //
8338                 MethodInfo get, set;
8339                 ArrayList set_arguments;
8340                 bool is_base_indexer;
8341
8342                 protected Type indexer_type;
8343                 protected Type current_type;
8344                 protected Expression instance_expr;
8345                 protected ArrayList arguments;
8346                 
8347                 public IndexerAccess (ElementAccess ea, Location loc)
8348                         : this (ea.Expr, false, loc)
8349                 {
8350                         this.arguments = ea.Arguments;
8351                 }
8352
8353                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8354                                          Location loc)
8355                 {
8356                         this.instance_expr = instance_expr;
8357                         this.is_base_indexer = is_base_indexer;
8358                         this.eclass = ExprClass.Value;
8359                         this.loc = loc;
8360                 }
8361
8362                 protected virtual bool CommonResolve (EmitContext ec)
8363                 {
8364                         indexer_type = instance_expr.Type;
8365                         current_type = ec.ContainerType;
8366
8367                         return true;
8368                 }
8369
8370                 public override Expression DoResolve (EmitContext ec)
8371                 {
8372                         ArrayList AllGetters = new ArrayList();
8373                         if (!CommonResolve (ec))
8374                                 return null;
8375
8376                         //
8377                         // Step 1: Query for all `Item' *properties*.  Notice
8378                         // that the actual methods are pointed from here.
8379                         //
8380                         // This is a group of properties, piles of them.  
8381
8382                         bool found_any = false, found_any_getters = false;
8383                         Type lookup_type = indexer_type;
8384
8385                         Indexers ilist;
8386                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8387                         if (ilist != null) {
8388                                 found_any = true;
8389                                 if (ilist.Properties != null) {
8390                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8391                                                 if (ix.Getter != null)
8392                                                         AllGetters.Add(ix.Getter);
8393                                         }
8394                                 }
8395                         }
8396
8397                         if (AllGetters.Count > 0) {
8398                                 found_any_getters = true;
8399                                 get = (MethodInfo) Invocation.OverloadResolve (
8400                                         ec, new MethodGroupExpr (AllGetters, loc),
8401                                         arguments, false, loc);
8402                         }
8403
8404                         if (!found_any) {
8405                                 Report.Error (21, loc,
8406                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8407                                               "' does not have any indexers defined");
8408                                 return null;
8409                         }
8410
8411                         if (!found_any_getters) {
8412                                 Error (154, "indexer can not be used in this context, because " +
8413                                        "it lacks a `get' accessor");
8414                                 return null;
8415                         }
8416
8417                         if (get == null) {
8418                                 Error (1501, "No Overload for method `this' takes `" +
8419                                        arguments.Count + "' arguments");
8420                                 return null;
8421                         }
8422
8423                         //
8424                         // Only base will allow this invocation to happen.
8425                         //
8426                         if (get.IsAbstract && this is BaseIndexerAccess){
8427                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8428                                 return null;
8429                         }
8430
8431                         type = get.ReturnType;
8432                         if (type.IsPointer && !ec.InUnsafe){
8433                                 UnsafeError (loc);
8434                                 return null;
8435                         }
8436                         
8437                         eclass = ExprClass.IndexerAccess;
8438                         return this;
8439                 }
8440
8441                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8442                 {
8443                         ArrayList AllSetters = new ArrayList();
8444                         if (!CommonResolve (ec))
8445                                 return null;
8446
8447                         bool found_any = false, found_any_setters = false;
8448
8449                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8450                         if (ilist != null) {
8451                                 found_any = true;
8452                                 if (ilist.Properties != null) {
8453                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8454                                                 if (ix.Setter != null)
8455                                                         AllSetters.Add(ix.Setter);
8456                                         }
8457                                 }
8458                         }
8459                         if (AllSetters.Count > 0) {
8460                                 found_any_setters = true;
8461                                 set_arguments = (ArrayList) arguments.Clone ();
8462                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8463                                 set = (MethodInfo) Invocation.OverloadResolve (
8464                                         ec, new MethodGroupExpr (AllSetters, loc),
8465                                         set_arguments, false, loc);
8466                         }
8467
8468                         if (!found_any) {
8469                                 Report.Error (21, loc,
8470                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8471                                               "' does not have any indexers defined");
8472                                 return null;
8473                         }
8474
8475                         if (!found_any_setters) {
8476                                 Error (154, "indexer can not be used in this context, because " +
8477                                        "it lacks a `set' accessor");
8478                                 return null;
8479                         }
8480
8481                         if (set == null) {
8482                                 Error (1501, "No Overload for method `this' takes `" +
8483                                        arguments.Count + "' arguments");
8484                                 return null;
8485                         }
8486
8487                         //
8488                         // Only base will allow this invocation to happen.
8489                         //
8490                         if (set.IsAbstract && this is BaseIndexerAccess){
8491                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8492                                 return null;
8493                         }
8494
8495                         //
8496                         // Now look for the actual match in the list of indexers to set our "return" type
8497                         //
8498                         type = TypeManager.void_type;   // default value
8499                         foreach (Indexers.Indexer ix in ilist.Properties){
8500                                 if (ix.Setter == set){
8501                                         type = ix.Type;
8502                                         break;
8503                                 }
8504                         }
8505                         
8506                         eclass = ExprClass.IndexerAccess;
8507                         return this;
8508                 }
8509                 
8510                 public override void Emit (EmitContext ec)
8511                 {
8512                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
8513                 }
8514
8515                 //
8516                 // source is ignored, because we already have a copy of it from the
8517                 // LValue resolution and we have already constructed a pre-cached
8518                 // version of the arguments (ea.set_arguments);
8519                 //
8520                 public void EmitAssign (EmitContext ec, Expression source)
8521                 {
8522                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
8523                 }
8524         }
8525
8526         /// <summary>
8527         ///   The base operator for method names
8528         /// </summary>
8529         public class BaseAccess : Expression {
8530                 string member;
8531                 
8532                 public BaseAccess (string member, Location l)
8533                 {
8534                         this.member = member;
8535                         loc = l;
8536                 }
8537
8538                 public override Expression DoResolve (EmitContext ec)
8539                 {
8540                         Expression c = CommonResolve (ec);
8541
8542                         if (c == null)
8543                                 return null;
8544
8545                         //
8546                         // MethodGroups use this opportunity to flag an error on lacking ()
8547                         //
8548                         if (!(c is MethodGroupExpr))
8549                                 return c.Resolve (ec);
8550                         return c;
8551                 }
8552
8553                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8554                 {
8555                         Expression c = CommonResolve (ec);
8556
8557                         if (c == null)
8558                                 return null;
8559
8560                         //
8561                         // MethodGroups use this opportunity to flag an error on lacking ()
8562                         //
8563                         if (! (c is MethodGroupExpr))
8564                                 return c.DoResolveLValue (ec, right_side);
8565
8566                         return c;
8567                 }
8568
8569                 Expression CommonResolve (EmitContext ec)
8570                 {
8571                         Expression member_lookup;
8572                         Type current_type = ec.ContainerType;
8573                         Type base_type = current_type.BaseType;
8574                         Expression e;
8575
8576                         if (ec.IsStatic){
8577                                 Error (1511, "Keyword base is not allowed in static method");
8578                                 return null;
8579                         }
8580
8581                         if (ec.IsFieldInitializer){
8582                                 Error (1512, "Keyword base is not available in the current context");
8583                                 return null;
8584                         }
8585                         
8586                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
8587                                                       member, AllMemberTypes, AllBindingFlags,
8588                                                       loc);
8589                         if (member_lookup == null) {
8590                                 MemberLookupFailed (
8591                                         ec, base_type, base_type, member, null, loc);
8592                                 return null;
8593                         }
8594
8595                         Expression left;
8596                         
8597                         if (ec.IsStatic)
8598                                 left = new TypeExpression (base_type, loc);
8599                         else
8600                                 left = ec.GetThis (loc);
8601                         
8602                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8603
8604                         if (e is PropertyExpr){
8605                                 PropertyExpr pe = (PropertyExpr) e;
8606
8607                                 pe.IsBase = true;
8608                         }
8609
8610                         return e;
8611                 }
8612
8613                 public override void Emit (EmitContext ec)
8614                 {
8615                         throw new Exception ("Should never be called"); 
8616                 }
8617         }
8618
8619         /// <summary>
8620         ///   The base indexer operator
8621         /// </summary>
8622         public class BaseIndexerAccess : IndexerAccess {
8623                 public BaseIndexerAccess (ArrayList args, Location loc)
8624                         : base (null, true, loc)
8625                 {
8626                         arguments = new ArrayList ();
8627                         foreach (Expression tmp in args)
8628                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8629                 }
8630
8631                 protected override bool CommonResolve (EmitContext ec)
8632                 {
8633                         instance_expr = ec.GetThis (loc);
8634
8635                         current_type = ec.ContainerType.BaseType;
8636                         indexer_type = current_type;
8637
8638                         foreach (Argument a in arguments){
8639                                 if (!a.Resolve (ec, loc))
8640                                         return false;
8641                         }
8642
8643                         return true;
8644                 }
8645         }
8646         
8647         /// <summary>
8648         ///   This class exists solely to pass the Type around and to be a dummy
8649         ///   that can be passed to the conversion functions (this is used by
8650         ///   foreach implementation to typecast the object return value from
8651         ///   get_Current into the proper type.  All code has been generated and
8652         ///   we only care about the side effect conversions to be performed
8653         ///
8654         ///   This is also now used as a placeholder where a no-action expression
8655         ///   is needed (the `New' class).
8656         /// </summary>
8657         public class EmptyExpression : Expression {
8658                 public EmptyExpression ()
8659                 {
8660                         type = TypeManager.object_type;
8661                         eclass = ExprClass.Value;
8662                         loc = Location.Null;
8663                 }
8664
8665                 public EmptyExpression (Type t)
8666                 {
8667                         type = t;
8668                         eclass = ExprClass.Value;
8669                         loc = Location.Null;
8670                 }
8671                 
8672                 public override Expression DoResolve (EmitContext ec)
8673                 {
8674                         return this;
8675                 }
8676
8677                 public override void Emit (EmitContext ec)
8678                 {
8679                         // nothing, as we only exist to not do anything.
8680                 }
8681
8682                 //
8683                 // This is just because we might want to reuse this bad boy
8684                 // instead of creating gazillions of EmptyExpressions.
8685                 // (CanImplicitConversion uses it)
8686                 //
8687                 public void SetType (Type t)
8688                 {
8689                         type = t;
8690                 }
8691         }
8692
8693         public class UserCast : Expression {
8694                 MethodBase method;
8695                 Expression source;
8696                 
8697                 public UserCast (MethodInfo method, Expression source, Location l)
8698                 {
8699                         this.method = method;
8700                         this.source = source;
8701                         type = method.ReturnType;
8702                         eclass = ExprClass.Value;
8703                         loc = l;
8704                 }
8705
8706                 public override Expression DoResolve (EmitContext ec)
8707                 {
8708                         //
8709                         // We are born fully resolved
8710                         //
8711                         return this;
8712                 }
8713
8714                 public override void Emit (EmitContext ec)
8715                 {
8716                         ILGenerator ig = ec.ig;
8717
8718                         source.Emit (ec);
8719                         
8720                         if (method is MethodInfo)
8721                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8722                         else
8723                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8724
8725                 }
8726         }
8727
8728         // <summary>
8729         //   This class is used to "construct" the type during a typecast
8730         //   operation.  Since the Type.GetType class in .NET can parse
8731         //   the type specification, we just use this to construct the type
8732         //   one bit at a time.
8733         // </summary>
8734         public class ComposedCast : TypeExpr {
8735                 Expression left;
8736                 string dim;
8737                 
8738                 public ComposedCast (Expression left, string dim, Location l)
8739                 {
8740                         this.left = left;
8741                         this.dim = dim;
8742                         loc = l;
8743                 }
8744
8745                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8746                 {
8747                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
8748                         if (ltype == null)
8749                                 return null;
8750
8751                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8752                                 Report.Error (1547, Location,
8753                                               "Keyword 'void' cannot be used in this context");
8754                                 return null;
8755                         }
8756
8757                         int pos = 0;
8758                         while ((pos < dim.Length) && (dim [pos] == '[')) {
8759                                 pos++;
8760
8761                                 if (dim [pos] == ']') {
8762                                         ltype = ltype.MakeArrayType ();
8763                                         pos++;
8764
8765                                         if (pos < dim.Length)
8766                                                 continue;
8767
8768                                         type = ltype;
8769                                         eclass = ExprClass.Type;
8770                                         return this;
8771                                 }
8772
8773                                 int rank = 0;
8774                                 while (dim [pos] == ',') {
8775                                         pos++; rank++;
8776                                 }
8777
8778                                 if ((dim [pos] != ']') || (pos != dim.Length-1))
8779                                         return null;
8780                                                 
8781                                 type = ltype.MakeArrayType (rank + 1);
8782                                 eclass = ExprClass.Type;
8783                                 return this;
8784                         }
8785
8786                         //
8787                         // ltype.Fullname is already fully qualified, so we can skip
8788                         // a lot of probes, and go directly to TypeManager.LookupType
8789                         //
8790                         string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
8791                         string cname = fname + dim;
8792                         type = TypeManager.LookupTypeDirect (cname);
8793                         if (type == null){
8794                                 //
8795                                 // For arrays of enumerations we are having a problem
8796                                 // with the direct lookup.  Need to investigate.
8797                                 //
8798                                 // For now, fall back to the full lookup in that case.
8799                                 //
8800                                 TypeExpr texpr = RootContext.LookupType (
8801                                         ec.DeclSpace, cname, false, loc);
8802
8803                                 if (texpr == null)
8804                                         return null;
8805
8806                                 type = texpr.ResolveType (ec);
8807                                 if (type == null)
8808                                         return null;
8809                         }
8810
8811                         if (!ec.ResolvingTypeTree){
8812                                 //
8813                                 // If the above flag is set, this is being invoked from the ResolveType function.
8814                                 // Upper layers take care of the type validity in this context.
8815                                 //
8816                         if (!ec.InUnsafe && type.IsPointer){
8817                                 UnsafeError (loc);
8818                                 return null;
8819                         }
8820                         }
8821                         
8822                         eclass = ExprClass.Type;
8823                         return this;
8824                 }
8825
8826                 public override string Name {
8827                         get {
8828                                 return left + dim;
8829                         }
8830                 }
8831         }
8832
8833         //
8834         // This class is used to represent the address of an array, used
8835         // only by the Fixed statement, this is like the C "&a [0]" construct.
8836         //
8837         public class ArrayPtr : Expression {
8838                 Expression array;
8839                 
8840                 public ArrayPtr (Expression array, Location l)
8841                 {
8842                         Type array_type = TypeManager.GetElementType (array.Type);
8843
8844                         this.array = array;
8845
8846                         type = TypeManager.GetPointerType (array_type);
8847                         eclass = ExprClass.Value;
8848                         loc = l;
8849                 }
8850
8851                 public override void Emit (EmitContext ec)
8852                 {
8853                         ILGenerator ig = ec.ig;
8854                         
8855                         array.Emit (ec);
8856                         IntLiteral.EmitInt (ig, 0);
8857                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8858                 }
8859
8860                 public override Expression DoResolve (EmitContext ec)
8861                 {
8862                         //
8863                         // We are born fully resolved
8864                         //
8865                         return this;
8866                 }
8867         }
8868
8869         //
8870         // Used by the fixed statement
8871         //
8872         public class StringPtr : Expression {
8873                 LocalBuilder b;
8874                 
8875                 public StringPtr (LocalBuilder b, Location l)
8876                 {
8877                         this.b = b;
8878                         eclass = ExprClass.Value;
8879                         type = TypeManager.char_ptr_type;
8880                         loc = l;
8881                 }
8882
8883                 public override Expression DoResolve (EmitContext ec)
8884                 {
8885                         // This should never be invoked, we are born in fully
8886                         // initialized state.
8887
8888                         return this;
8889                 }
8890
8891                 public override void Emit (EmitContext ec)
8892                 {
8893                         ILGenerator ig = ec.ig;
8894
8895                         ig.Emit (OpCodes.Ldloc, b);
8896                         ig.Emit (OpCodes.Conv_I);
8897                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8898                         ig.Emit (OpCodes.Add);
8899                 }
8900         }
8901         
8902         //
8903         // Implements the `stackalloc' keyword
8904         //
8905         public class StackAlloc : Expression {
8906                 Type otype;
8907                 Expression t;
8908                 Expression count;
8909                 
8910                 public StackAlloc (Expression type, Expression count, Location l)
8911                 {
8912                         t = type;
8913                         this.count = count;
8914                         loc = l;
8915                 }
8916
8917                 public override Expression DoResolve (EmitContext ec)
8918                 {
8919                         count = count.Resolve (ec);
8920                         if (count == null)
8921                                 return null;
8922                         
8923                         if (count.Type != TypeManager.int32_type){
8924                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8925                                 if (count == null)
8926                                         return null;
8927                         }
8928
8929                         Constant c = count as Constant;
8930                         // TODO: because we don't have property IsNegative
8931                         if (c != null && c.ConvertToUInt () == null) {
8932                                 // "Cannot use a negative size with stackalloc"
8933                                 Report.Error_T (247, loc);
8934                                 return null;
8935                         }
8936
8937                         if (ec.CurrentBranching.InCatch () ||
8938                             ec.CurrentBranching.InFinally (true)) {
8939                                 Error (255,
8940                                               "stackalloc can not be used in a catch or finally block");
8941                                 return null;
8942                         }
8943
8944                         otype = ec.DeclSpace.ResolveType (t, false, loc);
8945
8946                         if (otype == null)
8947                                 return null;
8948
8949                         if (!TypeManager.VerifyUnManaged (otype, loc))
8950                                 return null;
8951
8952                         type = TypeManager.GetPointerType (otype);
8953                         eclass = ExprClass.Value;
8954
8955                         return this;
8956                 }
8957
8958                 public override void Emit (EmitContext ec)
8959                 {
8960                         int size = GetTypeSize (otype);
8961                         ILGenerator ig = ec.ig;
8962                                 
8963                         if (size == 0)
8964                                 ig.Emit (OpCodes.Sizeof, otype);
8965                         else
8966                                 IntConstant.EmitInt (ig, size);
8967                         count.Emit (ec);
8968                         ig.Emit (OpCodes.Mul);
8969                         ig.Emit (OpCodes.Localloc);
8970                 }
8971         }
8972 }