2002-10-19 Rachel Hestilow <hestilow@ximian.com>
[mono.git] / mcs / mbas / 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 Ximian, Inc.
8 //
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                 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                         args.Add (new Argument (e, Argument.AType.Expression));
63                         method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
64
65                         if (method == null)
66                                 return null;
67
68                         return new StaticCallExpr ((MethodInfo) method, args, loc);
69                 }
70
71                 public override void EmitStatement (EmitContext ec)
72                 {
73                         Emit (ec);
74                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
75                                 ec.ig.Emit (OpCodes.Pop);
76                 }
77         }
78         
79         /// <summary>
80         ///   Unary expressions.  
81         /// </summary>
82         ///
83         /// <remarks>
84         ///   Unary implements unary expressions.   It derives from
85         ///   ExpressionStatement becuase the pre/post increment/decrement
86         ///   operators can be used in a statement context.
87         /// </remarks>
88         public class Unary : Expression {
89                 public enum Operator : byte {
90                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
91                         Indirection, AddressOf,  TOP
92                 }
93
94                 public Operator Oper;
95                 public Expression Expr;
96                 
97                 public Unary (Operator op, Expression expr, Location loc)
98                 {
99                         this.Oper = op;
100                         this.Expr = expr;
101                         this.loc = loc;
102                 }
103
104                 /// <summary>
105                 ///   Returns a stringified representation of the Operator
106                 /// </summary>
107                 static public string OperName (Operator oper)
108                 {
109                         switch (oper){
110                         case Operator.UnaryPlus:
111                                 return "+";
112                         case Operator.UnaryNegation:
113                                 return "-";
114                         case Operator.LogicalNot:
115                                 return "!";
116                         case Operator.OnesComplement:
117                                 return "~";
118                         case Operator.AddressOf:
119                                 return "&";
120                         case Operator.Indirection:
121                                 return "*";
122                         }
123
124                         return oper.ToString ();
125                 }
126
127                 static string [] oper_names;
128
129                 static Unary ()
130                 {
131                         oper_names = new string [(int)Operator.TOP];
132
133                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
134                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
135                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
136                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
137                         oper_names [(int) Operator.Indirection] = "op_Indirection";
138                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
139                 }
140
141                 void Error23 (Type t)
142                 {
143                         Error (
144                                 23, "Operator " + OperName (Oper) +
145                                 " cannot be applied to operand of type `" +
146                                 TypeManager.CSharpName (t) + "'");
147                 }
148
149                 /// <remarks>
150                 ///   The result has been already resolved:
151                 ///
152                 ///   FIXME: a minus constant -128 sbyte cant be turned into a
153                 ///   constant byte.
154                 /// </remarks>
155                 static Expression TryReduceNegative (Constant expr)
156                 {
157                         Expression e = null;
158                         
159                         if (expr is IntConstant)
160                                 e = new IntConstant (-((IntConstant) expr).Value);
161                         else if (expr is UIntConstant){
162                                 uint value = ((UIntConstant) expr).Value;
163
164                                 if (value < 2147483649)
165                                         return new IntConstant (-(int)value);
166                                 else
167                                         e = new LongConstant (value);
168                         }
169                         else if (expr is LongConstant)
170                                 e = new LongConstant (-((LongConstant) expr).Value);
171                         else if (expr is ULongConstant){
172                                 ulong value = ((ULongConstant) expr).Value;
173
174                                 if (value < 9223372036854775809)
175                                         return new LongConstant(-(long)value);
176                         }
177                         else if (expr is FloatConstant)
178                                 e = new FloatConstant (-((FloatConstant) expr).Value);
179                         else if (expr is DoubleConstant)
180                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);
181                         else if (expr is DecimalConstant)
182                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);
183                         else if (expr is ShortConstant)
184                                 e = new IntConstant (-((ShortConstant) expr).Value);
185                         else if (expr is UShortConstant)
186                                 e = new IntConstant (-((UShortConstant) expr).Value);
187                         return e;
188                 }
189
190                 // <summary>
191                 //   This routine will attempt to simplify the unary expression when the
192                 //   argument is a constant.  The result is returned in `result' and the
193                 //   function returns true or false depending on whether a reduction
194                 //   was performed or not
195                 // </summary>
196                 bool Reduce (EmitContext ec, Constant e, out Expression result)
197                 {
198                         Type expr_type = e.Type;
199                         
200                         switch (Oper){
201                         case Operator.UnaryPlus:
202                                 result = e;
203                                 return true;
204                                 
205                         case Operator.UnaryNegation:
206                                 result = TryReduceNegative (e);
207                                 return true;
208                                 
209                         case Operator.LogicalNot:
210                                 if (expr_type != TypeManager.bool_type) {
211                                         result = null;
212                                         Error23 (expr_type);
213                                         return false;
214                                 }
215                                 
216                                 BoolConstant b = (BoolConstant) e;
217                                 result = new BoolConstant (!(b.Value));
218                                 return true;
219                                 
220                         case Operator.OnesComplement:
221                                 if (!((expr_type == TypeManager.int32_type) ||
222                                       (expr_type == TypeManager.uint32_type) ||
223                                       (expr_type == TypeManager.int64_type) ||
224                                       (expr_type == TypeManager.uint64_type) ||
225                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
226                                         result = null;
227                                         Error23 (expr_type);
228                                         return false;
229                                 }
230
231                                 if (e is EnumConstant){
232                                         EnumConstant enum_constant = (EnumConstant) e;
233                                         Expression reduced;
234                                         
235                                         if (Reduce (ec, enum_constant.Child, out reduced)){
236                                                 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
237                                                 return true;
238                                         } else {
239                                                 result = null;
240                                                 return false;
241                                         }
242                                 }
243
244                                 if (expr_type == TypeManager.int32_type){
245                                         result = new IntConstant (~ ((IntConstant) e).Value);
246                                 } else if (expr_type == TypeManager.uint32_type){
247                                         result = new UIntConstant (~ ((UIntConstant) e).Value);
248                                 } else if (expr_type == TypeManager.int64_type){
249                                         result = new LongConstant (~ ((LongConstant) e).Value);
250                                 } else if (expr_type == TypeManager.uint64_type){
251                                         result = new ULongConstant (~ ((ULongConstant) e).Value);
252                                 } else {
253                                         result = null;
254                                         Error23 (expr_type);
255                                         return false;
256                                 }
257                                 return true;
258
259                         case Operator.AddressOf:
260                                 result = this;
261                                 return false;
262
263                         case Operator.Indirection:
264                                 result = this;
265                                 return false;
266                         }
267                         throw new Exception ("Can not constant fold: " + Oper.ToString());
268                 }
269
270                 Expression ResolveOperator (EmitContext ec)
271                 {
272                         Type expr_type = Expr.Type;
273
274                         //
275                         // Step 1: Perform Operator Overload location
276                         //
277                         Expression mg;
278                         string op_name;
279                         
280                         op_name = oper_names [(int) Oper];
281
282                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
283                         
284                         if (mg != null) {
285                                 Expression e = StaticCallExpr.MakeSimpleCall (
286                                         ec, (MethodGroupExpr) mg, Expr, loc);
287
288                                 if (e == null){
289                                         Error23 (expr_type);
290                                         return null;
291                                 }
292                                 
293                                 return e;
294                         }
295
296                         // Only perform numeric promotions on:
297                         // +, - 
298
299                         if (expr_type == null)
300                                 return null;
301                         
302                         //
303                         // Step 2: Default operations on CLI native types.
304                         //
305
306                         // Attempt to use a constant folding operation.
307                         if (Expr is Constant){
308                                 Expression result;
309                                 
310                                 if (Reduce (ec, (Constant) Expr, out result))
311                                         return result;
312                         }
313
314                         switch (Oper){
315                         case Operator.LogicalNot:
316                                 if (expr_type != TypeManager.bool_type) {
317                                         Error23 (Expr.Type);
318                                         return null;
319                                 }
320                                 
321                                 type = TypeManager.bool_type;
322                                 return this;
323
324                         case Operator.OnesComplement:
325                                 if (!((expr_type == TypeManager.int32_type) ||
326                                       (expr_type == TypeManager.uint32_type) ||
327                                       (expr_type == TypeManager.int64_type) ||
328                                       (expr_type == TypeManager.uint64_type) ||
329                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
330                                         Expression e;
331
332                                         e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
333                                         if (e != null){
334                                                 type = TypeManager.int32_type;
335                                                 return this;
336                                         }
337                                         e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
338                                         if (e != null){
339                                                 type = TypeManager.uint32_type;
340                                                 return this;
341                                         }
342                                         e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
343                                         if (e != null){
344                                                 type = TypeManager.int64_type;
345                                                 return this;
346                                         }
347                                         e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
348                                         if (e != null){
349                                                 type = TypeManager.uint64_type;
350                                                 return this;
351                                         }
352                                         Error23 (expr_type);
353                                         return null;
354                                 }
355                                 type = expr_type;
356                                 return this;
357
358                         case Operator.AddressOf:
359                                 if (Expr.eclass != ExprClass.Variable){
360                                         Error (211, "Cannot take the address of non-variables");
361                                         return null;
362                                 }
363                                 
364                                 if (!ec.InUnsafe) {
365                                         UnsafeError (loc); 
366                                         return null;
367                                 }
368                                 
369                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
370                                         return null;
371                                 }
372                                 
373                                 string ptr_type_name = Expr.Type.FullName + "*";
374                                 type = TypeManager.LookupType (ptr_type_name);
375                                 
376                                 return this;
377
378                         case Operator.Indirection:
379                                 if (!ec.InUnsafe){
380                                         UnsafeError (loc);
381                                         return null;
382                                 }
383                                 
384                                 if (!expr_type.IsPointer){
385                                         Error (
386                                                 193,
387                                                 "The * or -> operator can only be applied to pointers");
388                                         return null;
389                                 }
390                                 
391                                 //
392                                 // We create an Indirection expression, because
393                                 // it can implement the IMemoryLocation.
394                                 // 
395                                 return new Indirection (Expr, loc);
396                         
397                         case Operator.UnaryPlus:
398                                 //
399                                 // A plus in front of something is just a no-op, so return the child.
400                                 //
401                                 return Expr;
402
403                         case Operator.UnaryNegation:
404                                 //
405                                 // Deals with -literals
406                                 // int     operator- (int x)
407                                 // long    operator- (long x)
408                                 // float   operator- (float f)
409                                 // double  operator- (double d)
410                                 // decimal operator- (decimal d)
411                                 //
412                                 Expression expr = null;
413
414                                 //
415                                 // transform - - expr into expr
416                                 //
417                                 if (Expr is Unary){
418                                         Unary unary = (Unary) Expr;
419                                         
420                                         if (unary.Oper == Operator.UnaryNegation)
421                                                 return unary.Expr;
422                                 }
423
424                                 //
425                                 // perform numeric promotions to int,
426                                 // long, double.
427                                 //
428                                 //
429                                 // The following is inneficient, because we call
430                                 // ConvertImplicit too many times.
431                                 //
432                                 // It is also not clear if we should convert to Float
433                                 // or Double initially.
434                                 //
435                                 if (expr_type == TypeManager.uint32_type){
436                                         //
437                                         // FIXME: handle exception to this rule that
438                                         // permits the int value -2147483648 (-2^31) to
439                                         // bt wrote as a decimal interger literal
440                                         //
441                                         type = TypeManager.int64_type;
442                                         Expr = ConvertImplicit (ec, Expr, type, loc);
443                                         return this;
444                                 }
445
446                                 if (expr_type == TypeManager.uint64_type){
447                                         //
448                                         // FIXME: Handle exception of `long value'
449                                         // -92233720368547758087 (-2^63) to be wrote as
450                                         // decimal integer literal.
451                                         //
452                                         Error23 (expr_type);
453                                         return null;
454                                 }
455
456                                 if (expr_type == TypeManager.float_type){
457                                         type = expr_type;
458                                         return this;
459                                 }
460                                 
461                                 expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
462                                 if (expr != null){
463                                         Expr = expr;
464                                         type = expr.Type;
465                                         return this;
466                                 } 
467
468                                 expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
469                                 if (expr != null){
470                                         Expr = expr;
471                                         type = expr.Type;
472                                         return this;
473                                 }
474
475                                 expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
476                                 if (expr != null){
477                                         Expr = expr;
478                                         type = expr.Type;
479                                         return this;
480                                 }
481                                 
482                                 Error23 (expr_type);
483                                 return null;
484                         }
485
486                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
487                                TypeManager.CSharpName (expr_type) + "'");
488                         return null;
489                 }
490
491                 public override Expression DoResolve (EmitContext ec)
492                 {
493                         if (Oper == Operator.AddressOf)
494                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
495                         else
496                                 Expr = Expr.Resolve (ec);
497                         
498                         if (Expr == null)
499                                 return null;
500
501                         eclass = ExprClass.Value;
502                         return ResolveOperator (ec);
503                 }
504
505                 public override void Emit (EmitContext ec)
506                 {
507                         ILGenerator ig = ec.ig;
508                         Type expr_type = Expr.Type;
509                         
510                         switch (Oper) {
511                         case Operator.UnaryPlus:
512                                 throw new Exception ("This should be caught by Resolve");
513                                 
514                         case Operator.UnaryNegation:
515                                 Expr.Emit (ec);
516                                 ig.Emit (OpCodes.Neg);
517                                 break;
518                                 
519                         case Operator.LogicalNot:
520                                 Expr.Emit (ec);
521                                 ig.Emit (OpCodes.Ldc_I4_0);
522                                 ig.Emit (OpCodes.Ceq);
523                                 break;
524                                 
525                         case Operator.OnesComplement:
526                                 Expr.Emit (ec);
527                                 ig.Emit (OpCodes.Not);
528                                 break;
529                                 
530                         case Operator.AddressOf:
531                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
532                                 break;
533                                 
534                         default:
535                                 throw new Exception ("This should not happen: Operator = "
536                                                      + Oper.ToString ());
537                         }
538                 }
539
540                 /// <summary>
541                 ///   This will emit the child expression for `ec' avoiding the logical
542                 ///   not.  The parent will take care of changing brfalse/brtrue
543                 /// </summary>
544                 public void EmitLogicalNot (EmitContext ec)
545                 {
546                         if (Oper != Operator.LogicalNot)
547                                 throw new Exception ("EmitLogicalNot can only be called with !expr");
548
549                         Expr.Emit (ec);
550                 }
551
552                 public override string ToString ()
553                 {
554                         return "Unary (" + Oper + ", " + Expr + ")";
555                 }
556                 
557         }
558
559         //
560         // Unary operators are turned into Indirection expressions
561         // after semantic analysis (this is so we can take the address
562         // of an indirection).
563         //
564         public class Indirection : Expression, IMemoryLocation, IAssignMethod {
565                 Expression expr;
566                 LocalTemporary temporary;
567                 bool have_temporary;
568                 
569                 public Indirection (Expression expr, Location l)
570                 {
571                         this.expr = expr;
572                         this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
573                         eclass = ExprClass.Variable;
574                         loc = l;
575                 }
576
577                 void LoadExprValue (EmitContext ec)
578                 {
579                 }
580                 
581                 public override void Emit (EmitContext ec)
582                 {
583                         ILGenerator ig = ec.ig;
584
585                         if (temporary != null){
586                                 if (have_temporary){
587                                         temporary.Emit (ec);
588                                         return;
589                                 }
590                                 expr.Emit (ec);
591                                 ec.ig.Emit (OpCodes.Dup);
592                                 temporary.Store (ec);
593                                 have_temporary = true;
594                         } else
595                                 expr.Emit (ec);
596                         
597                         LoadFromPtr (ig, Type);
598                 }
599
600                 public void EmitAssign (EmitContext ec, Expression source)
601                 {
602                         if (temporary != null){
603                                 if (have_temporary){
604                                         temporary.Emit (ec);
605                                         return;
606                                 }
607                                 expr.Emit (ec);
608                                 ec.ig.Emit (OpCodes.Dup);
609                                 temporary.Store (ec);
610                                 have_temporary = true;
611                         } else
612                                 expr.Emit (ec);
613
614                         source.Emit (ec);
615                         StoreFromPtr (ec.ig, type);
616                 }
617                 
618                 public void AddressOf (EmitContext ec, AddressOp Mode)
619                 {
620                         if (temporary != null){
621                                 if (have_temporary){
622                                         temporary.Emit (ec);
623                                         return;
624                                 }
625                                 expr.Emit (ec);
626                                 ec.ig.Emit (OpCodes.Dup);
627                                 temporary.Store (ec);
628                                 have_temporary = true;
629                         } else
630                                 expr.Emit (ec);
631                 }
632
633                 public override Expression DoResolve (EmitContext ec)
634                 {
635                         //
636                         // Born fully resolved
637                         //
638                         return this;
639                 }
640
641                 public new void CacheTemporaries (EmitContext ec)
642                 {
643                         temporary = new LocalTemporary (ec, type);
644                 }
645         }
646         
647         /// <summary>
648         ///   Unary Mutator expressions (pre and post ++ and --)
649         /// </summary>
650         ///
651         /// <remarks>
652         ///   UnaryMutator implements ++ and -- expressions.   It derives from
653         ///   ExpressionStatement becuase the pre/post increment/decrement
654         ///   operators can be used in a statement context.
655         ///
656         /// FIXME: Idea, we could split this up in two classes, one simpler
657         /// for the common case, and one with the extra fields for more complex
658         /// classes (indexers require temporary access;  overloaded require method)
659         ///
660         /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
661         /// PostDecrement, that way we could save the `Mode' byte as well.  
662         /// </remarks>
663         public class UnaryMutator : ExpressionStatement {
664                 public enum Mode : byte {
665                         PreIncrement, PreDecrement, PostIncrement, PostDecrement
666                 }
667                 
668                 Mode mode;
669                 Expression expr;
670                 LocalTemporary temp_storage;
671
672                 //
673                 // This is expensive for the simplest case.
674                 //
675                 Expression method;
676                         
677                 public UnaryMutator (Mode m, Expression e, Location l)
678                 {
679                         mode = m;
680                         loc = l;
681                         expr = e;
682                 }
683
684                 static string OperName (Mode mode)
685                 {
686                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
687                                 "++" : "--";
688                 }
689                 
690                 void Error23 (Type t)
691                 {
692                         Error (
693                                 23, "Operator " + OperName (mode) + 
694                                 " cannot be applied to operand of type `" +
695                                 TypeManager.CSharpName (t) + "'");
696                 }
697
698                 /// <summary>
699                 ///   Returns whether an object of type `t' can be incremented
700                 ///   or decremented with add/sub (ie, basically whether we can
701                 ///   use pre-post incr-decr operations on it, but it is not a
702                 ///   System.Decimal, which we require operator overloading to catch)
703                 /// </summary>
704                 static bool IsIncrementableNumber (Type t)
705                 {
706                         return (t == TypeManager.sbyte_type) ||
707                                 (t == TypeManager.byte_type) ||
708                                 (t == TypeManager.short_type) ||
709                                 (t == TypeManager.ushort_type) ||
710                                 (t == TypeManager.int32_type) ||
711                                 (t == TypeManager.uint32_type) ||
712                                 (t == TypeManager.int64_type) ||
713                                 (t == TypeManager.uint64_type) ||
714                                 (t == TypeManager.char_type) ||
715                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
716                                 (t == TypeManager.float_type) ||
717                                 (t == TypeManager.double_type) ||
718                                 (t.IsPointer && t != TypeManager.void_ptr_type);
719                 }
720
721                 Expression ResolveOperator (EmitContext ec)
722                 {
723                         Type expr_type = expr.Type;
724
725                         //
726                         // Step 1: Perform Operator Overload location
727                         //
728                         Expression mg;
729                         string op_name;
730                         
731                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
732                                 op_name = "op_Increment";
733                         else 
734                                 op_name = "op_Decrement";
735
736                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
737
738                         if (mg == null && expr_type.BaseType != null)
739                                 mg = MemberLookup (ec, expr_type.BaseType, op_name,
740                                                    MemberTypes.Method, AllBindingFlags, loc);
741                         
742                         if (mg != null) {
743                                 method = StaticCallExpr.MakeSimpleCall (
744                                         ec, (MethodGroupExpr) mg, expr, loc);
745
746                                 type = method.Type;
747                                 return this;
748                         }
749
750                         //
751                         // The operand of the prefix/postfix increment decrement operators
752                         // should be an expression that is classified as a variable,
753                         // a property access or an indexer access
754                         //
755                         type = expr_type;
756                         if (expr.eclass == ExprClass.Variable){
757                                 if (IsIncrementableNumber (expr_type) ||
758                                     expr_type == TypeManager.decimal_type){
759                                         return this;
760                                 }
761                         } else if (expr.eclass == ExprClass.IndexerAccess){
762                                 IndexerAccess ia = (IndexerAccess) expr;
763                                 
764                                 temp_storage = new LocalTemporary (ec, expr.Type);
765                                 
766                                 expr = ia.ResolveLValue (ec, temp_storage);
767                                 if (expr == null)
768                                         return null;
769
770                                 return this;
771                         } else if (expr.eclass == ExprClass.PropertyAccess){
772                                 PropertyExpr pe = (PropertyExpr) expr;
773
774                                 if (pe.VerifyAssignable ())
775                                         return this;
776
777                                 return null;
778                         } else {
779                                 expr.Error118 ("variable, indexer or property access");
780                                 return null;
781                         }
782
783                         Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
784                                TypeManager.CSharpName (expr_type) + "'");
785                         return null;
786                 }
787
788                 public override Expression DoResolve (EmitContext ec)
789                 {
790                         expr = expr.Resolve (ec);
791                         
792                         if (expr == null)
793                                 return null;
794
795                         eclass = ExprClass.Value;
796                         return ResolveOperator (ec);
797                 }
798
799                 static int PtrTypeSize (Type t)
800                 {
801                         return GetTypeSize (t.GetElementType ());
802                 }
803
804                 //
805                 // Loads the proper "1" into the stack based on the type
806                 //
807                 static void LoadOne (ILGenerator ig, Type t)
808                 {
809                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
810                                 ig.Emit (OpCodes.Ldc_I8, 1L);
811                         else if (t == TypeManager.double_type)
812                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
813                         else if (t == TypeManager.float_type)
814                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
815                         else if (t.IsPointer){
816                                 int n = PtrTypeSize (t);
817                                 
818                                 if (n == 0)
819                                         ig.Emit (OpCodes.Sizeof, t);
820                                 else
821                                         IntConstant.EmitInt (ig, n);
822                         } else 
823                                 ig.Emit (OpCodes.Ldc_I4_1);
824                 }
825
826                 
827                 //
828                 // FIXME: We need some way of avoiding the use of temp_storage
829                 // for some types of storage (parameters, local variables,
830                 // static fields) and single-dimension array access.
831                 //
832                 void EmitCode (EmitContext ec, bool is_expr)
833                 {
834                         ILGenerator ig = ec.ig;
835                         IAssignMethod ia = (IAssignMethod) expr;
836                         Type expr_type = expr.Type;
837                         
838                         if (temp_storage == null)
839                                 temp_storage = new LocalTemporary (ec, expr_type);
840
841                         ia.CacheTemporaries (ec);
842                         ig.Emit (OpCodes.Nop);
843                         switch (mode){
844                         case Mode.PreIncrement:
845                         case Mode.PreDecrement:
846                                 if (method == null){
847                                         expr.Emit (ec);
848
849                                         LoadOne (ig, expr_type);
850                                         
851                                         //
852                                         // Select the opcode based on the check state (then the type)
853                                         // and the actual operation
854                                         //
855                                         if (ec.CheckState){
856                                                 if (expr_type == TypeManager.int32_type ||
857                                                     expr_type == TypeManager.int64_type){
858                                                         if (mode == Mode.PreDecrement)
859                                                                 ig.Emit (OpCodes.Sub_Ovf);
860                                                         else
861                                                                 ig.Emit (OpCodes.Add_Ovf);
862                                                 } else if (expr_type == TypeManager.uint32_type ||
863                                                            expr_type == TypeManager.uint64_type){
864                                                         if (mode == Mode.PreDecrement)
865                                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
866                                                         else
867                                                                 ig.Emit (OpCodes.Add_Ovf_Un);
868                                                 } else {
869                                                         if (mode == Mode.PreDecrement)
870                                                                 ig.Emit (OpCodes.Sub_Ovf);
871                                                         else
872                                                                 ig.Emit (OpCodes.Add_Ovf);
873                                                 }
874                                         } else {
875                                                 if (mode == Mode.PreDecrement)
876                                                         ig.Emit (OpCodes.Sub);
877                                                 else
878                                                         ig.Emit (OpCodes.Add);
879                                         }
880                                 } else 
881                                         method.Emit (ec);
882
883                                 temp_storage.Store (ec);
884                                 ia.EmitAssign (ec, temp_storage);
885                                 if (is_expr)
886                                         temp_storage.Emit (ec);
887                                 break;
888                                 
889                         case Mode.PostIncrement:
890                         case Mode.PostDecrement:
891                                 if (is_expr)
892                                         expr.Emit (ec);
893                                 
894                                 if (method == null){
895                                         if (!is_expr)
896                                                 expr.Emit (ec);
897                                         else
898                                                 ig.Emit (OpCodes.Dup);
899
900                                         LoadOne (ig, expr_type);
901                                         
902                                         if (ec.CheckState){
903                                                 if (expr_type == TypeManager.int32_type ||
904                                                     expr_type == TypeManager.int64_type){
905                                                         if (mode == Mode.PostDecrement)
906                                                                 ig.Emit (OpCodes.Sub_Ovf);
907                                                         else
908                                                                 ig.Emit (OpCodes.Add_Ovf);
909                                                 } else if (expr_type == TypeManager.uint32_type ||
910                                                            expr_type == TypeManager.uint64_type){
911                                                         if (mode == Mode.PostDecrement)
912                                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
913                                                         else
914                                                                 ig.Emit (OpCodes.Add_Ovf_Un);
915                                                 } else {
916                                                         if (mode == Mode.PostDecrement)
917                                                                 ig.Emit (OpCodes.Sub_Ovf);
918                                                         else
919                                                                 ig.Emit (OpCodes.Add_Ovf);
920                                                 }
921                                         } else {
922                                                 if (mode == Mode.PostDecrement)
923                                                         ig.Emit (OpCodes.Sub);
924                                                 else
925                                                         ig.Emit (OpCodes.Add);
926                                         }
927                                 } else {
928                                         method.Emit (ec);
929                                 }
930                                 
931                                 temp_storage.Store (ec);
932                                 ia.EmitAssign (ec, temp_storage);
933                                 break;
934                         }
935                 }
936
937                 public override void Emit (EmitContext ec)
938                 {
939                         EmitCode (ec, true);
940                         
941                 }
942                 
943                 public override void EmitStatement (EmitContext ec)
944                 {
945                         EmitCode (ec, false);
946                 }
947
948         }
949
950         /// <summary>
951         ///   Base class for the `Is' and `As' classes. 
952         /// </summary>
953         ///
954         /// <remarks>
955         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
956         ///   size. 
957         /// </remarks>
958         public abstract class Probe : Expression {
959                 public readonly Expression ProbeType;
960                 protected Expression expr;
961                 protected Type probe_type;
962                 
963                 public Probe (Expression expr, Expression probe_type, Location l)
964                 {
965                         ProbeType = probe_type;
966                         loc = l;
967                         this.expr = expr;
968                 }
969
970                 public Expression Expr {
971                         get {
972                                 return expr;
973                         }
974                 }
975
976                 public override Expression DoResolve (EmitContext ec)
977                 {
978                         probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
979
980                         if (probe_type == null)
981                                 return null;
982
983                         expr = expr.Resolve (ec);
984                         
985                         return this;
986                 }
987         }
988
989         /// <summary>
990         ///   Implementation of the `is' operator.
991         /// </summary>
992         public class Is : Probe {
993                 public Is (Expression expr, Expression probe_type, Location l)
994                         : base (expr, probe_type, l)
995                 {
996                 }
997
998                 enum Action {
999                         AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1000                 }
1001
1002                 Action action;
1003                 
1004                 public override void Emit (EmitContext ec)
1005                 {
1006                         ILGenerator ig = ec.ig;
1007
1008                         expr.Emit (ec);
1009
1010                         switch (action){
1011                         case Action.AlwaysFalse:
1012                                 ig.Emit (OpCodes.Pop);
1013                                 IntConstant.EmitInt (ig, 0);
1014                                 return;
1015                         case Action.AlwaysTrue:
1016                                 ig.Emit (OpCodes.Pop);
1017                                 ig.Emit (OpCodes.Nop);
1018                                 IntConstant.EmitInt (ig, 1);
1019                                 return;
1020                         case Action.LeaveOnStack:
1021                                 // the `e != null' rule.
1022                                 return;
1023                         case Action.Probe:
1024                                 ig.Emit (OpCodes.Isinst, probe_type);
1025                                 ig.Emit (OpCodes.Ldnull);
1026                                 ig.Emit (OpCodes.Cgt_Un);
1027                                 return;
1028                         }
1029                         throw new Exception ("never reached");
1030                 }
1031
1032                 public override Expression DoResolve (EmitContext ec)
1033                 {
1034                         Expression e = base.DoResolve (ec);
1035
1036                         if ((e == null) || (expr == null))
1037                                 return null;
1038
1039                         Type etype = expr.Type;
1040                         bool warning_always_matches = false;
1041                         bool warning_never_matches = false;
1042
1043                         type = TypeManager.bool_type;
1044                         eclass = ExprClass.Value;
1045
1046                         //
1047                         // First case, if at compile time, there is an implicit conversion
1048                         // then e != null (objects) or true (value types)
1049                         //
1050                         e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1051                         if (e != null){
1052                                 expr = e;
1053                                 if (etype.IsValueType)
1054                                         action = Action.AlwaysTrue;
1055                                 else
1056                                         action = Action.LeaveOnStack;
1057
1058                                 warning_always_matches = true;
1059                         } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1060                                 //
1061                                 // Second case: explicit reference convresion
1062                                 //
1063                                 if (expr is NullLiteral)
1064                                         action = Action.AlwaysFalse;
1065                                 else
1066                                         action = Action.Probe;
1067                         } else {
1068                                 action = Action.AlwaysFalse;
1069                                 warning_never_matches = true;
1070                         }
1071                         
1072                         if (RootContext.WarningLevel >= 1){
1073                                 if (warning_always_matches)
1074                                         Warning (
1075                                                 183,
1076                                                 "The expression is always of type `" +
1077                                                 TypeManager.CSharpName (probe_type) + "'");
1078                                 else if (warning_never_matches){
1079                                         if (!(probe_type.IsInterface || expr.Type.IsInterface))
1080                                                 Warning (
1081                                                         184,
1082                                                         "The expression is never of type `" +
1083                                                         TypeManager.CSharpName (probe_type) + "'");
1084                                 }
1085                         }
1086
1087                         return this;
1088                 }                               
1089         }
1090
1091         /// <summary>
1092         ///   Implementation of the `as' operator.
1093         /// </summary>
1094         public class As : Probe {
1095                 public As (Expression expr, Expression probe_type, Location l)
1096                         : base (expr, probe_type, l)
1097                 {
1098                 }
1099
1100                 bool do_isinst = false;
1101                 
1102                 public override void Emit (EmitContext ec)
1103                 {
1104                         ILGenerator ig = ec.ig;
1105
1106                         expr.Emit (ec);
1107
1108                         if (do_isinst)
1109                                 ig.Emit (OpCodes.Isinst, probe_type);
1110                 }
1111
1112                 static void Error_CannotConvertType (Type source, Type target, Location loc)
1113                 {
1114                         Report.Error (
1115                                 39, loc, "as operator can not convert from `" +
1116                                 TypeManager.CSharpName (source) + "' to `" +
1117                                 TypeManager.CSharpName (target) + "'");
1118                 }
1119                 
1120                 public override Expression DoResolve (EmitContext ec)
1121                 {
1122                         Expression e = base.DoResolve (ec);
1123
1124                         if (e == null)
1125                                 return null;
1126
1127                         type = probe_type;
1128                         eclass = ExprClass.Value;
1129                         Type etype = expr.Type;
1130                         
1131                         e = ConvertImplicit (ec, expr, probe_type, loc);
1132                         if (e != null){
1133                                 expr = e;
1134                                 do_isinst = false;
1135                                 return this;
1136                         }
1137
1138                         if (ExplicitReferenceConversionExists (etype, probe_type)){
1139                                 do_isinst = true;
1140                                 return this;
1141                         }
1142
1143                         Error_CannotConvertType (etype, probe_type, loc);
1144                         return null;
1145                 }                               
1146         }
1147         
1148         /// <summary>
1149         ///   This represents a typecast in the source language.
1150         ///
1151         ///   FIXME: Cast expressions have an unusual set of parsing
1152         ///   rules, we need to figure those out.
1153         /// </summary>
1154         public class Cast : Expression {
1155                 Expression target_type;
1156                 Expression expr;
1157                         
1158                 public Cast (Expression cast_type, Expression expr, Location loc)
1159                 {
1160                         this.target_type = cast_type;
1161                         this.expr = expr;
1162                         this.loc = loc;
1163                 }
1164
1165                 public Expression TargetType {
1166                         get {
1167                                 return target_type;
1168                         }
1169                 }
1170
1171                 public Expression Expr {
1172                         get {
1173                                 return expr;
1174                         }
1175                         set {
1176                                 expr = value;
1177                         }
1178                 }
1179
1180                 /// <summary>
1181                 ///   Attempts to do a compile-time folding of a constant cast.
1182                 /// </summary>
1183                 Expression TryReduce (EmitContext ec, Type target_type)
1184                 {
1185                         if (expr is ByteConstant){
1186                                 byte v = ((ByteConstant) expr).Value;
1187         
1188                                 if (target_type == TypeManager.sbyte_type)
1189                                         return new SByteConstant ((sbyte) v);
1190                                 if (target_type == TypeManager.short_type)
1191                                         return new ShortConstant ((short) v);
1192                                 if (target_type == TypeManager.ushort_type)
1193                                         return new UShortConstant ((ushort) v);
1194                                 if (target_type == TypeManager.int32_type)
1195                                         return new IntConstant ((int) v);
1196                                 if (target_type == TypeManager.uint32_type)
1197                                         return new UIntConstant ((uint) v);
1198                                 if (target_type == TypeManager.int64_type)
1199                                         return new LongConstant ((long) v);
1200                                 if (target_type == TypeManager.uint64_type)
1201                                         return new ULongConstant ((ulong) v);
1202                                 if (target_type == TypeManager.float_type)
1203                                         return new FloatConstant ((float) v);
1204                                 if (target_type == TypeManager.double_type)
1205                                         return new DoubleConstant ((double) v);
1206                                 if (target_type == TypeManager.char_type)
1207                                         return new CharConstant ((char) v);
1208                                 if (target_type == TypeManager.decimal_type)
1209                                         return new DecimalConstant ((decimal) v);
1210                         }
1211                         if (expr is SByteConstant){
1212                                 sbyte v = ((SByteConstant) expr).Value;
1213         
1214                                 if (target_type == TypeManager.byte_type)
1215                                         return new ByteConstant ((byte) v);
1216                                 if (target_type == TypeManager.short_type)
1217                                         return new ShortConstant ((short) v);
1218                                 if (target_type == TypeManager.ushort_type)
1219                                         return new UShortConstant ((ushort) v);
1220                                 if (target_type == TypeManager.int32_type)
1221                                         return new IntConstant ((int) v);
1222                                 if (target_type == TypeManager.uint32_type)
1223                                         return new UIntConstant ((uint) v);
1224                                 if (target_type == TypeManager.int64_type)
1225                                         return new LongConstant ((long) v);
1226                                 if (target_type == TypeManager.uint64_type)
1227                                         return new ULongConstant ((ulong) v);
1228                                 if (target_type == TypeManager.float_type)
1229                                         return new FloatConstant ((float) v);
1230                                 if (target_type == TypeManager.double_type)
1231                                         return new DoubleConstant ((double) v);
1232                                 if (target_type == TypeManager.char_type)
1233                                         return new CharConstant ((char) v);
1234                                 if (target_type == TypeManager.decimal_type)
1235                                         return new DecimalConstant ((decimal) v);
1236                         }
1237                         if (expr is ShortConstant){
1238                                 short v = ((ShortConstant) expr).Value;
1239         
1240                                 if (target_type == TypeManager.byte_type)
1241                                         return new ByteConstant ((byte) v);
1242                                 if (target_type == TypeManager.sbyte_type)
1243                                         return new SByteConstant ((sbyte) v);
1244                                 if (target_type == TypeManager.ushort_type)
1245                                         return new UShortConstant ((ushort) v);
1246                                 if (target_type == TypeManager.int32_type)
1247                                         return new IntConstant ((int) v);
1248                                 if (target_type == TypeManager.uint32_type)
1249                                         return new UIntConstant ((uint) v);
1250                                 if (target_type == TypeManager.int64_type)
1251                                         return new LongConstant ((long) v);
1252                                 if (target_type == TypeManager.uint64_type)
1253                                         return new ULongConstant ((ulong) v);
1254                                 if (target_type == TypeManager.float_type)
1255                                         return new FloatConstant ((float) v);
1256                                 if (target_type == TypeManager.double_type)
1257                                         return new DoubleConstant ((double) v);
1258                                 if (target_type == TypeManager.char_type)
1259                                         return new CharConstant ((char) v);
1260                                 if (target_type == TypeManager.decimal_type)
1261                                         return new DecimalConstant ((decimal) v);
1262                         }
1263                         if (expr is UShortConstant){
1264                                 ushort v = ((UShortConstant) expr).Value;
1265         
1266                                 if (target_type == TypeManager.byte_type)
1267                                         return new ByteConstant ((byte) v);
1268                                 if (target_type == TypeManager.sbyte_type)
1269                                         return new SByteConstant ((sbyte) v);
1270                                 if (target_type == TypeManager.short_type)
1271                                         return new ShortConstant ((short) v);
1272                                 if (target_type == TypeManager.int32_type)
1273                                         return new IntConstant ((int) v);
1274                                 if (target_type == TypeManager.uint32_type)
1275                                         return new UIntConstant ((uint) v);
1276                                 if (target_type == TypeManager.int64_type)
1277                                         return new LongConstant ((long) v);
1278                                 if (target_type == TypeManager.uint64_type)
1279                                         return new ULongConstant ((ulong) v);
1280                                 if (target_type == TypeManager.float_type)
1281                                         return new FloatConstant ((float) v);
1282                                 if (target_type == TypeManager.double_type)
1283                                         return new DoubleConstant ((double) v);
1284                                 if (target_type == TypeManager.char_type)
1285                                         return new CharConstant ((char) v);
1286                                 if (target_type == TypeManager.decimal_type)
1287                                         return new DecimalConstant ((decimal) v);
1288                         }
1289                         if (expr is IntConstant){
1290                                 int v = ((IntConstant) expr).Value;
1291         
1292                                 if (target_type == TypeManager.byte_type)
1293                                         return new ByteConstant ((byte) v);
1294                                 if (target_type == TypeManager.sbyte_type)
1295                                         return new SByteConstant ((sbyte) v);
1296                                 if (target_type == TypeManager.short_type)
1297                                         return new ShortConstant ((short) v);
1298                                 if (target_type == TypeManager.ushort_type)
1299                                         return new UShortConstant ((ushort) v);
1300                                 if (target_type == TypeManager.uint32_type)
1301                                         return new UIntConstant ((uint) v);
1302                                 if (target_type == TypeManager.int64_type)
1303                                         return new LongConstant ((long) v);
1304                                 if (target_type == TypeManager.uint64_type)
1305                                         return new ULongConstant ((ulong) v);
1306                                 if (target_type == TypeManager.float_type)
1307                                         return new FloatConstant ((float) v);
1308                                 if (target_type == TypeManager.double_type)
1309                                         return new DoubleConstant ((double) v);
1310                                 if (target_type == TypeManager.char_type)
1311                                         return new CharConstant ((char) v);
1312                                 if (target_type == TypeManager.decimal_type)
1313                                         return new DecimalConstant ((decimal) v);
1314                         }
1315                         if (expr is UIntConstant){
1316                                 uint v = ((UIntConstant) expr).Value;
1317         
1318                                 if (target_type == TypeManager.byte_type)
1319                                         return new ByteConstant ((byte) v);
1320                                 if (target_type == TypeManager.sbyte_type)
1321                                         return new SByteConstant ((sbyte) v);
1322                                 if (target_type == TypeManager.short_type)
1323                                         return new ShortConstant ((short) v);
1324                                 if (target_type == TypeManager.ushort_type)
1325                                         return new UShortConstant ((ushort) v);
1326                                 if (target_type == TypeManager.int32_type)
1327                                         return new IntConstant ((int) v);
1328                                 if (target_type == TypeManager.int64_type)
1329                                         return new LongConstant ((long) v);
1330                                 if (target_type == TypeManager.uint64_type)
1331                                         return new ULongConstant ((ulong) v);
1332                                 if (target_type == TypeManager.float_type)
1333                                         return new FloatConstant ((float) v);
1334                                 if (target_type == TypeManager.double_type)
1335                                         return new DoubleConstant ((double) v);
1336                                 if (target_type == TypeManager.char_type)
1337                                         return new CharConstant ((char) v);
1338                                 if (target_type == TypeManager.decimal_type)
1339                                         return new DecimalConstant ((decimal) v);
1340                         }
1341                         if (expr is LongConstant){
1342                                 long v = ((LongConstant) expr).Value;
1343         
1344                                 if (target_type == TypeManager.byte_type)
1345                                         return new ByteConstant ((byte) v);
1346                                 if (target_type == TypeManager.sbyte_type)
1347                                         return new SByteConstant ((sbyte) v);
1348                                 if (target_type == TypeManager.short_type)
1349                                         return new ShortConstant ((short) v);
1350                                 if (target_type == TypeManager.ushort_type)
1351                                         return new UShortConstant ((ushort) v);
1352                                 if (target_type == TypeManager.int32_type)
1353                                         return new IntConstant ((int) v);
1354                                 if (target_type == TypeManager.uint32_type)
1355                                         return new UIntConstant ((uint) v);
1356                                 if (target_type == TypeManager.uint64_type)
1357                                         return new ULongConstant ((ulong) v);
1358                                 if (target_type == TypeManager.float_type)
1359                                         return new FloatConstant ((float) v);
1360                                 if (target_type == TypeManager.double_type)
1361                                         return new DoubleConstant ((double) v);
1362                                 if (target_type == TypeManager.char_type)
1363                                         return new CharConstant ((char) v);
1364                                 if (target_type == TypeManager.decimal_type)
1365                                         return new DecimalConstant ((decimal) v);
1366                         }
1367                         if (expr is ULongConstant){
1368                                 ulong v = ((ULongConstant) expr).Value;
1369         
1370                                 if (target_type == TypeManager.byte_type)
1371                                         return new ByteConstant ((byte) v);
1372                                 if (target_type == TypeManager.sbyte_type)
1373                                         return new SByteConstant ((sbyte) v);
1374                                 if (target_type == TypeManager.short_type)
1375                                         return new ShortConstant ((short) v);
1376                                 if (target_type == TypeManager.ushort_type)
1377                                         return new UShortConstant ((ushort) v);
1378                                 if (target_type == TypeManager.int32_type)
1379                                         return new IntConstant ((int) v);
1380                                 if (target_type == TypeManager.uint32_type)
1381                                         return new UIntConstant ((uint) v);
1382                                 if (target_type == TypeManager.int64_type)
1383                                         return new LongConstant ((long) v);
1384                                 if (target_type == TypeManager.float_type)
1385                                         return new FloatConstant ((float) v);
1386                                 if (target_type == TypeManager.double_type)
1387                                         return new DoubleConstant ((double) v);
1388                                 if (target_type == TypeManager.char_type)
1389                                         return new CharConstant ((char) v);
1390                                 if (target_type == TypeManager.decimal_type)
1391                                         return new DecimalConstant ((decimal) v);
1392                         }
1393                         if (expr is FloatConstant){
1394                                 float v = ((FloatConstant) expr).Value;
1395         
1396                                 if (target_type == TypeManager.byte_type)
1397                                         return new ByteConstant ((byte) v);
1398                                 if (target_type == TypeManager.sbyte_type)
1399                                         return new SByteConstant ((sbyte) v);
1400                                 if (target_type == TypeManager.short_type)
1401                                         return new ShortConstant ((short) v);
1402                                 if (target_type == TypeManager.ushort_type)
1403                                         return new UShortConstant ((ushort) v);
1404                                 if (target_type == TypeManager.int32_type)
1405                                         return new IntConstant ((int) v);
1406                                 if (target_type == TypeManager.uint32_type)
1407                                         return new UIntConstant ((uint) v);
1408                                 if (target_type == TypeManager.int64_type)
1409                                         return new LongConstant ((long) v);
1410                                 if (target_type == TypeManager.uint64_type)
1411                                         return new ULongConstant ((ulong) v);
1412                                 if (target_type == TypeManager.double_type)
1413                                         return new DoubleConstant ((double) v);
1414                                 if (target_type == TypeManager.char_type)
1415                                         return new CharConstant ((char) v);
1416                                 if (target_type == TypeManager.decimal_type)
1417                                         return new DecimalConstant ((decimal) v);
1418                         }
1419                         if (expr is DoubleConstant){
1420                                 double v = ((DoubleConstant) expr).Value;
1421         
1422                                 if (target_type == TypeManager.byte_type)
1423                                         return new ByteConstant ((byte) v);
1424                                 if (target_type == TypeManager.sbyte_type)
1425                                         return new SByteConstant ((sbyte) v);
1426                                 if (target_type == TypeManager.short_type)
1427                                         return new ShortConstant ((short) v);
1428                                 if (target_type == TypeManager.ushort_type)
1429                                         return new UShortConstant ((ushort) v);
1430                                 if (target_type == TypeManager.int32_type)
1431                                         return new IntConstant ((int) v);
1432                                 if (target_type == TypeManager.uint32_type)
1433                                         return new UIntConstant ((uint) v);
1434                                 if (target_type == TypeManager.int64_type)
1435                                         return new LongConstant ((long) v);
1436                                 if (target_type == TypeManager.uint64_type)
1437                                         return new ULongConstant ((ulong) v);
1438                                 if (target_type == TypeManager.float_type)
1439                                         return new FloatConstant ((float) v);
1440                                 if (target_type == TypeManager.char_type)
1441                                         return new CharConstant ((char) v);
1442                                 if (target_type == TypeManager.decimal_type)
1443                                         return new DecimalConstant ((decimal) v);
1444                         }
1445
1446                         return null;
1447                 }
1448                 
1449                 public override Expression DoResolve (EmitContext ec)
1450                 {
1451                         expr = expr.Resolve (ec);
1452                         if (expr == null)
1453                                 return null;
1454
1455                         int errors = Report.Errors;
1456
1457                         type = ec.DeclSpace.ResolveType (target_type, false, Location);
1458                         
1459                         if (type == null)
1460                                 return null;
1461
1462                         eclass = ExprClass.Value;
1463                         
1464                         if (expr is Constant){
1465                                 Expression e = TryReduce (ec, type);
1466
1467                                 if (e != null)
1468                                         return e;
1469                         }
1470                         
1471                         expr = ConvertExplicit (ec, expr, type, loc);
1472                         return expr;
1473                 }
1474
1475                 public override void Emit (EmitContext ec)
1476                 {
1477                         //
1478                         // This one will never happen
1479                         //
1480                         throw new Exception ("Should not happen");
1481                 }
1482         }
1483
1484         /// <summary>
1485         ///   Binary operators
1486         /// </summary>
1487         public class Binary : Expression {
1488                 public enum Operator : byte {
1489                         Multiply, Division, Modulus,
1490                         Addition, Subtraction,
1491                         LeftShift, RightShift,
1492                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1493                         Equality, Inequality,
1494                         BitwiseAnd,
1495                         ExclusiveOr,
1496                         BitwiseOr,
1497                         LogicalAnd,
1498                         LogicalOr,
1499                         TOP
1500                 }
1501
1502                 Operator oper;
1503                 Expression left, right;
1504
1505                 //
1506                 // After resolution, method might contain the operator overload
1507                 // method.
1508                 //
1509                 protected MethodBase method;
1510                 ArrayList  Arguments;
1511
1512                 bool DelegateOperation;
1513
1514                 // This must be kept in sync with Operator!!!
1515                 static string [] oper_names;
1516
1517                 static Binary ()
1518                 {
1519                         oper_names = new string [(int) Operator.TOP];
1520
1521                         oper_names [(int) Operator.Multiply] = "op_Multiply";
1522                         oper_names [(int) Operator.Division] = "op_Division";
1523                         oper_names [(int) Operator.Modulus] = "op_Modulus";
1524                         oper_names [(int) Operator.Addition] = "op_Addition";
1525                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1526                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1527                         oper_names [(int) Operator.RightShift] = "op_RightShift";
1528                         oper_names [(int) Operator.LessThan] = "op_LessThan";
1529                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1530                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1531                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1532                         oper_names [(int) Operator.Equality] = "op_Equality";
1533                         oper_names [(int) Operator.Inequality] = "op_Inequality";
1534                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1535                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1536                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1537                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1538                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1539                 }
1540
1541                 public Binary (Operator oper, Expression left, Expression right, Location loc)
1542                 {
1543                         this.oper = oper;
1544                         this.left = left;
1545                         this.right = right;
1546                         this.loc = loc;
1547                 }
1548
1549                 public Operator Oper {
1550                         get {
1551                                 return oper;
1552                         }
1553                         set {
1554                                 oper = value;
1555                         }
1556                 }
1557                 
1558                 public Expression Left {
1559                         get {
1560                                 return left;
1561                         }
1562                         set {
1563                                 left = value;
1564                         }
1565                 }
1566
1567                 public Expression Right {
1568                         get {
1569                                 return right;
1570                         }
1571                         set {
1572                                 right = value;
1573                         }
1574                 }
1575
1576
1577                 /// <summary>
1578                 ///   Returns a stringified representation of the Operator
1579                 /// </summary>
1580                 static string OperName (Operator oper)
1581                 {
1582                         switch (oper){
1583                         case Operator.Multiply:
1584                                 return "*";
1585                         case Operator.Division:
1586                                 return "/";
1587                         case Operator.Modulus:
1588                                 return "%";
1589                         case Operator.Addition:
1590                                 return "+";
1591                         case Operator.Subtraction:
1592                                 return "-";
1593                         case Operator.LeftShift:
1594                                 return "<<";
1595                         case Operator.RightShift:
1596                                 return ">>";
1597                         case Operator.LessThan:
1598                                 return "<";
1599                         case Operator.GreaterThan:
1600                                 return ">";
1601                         case Operator.LessThanOrEqual:
1602                                 return "<=";
1603                         case Operator.GreaterThanOrEqual:
1604                                 return ">=";
1605                         case Operator.Equality:
1606                                 return "==";
1607                         case Operator.Inequality:
1608                                 return "!=";
1609                         case Operator.BitwiseAnd:
1610                                 return "&";
1611                         case Operator.BitwiseOr:
1612                                 return "|";
1613                         case Operator.ExclusiveOr:
1614                                 return "^";
1615                         case Operator.LogicalOr:
1616                                 return "||";
1617                         case Operator.LogicalAnd:
1618                                 return "&&";
1619                         }
1620
1621                         return oper.ToString ();
1622                 }
1623
1624                 public override string ToString ()
1625                 {
1626                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1627                                 right.ToString () + ")";
1628                 }
1629                 
1630                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1631                 {
1632                         if (expr.Type == target_type)
1633                                 return expr;
1634
1635                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
1636                 }
1637
1638                 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1639                 {
1640                         Report.Error (
1641                                 34, loc, "Operator `" + OperName (oper) 
1642                                 + "' is ambiguous on operands of type `"
1643                                 + TypeManager.CSharpName (l) + "' "
1644                                 + "and `" + TypeManager.CSharpName (r)
1645                                 + "'");
1646                 }
1647
1648                 //
1649                 // Note that handling the case l == Decimal || r == Decimal
1650                 // is taken care of by the Step 1 Operator Overload resolution.
1651                 //
1652                 bool DoNumericPromotions (EmitContext ec, Type l, Type r)
1653                 {
1654                         if (l == TypeManager.double_type || r == TypeManager.double_type){
1655                                 //
1656                                 // If either operand is of type double, the other operand is
1657                                 // conveted to type double.
1658                                 //
1659                                 if (r != TypeManager.double_type)
1660                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
1661                                 if (l != TypeManager.double_type)
1662                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
1663                                 
1664                                 type = TypeManager.double_type;
1665                         } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1666                                 //
1667                                 // if either operand is of type float, the other operand is
1668                                 // converted to type float.
1669                                 //
1670                                 if (r != TypeManager.double_type)
1671                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
1672                                 if (l != TypeManager.double_type)
1673                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
1674                                 type = TypeManager.float_type;
1675                         } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
1676                                 Expression e;
1677                                 Type other;
1678                                 //
1679                                 // If either operand is of type ulong, the other operand is
1680                                 // converted to type ulong.  or an error ocurrs if the other
1681                                 // operand is of type sbyte, short, int or long
1682                                 //
1683                                 if (l == TypeManager.uint64_type){
1684                                         if (r != TypeManager.uint64_type){
1685                                                 if (right is IntConstant){
1686                                                         IntConstant ic = (IntConstant) right;
1687                                                         
1688                                                         e = TryImplicitIntConversion (l, ic);
1689                                                         if (e != null)
1690                                                                 right = e;
1691                                                 } else if (right is LongConstant){
1692                                                         long ll = ((LongConstant) right).Value;
1693
1694                                                         if (ll > 0)
1695                                                                 right = new ULongConstant ((ulong) ll);
1696                                                 } else {
1697                                                         e = ImplicitNumericConversion (ec, right, l, loc);
1698                                                         if (e != null)
1699                                                                 right = e;
1700                                                 }
1701                                         }
1702                                         other = right.Type;
1703                                 } else {
1704                                         if (left is IntConstant){
1705                                                 e = TryImplicitIntConversion (r, (IntConstant) left);
1706                                                 if (e != null)
1707                                                         left = e;
1708                                         } else if (left is LongConstant){
1709                                                 long ll = ((LongConstant) left).Value;
1710                                                 
1711                                                 if (ll > 0)
1712                                                         left = new ULongConstant ((ulong) ll);
1713                                         } else {
1714                                                 e = ImplicitNumericConversion (ec, left, r, loc);
1715                                                 if (e != null)
1716                                                         left = e;
1717                                         }
1718                                         other = left.Type;
1719                                 }
1720
1721                                 if ((other == TypeManager.sbyte_type) ||
1722                                     (other == TypeManager.short_type) ||
1723                                     (other == TypeManager.int32_type) ||
1724                                     (other == TypeManager.int64_type))
1725                                         Error_OperatorAmbiguous (loc, oper, l, r);
1726                                 type = TypeManager.uint64_type;
1727                         } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1728                                 //
1729                                 // If either operand is of type long, the other operand is converted
1730                                 // to type long.
1731                                 //
1732                                 if (l != TypeManager.int64_type)
1733                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
1734                                 if (r != TypeManager.int64_type)
1735                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
1736                                 
1737                                 type = TypeManager.int64_type;
1738                         } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1739                                 //
1740                                 // If either operand is of type uint, and the other
1741                                 // operand is of type sbyte, short or int, othe operands are
1742                                 // converted to type long.
1743                                 //
1744                                 Type other = null;
1745                                 
1746                                 if (l == TypeManager.uint32_type){
1747                                         if (right is IntConstant){
1748                                                 IntConstant ic = (IntConstant) right;
1749                                                 int val = ic.Value;
1750                                                 
1751                                                 if (val >= 0)
1752                                                         right = new UIntConstant ((uint) val);
1753
1754                                                 type = l;
1755                                                 return true;
1756                                         }
1757                                         other = r;
1758                                 } 
1759                                 else if (r == TypeManager.uint32_type){
1760                                         if (left is IntConstant){
1761                                                 IntConstant ic = (IntConstant) left;
1762                                                 int val = ic.Value;
1763                                                 
1764                                                 if (val >= 0)
1765                                                         left = new UIntConstant ((uint) val);
1766
1767                                                 type = r;
1768                                                 return true;
1769                                         }
1770                                         
1771                                         other = l;
1772                                 }
1773
1774                                 if ((other == TypeManager.sbyte_type) ||
1775                                     (other == TypeManager.short_type) ||
1776                                     (other == TypeManager.int32_type)){
1777                                         left = ForceConversion (ec, left, TypeManager.int64_type);
1778                                         right = ForceConversion (ec, right, TypeManager.int64_type);
1779                                         type = TypeManager.int64_type;
1780                                 } else {
1781                                         //
1782                                         // if either operand is of type uint, the other
1783                                         // operand is converd to type uint
1784                                         //
1785                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
1786                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
1787                                         type = TypeManager.uint32_type;
1788                                 } 
1789                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1790                                 if (l != TypeManager.decimal_type)
1791                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
1792
1793                                 if (r != TypeManager.decimal_type)
1794                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
1795                                 type = TypeManager.decimal_type;
1796                         } else {
1797                                 left = ForceConversion (ec, left, TypeManager.int32_type);
1798                                 right = ForceConversion (ec, right, TypeManager.int32_type);
1799
1800                                 type = TypeManager.int32_type;
1801                         }
1802
1803                         return (left != null) && (right != null);
1804                 }
1805
1806                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1807                 {
1808                         Report.Error (19, loc,
1809                                "Operator " + name + " cannot be applied to operands of type `" +
1810                                TypeManager.CSharpName (l) + "' and `" +
1811                                TypeManager.CSharpName (r) + "'");
1812                 }
1813                 
1814                 void Error_OperatorCannotBeApplied ()
1815                 {
1816                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1817                 }
1818
1819                 static bool is_32_or_64 (Type t)
1820                 {
1821                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1822                                 t == TypeManager.int64_type || t == TypeManager.uint64_type);
1823                 }
1824
1825                 static bool is_unsigned (Type t)
1826                 {
1827                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1828                                 t == TypeManager.short_type || t == TypeManager.byte_type);
1829                 }
1830                                         
1831                 Expression CheckShiftArguments (EmitContext ec)
1832                 {
1833                         Expression e;
1834                         Type l = left.Type;
1835                         Type r = right.Type;
1836
1837                         e = ForceConversion (ec, right, TypeManager.int32_type);
1838                         if (e == null){
1839                                 Error_OperatorCannotBeApplied ();
1840                                 return null;
1841                         }
1842                         right = e;
1843
1844                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
1845                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
1846                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
1847                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
1848                                 left = e;
1849                                 type = e.Type;
1850
1851                                 return this;
1852                         }
1853                         Error_OperatorCannotBeApplied ();
1854                         return null;
1855                 }
1856
1857                 Expression ResolveOperator (EmitContext ec)
1858                 {
1859                         Type l = left.Type;
1860                         Type r = right.Type;
1861
1862                         bool overload_failed = false;
1863
1864                         //
1865                         // Step 1: Perform Operator Overload location
1866                         //
1867                         Expression left_expr, right_expr;
1868                                 
1869                         string op = oper_names [(int) oper];
1870                                 
1871                         MethodGroupExpr union;
1872                         left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
1873                         if (r != l){
1874                                 right_expr = MemberLookup (
1875                                         ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
1876                                 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
1877                         } else
1878                                 union = (MethodGroupExpr) left_expr;
1879                                 
1880                         if (union != null) {
1881                                 Arguments = new ArrayList ();
1882                                 Arguments.Add (new Argument (left, Argument.AType.Expression));
1883                                 Arguments.Add (new Argument (right, Argument.AType.Expression));
1884                                 
1885                                 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
1886                                 if (method != null) {
1887                                         MethodInfo mi = (MethodInfo) method;
1888                                         
1889                                         type = mi.ReturnType;
1890                                         return this;
1891                                 } else {
1892                                         overload_failed = true;
1893                                 }
1894                         }       
1895                         
1896                         //
1897                         // Step 2: Default operations on CLI native types.
1898                         //
1899
1900                         //
1901                         // Step 0: String concatenation (because overloading will get this wrong)
1902                         //
1903                         if (oper == Operator.Addition){
1904                                 //
1905                                 // If any of the arguments is a string, cast to string
1906                                 //
1907                                 
1908                                 if (l == TypeManager.string_type){
1909                                         
1910                                         if (r == TypeManager.void_type) {
1911                                                 Error_OperatorCannotBeApplied ();
1912                                                 return null;
1913                                         }
1914                                         
1915                                         if (r == TypeManager.string_type){
1916                                                 if (left is Constant && right is Constant){
1917                                                         StringConstant ls = (StringConstant) left;
1918                                                         StringConstant rs = (StringConstant) right;
1919                                                         
1920                                                         return new StringConstant (
1921                                                                 ls.Value + rs.Value);
1922                                                 }
1923                                                 
1924                                                 // string + string
1925                                                 method = TypeManager.string_concat_string_string;
1926                                         } else {
1927                                                 // string + object
1928                                                 method = TypeManager.string_concat_object_object;
1929                                                 right = ConvertImplicit (ec, right,
1930                                                                          TypeManager.object_type, loc);
1931                                         }
1932                                         type = TypeManager.string_type;
1933
1934                                         Arguments = new ArrayList ();
1935                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1936                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1937
1938                                         return this;
1939                                         
1940                                 } else if (r == TypeManager.string_type){
1941                                         // object + string
1942
1943                                         if (l == TypeManager.void_type) {
1944                                                 Error_OperatorCannotBeApplied ();
1945                                                 return null;
1946                                         }
1947                                         
1948                                         method = TypeManager.string_concat_object_object;
1949                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
1950                                         Arguments = new ArrayList ();
1951                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
1952                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
1953
1954                                         type = TypeManager.string_type;
1955
1956                                         return this;
1957                                 }
1958
1959                                 //
1960                                 // Transform a + ( - b) into a - b
1961                                 //
1962                                 if (right is Unary){
1963                                         Unary right_unary = (Unary) right;
1964
1965                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
1966                                                 oper = Operator.Subtraction;
1967                                                 right = right_unary.Expr;
1968                                                 r = right.Type;
1969                                         }
1970                                 }
1971                         }
1972
1973                         if (oper == Operator.Equality || oper == Operator.Inequality){
1974                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1975                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1976                                                 Error_OperatorCannotBeApplied ();
1977                                                 return null;
1978                                         }
1979                                         
1980                                         type = TypeManager.bool_type;
1981                                         return this;
1982                                 }
1983
1984                                 //
1985                                 // operator != (object a, object b)
1986                                 // operator == (object a, object b)
1987                                 //
1988                                 // For this to be used, both arguments have to be reference-types.
1989                                 // Read the rationale on the spec (14.9.6)
1990                                 //
1991                                 // Also, if at compile time we know that the classes do not inherit
1992                                 // one from the other, then we catch the error there.
1993                                 //
1994                                 if (!(l.IsValueType || r.IsValueType)){
1995                                         type = TypeManager.bool_type;
1996
1997                                         if (l == r)
1998                                                 return this;
1999                                         
2000                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2001                                                 return this;
2002
2003                                         //
2004                                         // Also, a standard conversion must exist from either one
2005                                         //
2006                                         if (!(StandardConversionExists (left, r) ||
2007                                               StandardConversionExists (right, l))){
2008                                                 Error_OperatorCannotBeApplied ();
2009                                                 return null;
2010                                         }
2011                                         //
2012                                         // We are going to have to convert to an object to compare
2013                                         //
2014                                         if (l != TypeManager.object_type)
2015                                                 left = new EmptyCast (left, TypeManager.object_type);
2016                                         if (r != TypeManager.object_type)
2017                                                 right = new EmptyCast (right, TypeManager.object_type);
2018
2019                                         //
2020                                         // FIXME: CSC here catches errors cs254 and cs252
2021                                         //
2022                                         return this;
2023                                 }
2024
2025                                 //
2026                                 // One of them is a valuetype, but the other one is not.
2027                                 //
2028                                 if (!l.IsValueType || !r.IsValueType) {
2029                                         Error_OperatorCannotBeApplied ();
2030                                         return null;
2031                                 }
2032                         }
2033
2034                         // Only perform numeric promotions on:
2035                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2036                         //
2037                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2038                                 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2039                                     r.IsSubclassOf (TypeManager.delegate_type)) {
2040                                         
2041                                         Arguments = new ArrayList ();
2042                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2043                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2044                                         
2045                                         if (oper == Operator.Addition)
2046                                                 method = TypeManager.delegate_combine_delegate_delegate;
2047                                         else
2048                                                 method = TypeManager.delegate_remove_delegate_delegate;
2049
2050                                         if (l != r) {
2051                                                 Error_OperatorCannotBeApplied ();
2052                                                 return null;
2053                                         }
2054
2055                                         DelegateOperation = true;
2056                                         type = l;
2057                                         return this;
2058                                 }
2059
2060                                 //
2061                                 // Pointer arithmetic:
2062                                 //
2063                                 // T* operator + (T* x, int y);
2064                                 // T* operator + (T* x, uint y);
2065                                 // T* operator + (T* x, long y);
2066                                 // T* operator + (T* x, ulong y);
2067                                 //
2068                                 // T* operator + (int y,   T* x);
2069                                 // T* operator + (uint y,  T *x);
2070                                 // T* operator + (long y,  T *x);
2071                                 // T* operator + (ulong y, T *x);
2072                                 //
2073                                 // T* operator - (T* x, int y);
2074                                 // T* operator - (T* x, uint y);
2075                                 // T* operator - (T* x, long y);
2076                                 // T* operator - (T* x, ulong y);
2077                                 //
2078                                 // long operator - (T* x, T *y)
2079                                 //
2080                                 if (l.IsPointer){
2081                                         if (r.IsPointer && oper == Operator.Subtraction){
2082                                                 if (r == l)
2083                                                         return new PointerArithmetic (
2084                                                                 false, left, right, TypeManager.int64_type,
2085                                                                 loc);
2086                                         } else if (is_32_or_64 (r))
2087                                                 return new PointerArithmetic (
2088                                                         oper == Operator.Addition, left, right, l, loc);
2089                                 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2090                                         return new PointerArithmetic (
2091                                                 true, right, left, r, loc);
2092                         }
2093                         
2094                         //
2095                         // Enumeration operators
2096                         //
2097                         bool lie = TypeManager.IsEnumType (l);
2098                         bool rie = TypeManager.IsEnumType (r);
2099                         if (lie || rie){
2100                                 Expression temp;
2101
2102                                 //
2103                                 // operator + (E e, U x)
2104                                 //
2105                                 if (oper == Operator.Addition){
2106                                         if (lie && rie){
2107                                                 Error_OperatorCannotBeApplied ();
2108                                                 return null;
2109                                         }
2110
2111                                         Type enum_type = lie ? l : r;
2112                                         Type other_type = lie ? r : l;
2113                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2114 ;
2115                                         
2116                                         if (underlying_type != other_type){
2117                                                 Error_OperatorCannotBeApplied ();
2118                                                 return null;
2119                                         }
2120
2121                                         type = enum_type;
2122                                         return this;
2123                                 }
2124                                 
2125                                 if (!rie){
2126                                         temp = ConvertImplicit (ec, right, l, loc);
2127                                         if (temp != null)
2128                                                 right = temp;
2129                                         else {
2130                                                 Error_OperatorCannotBeApplied ();
2131                                                 return null;
2132                                         }
2133                                 } if (!lie){
2134                                         temp = ConvertImplicit (ec, left, r, loc);
2135                                         if (temp != null){
2136                                                 left = temp;
2137                                                 l = r;
2138                                         } else {
2139                                                 Error_OperatorCannotBeApplied ();
2140                                                 return null;
2141                                         }
2142                                 }
2143
2144                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2145                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2146                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2147                                         type = TypeManager.bool_type;
2148                                         return this;
2149                                 }
2150
2151                                 if (oper == Operator.BitwiseAnd ||
2152                                     oper == Operator.BitwiseOr ||
2153                                     oper == Operator.ExclusiveOr){
2154                                         type = l;
2155                                         return this;
2156                                 }
2157                                 Error_OperatorCannotBeApplied ();
2158                                 return null;
2159                         }
2160                         
2161                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2162                                 return CheckShiftArguments (ec);
2163
2164                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2165                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
2166                                         Error_OperatorCannotBeApplied ();
2167                                         return null;
2168                                 }
2169
2170                                 type = TypeManager.bool_type;
2171                                 return this;
2172                         } 
2173
2174                         //
2175                         // operator & (bool x, bool y)
2176                         // operator | (bool x, bool y)
2177                         // operator ^ (bool x, bool y)
2178                         //
2179                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2180                                 if (oper == Operator.BitwiseAnd ||
2181                                     oper == Operator.BitwiseOr ||
2182                                     oper == Operator.ExclusiveOr){
2183                                         type = l;
2184                                         return this;
2185                                 }
2186                         }
2187                         
2188                         //
2189                         // Pointer comparison
2190                         //
2191                         if (l.IsPointer && r.IsPointer){
2192                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2193                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2194                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2195                                         type = TypeManager.bool_type;
2196                                         return this;
2197                                 }
2198                         }
2199                         
2200                         //
2201                         // We are dealing with numbers
2202                         //
2203                         if (overload_failed){
2204                                 Error_OperatorCannotBeApplied ();
2205                                 return null;
2206                         }
2207
2208                         //
2209                         // This will leave left or right set to null if there is an error
2210                         //
2211                         DoNumericPromotions (ec, l, r);
2212                         if (left == null || right == null){
2213                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2214                                 return null;
2215                         }
2216
2217                         //
2218                         // reload our cached types if required
2219                         //
2220                         l = left.Type;
2221                         r = right.Type;
2222                         
2223                         if (oper == Operator.BitwiseAnd ||
2224                             oper == Operator.BitwiseOr ||
2225                             oper == Operator.ExclusiveOr){
2226                                 if (l == r){
2227                                         if (!((l == TypeManager.int32_type) ||
2228                                               (l == TypeManager.uint32_type) ||
2229                                               (l == TypeManager.int64_type) ||
2230                                               (l == TypeManager.uint64_type)))
2231                                                 type = l;
2232                                 } else {
2233                                         Error_OperatorCannotBeApplied ();
2234                                         return null;
2235                                 }
2236                         }
2237
2238                         if (oper == Operator.Equality ||
2239                             oper == Operator.Inequality ||
2240                             oper == Operator.LessThanOrEqual ||
2241                             oper == Operator.LessThan ||
2242                             oper == Operator.GreaterThanOrEqual ||
2243                             oper == Operator.GreaterThan){
2244                                 type = TypeManager.bool_type;
2245                         }
2246
2247                         return this;
2248                 }
2249
2250                 public override Expression DoResolve (EmitContext ec)
2251                 {
2252                         left = left.Resolve (ec);
2253                         right = right.Resolve (ec);
2254
2255                         if (left == null || right == null)
2256                                 return null;
2257
2258                         if (left.Type == null)
2259                                 throw new Exception (
2260                                         "Resolve returned non null, but did not set the type! (" +
2261                                         left + ") at Line: " + loc.Row);
2262                         if (right.Type == null)
2263                                 throw new Exception (
2264                                         "Resolve returned non null, but did not set the type! (" +
2265                                         right + ") at Line: "+ loc.Row);
2266
2267                         eclass = ExprClass.Value;
2268
2269                         if (left is Constant && right is Constant){
2270                                 Expression e = ConstantFold.BinaryFold (
2271                                         ec, oper, (Constant) left, (Constant) right, loc);
2272                                 if (e != null)
2273                                         return e;
2274                         }
2275
2276                         return ResolveOperator (ec);
2277                 }
2278
2279                 /// <remarks>
2280                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2281                 ///   context of a conditional bool expression.  This function will return
2282                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2283                 ///
2284                 ///   The expression's code is generated, and we will generate a branch to `target'
2285                 ///   if the resulting expression value is equal to isTrue
2286                 /// </remarks>
2287                 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2288                 {
2289                         if (method != null)
2290                                 return false;
2291
2292                         ILGenerator ig = ec.ig;
2293
2294                         //
2295                         // This is more complicated than it looks, but its just to avoid
2296                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2297                         // but on top of that we want for == and != to use a special path
2298                         // if we are comparing against null
2299                         //
2300                         if (oper == Operator.Equality || oper == Operator.Inequality){
2301                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2302                                 
2303                                 if (left is NullLiteral){
2304                                         right.Emit (ec);
2305                                         if (my_on_true)
2306                                                 ig.Emit (OpCodes.Brtrue, target);
2307                                         else
2308                                                 ig.Emit (OpCodes.Brfalse, target);
2309                                         return true;
2310                                 } else if (right is NullLiteral){
2311                                         left.Emit (ec);
2312                                         if (my_on_true)
2313                                                 ig.Emit (OpCodes.Brtrue, target);
2314                                         else
2315                                                 ig.Emit (OpCodes.Brfalse, target);
2316                                         return true;
2317                                 } 
2318                         } else if (!(oper == Operator.LessThan ||
2319                                       oper == Operator.GreaterThan ||
2320                                       oper == Operator.LessThanOrEqual ||
2321                                       oper == Operator.GreaterThanOrEqual))
2322                                 return false;
2323                         
2324
2325                         
2326                         left.Emit (ec);
2327                         right.Emit (ec);
2328
2329                         bool isUnsigned = is_unsigned (left.Type);
2330
2331                         switch (oper){
2332                         case Operator.Equality:
2333                                 if (onTrue)
2334                                         ig.Emit (OpCodes.Beq, target);
2335                                 else
2336                                         ig.Emit (OpCodes.Bne_Un, target);
2337                                 break;
2338
2339                         case Operator.Inequality:
2340                                 if (onTrue)
2341                                         ig.Emit (OpCodes.Bne_Un, target);
2342                                 else
2343                                         ig.Emit (OpCodes.Beq, target);
2344                                 break;
2345
2346                         case Operator.LessThan:
2347                                 if (onTrue)
2348                                         if (isUnsigned)
2349                                                 ig.Emit (OpCodes.Blt_Un, target);
2350                                         else
2351                                                 ig.Emit (OpCodes.Blt, target);
2352                                 else
2353                                         if (isUnsigned)
2354                                                 ig.Emit (OpCodes.Bge_Un, target);
2355                                         else
2356                                                 ig.Emit (OpCodes.Bge, target);
2357                                 break;
2358
2359                         case Operator.GreaterThan:
2360                                 if (onTrue)
2361                                         if (isUnsigned)
2362                                                 ig.Emit (OpCodes.Bgt_Un, target);
2363                                         else
2364                                                 ig.Emit (OpCodes.Bgt, target);
2365                                 else
2366                                         if (isUnsigned)
2367                                                 ig.Emit (OpCodes.Ble_Un, target);
2368                                         else
2369                                                 ig.Emit (OpCodes.Ble, target);
2370                                 break;
2371
2372                         case Operator.LessThanOrEqual:
2373                                 if (onTrue)
2374                                         if (isUnsigned)
2375                                                 ig.Emit (OpCodes.Ble_Un, target);
2376                                         else
2377                                                 ig.Emit (OpCodes.Ble, target);
2378                                 else
2379                                         if (isUnsigned)
2380                                                 ig.Emit (OpCodes.Bgt_Un, target);
2381                                         else
2382                                                 ig.Emit (OpCodes.Bgt, target);
2383                                 break;
2384
2385
2386                         case Operator.GreaterThanOrEqual:
2387                                 if (onTrue)
2388                                         if (isUnsigned)
2389                                                 ig.Emit (OpCodes.Bge_Un, target);
2390                                         else
2391                                                 ig.Emit (OpCodes.Bge, target);
2392                                 else
2393                                         if (isUnsigned)
2394                                                 ig.Emit (OpCodes.Blt_Un, target);
2395                                         else
2396                                                 ig.Emit (OpCodes.Blt, target);
2397                                 break;
2398
2399                         default:
2400                                 return false;
2401                         }
2402                         
2403                         return true;
2404                 }
2405                 
2406                 public override void Emit (EmitContext ec)
2407                 {
2408                         ILGenerator ig = ec.ig;
2409                         Type l = left.Type;
2410                         Type r = right.Type;
2411                         OpCode opcode;
2412
2413                         if (method != null) {
2414
2415                                 // Note that operators are static anyway
2416                                 
2417                                 if (Arguments != null) 
2418                                         Invocation.EmitArguments (ec, method, Arguments);
2419                                 
2420                                 if (method is MethodInfo)
2421                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2422                                 else
2423                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2424
2425                                 if (DelegateOperation)
2426                                         ig.Emit (OpCodes.Castclass, type);
2427                                         
2428                                 return;
2429                         }
2430
2431                         //
2432                         // Handle short-circuit operators differently
2433                         // than the rest
2434                         //
2435                         if (oper == Operator.LogicalAnd){
2436                                 Label load_zero = ig.DefineLabel ();
2437                                 Label end = ig.DefineLabel ();
2438                                 
2439                                 left.Emit (ec);
2440                                 ig.Emit (OpCodes.Brfalse, load_zero);
2441                                 right.Emit (ec);
2442                                 ig.Emit (OpCodes.Br, end);
2443                                 ig.MarkLabel (load_zero);
2444                                 ig.Emit (OpCodes.Ldc_I4_0);
2445                                 ig.MarkLabel (end);
2446                                 return;
2447                         } else if (oper == Operator.LogicalOr){
2448                                 Label load_one = ig.DefineLabel ();
2449                                 Label end = ig.DefineLabel ();
2450                                 
2451                                 left.Emit (ec);
2452                                 ig.Emit (OpCodes.Brtrue, load_one);
2453                                 right.Emit (ec);
2454                                 ig.Emit (OpCodes.Br, end);
2455                                 ig.MarkLabel (load_one);
2456                                 ig.Emit (OpCodes.Ldc_I4_1);
2457                                 ig.MarkLabel (end);
2458                                 return;
2459                         }
2460                         
2461                         left.Emit (ec);
2462                         right.Emit (ec);
2463
2464                         switch (oper){
2465                         case Operator.Multiply:
2466                                 if (ec.CheckState){
2467                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2468                                                 opcode = OpCodes.Mul_Ovf;
2469                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2470                                                 opcode = OpCodes.Mul_Ovf_Un;
2471                                         else
2472                                                 opcode = OpCodes.Mul;
2473                                 } else
2474                                         opcode = OpCodes.Mul;
2475
2476                                 break;
2477
2478                         case Operator.Division:
2479                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2480                                         opcode = OpCodes.Div_Un;
2481                                 else
2482                                         opcode = OpCodes.Div;
2483                                 break;
2484
2485                         case Operator.Modulus:
2486                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2487                                         opcode = OpCodes.Rem_Un;
2488                                 else
2489                                         opcode = OpCodes.Rem;
2490                                 break;
2491
2492                         case Operator.Addition:
2493                                 if (ec.CheckState){
2494                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2495                                                 opcode = OpCodes.Add_Ovf;
2496                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2497                                                 opcode = OpCodes.Add_Ovf_Un;
2498                                         else
2499                                                 opcode = OpCodes.Add;
2500                                 } else
2501                                         opcode = OpCodes.Add;
2502                                 break;
2503
2504                         case Operator.Subtraction:
2505                                 if (ec.CheckState){
2506                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2507                                                 opcode = OpCodes.Sub_Ovf;
2508                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2509                                                 opcode = OpCodes.Sub_Ovf_Un;
2510                                         else
2511                                                 opcode = OpCodes.Sub;
2512                                 } else
2513                                         opcode = OpCodes.Sub;
2514                                 break;
2515
2516                         case Operator.RightShift:
2517                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2518                                         opcode = OpCodes.Shr_Un;
2519                                 else
2520                                         opcode = OpCodes.Shr;
2521                                 break;
2522                                 
2523                         case Operator.LeftShift:
2524                                 opcode = OpCodes.Shl;
2525                                 break;
2526
2527                         case Operator.Equality:
2528                                 opcode = OpCodes.Ceq;
2529                                 break;
2530
2531                         case Operator.Inequality:
2532                                 ec.ig.Emit (OpCodes.Ceq);
2533                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
2534                                 
2535                                 opcode = OpCodes.Ceq;
2536                                 break;
2537
2538                         case Operator.LessThan:
2539                                 opcode = OpCodes.Clt;
2540                                 break;
2541
2542                         case Operator.GreaterThan:
2543                                 opcode = OpCodes.Cgt;
2544                                 break;
2545
2546                         case Operator.LessThanOrEqual:
2547                                 ec.ig.Emit (OpCodes.Cgt);
2548                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
2549                                 
2550                                 opcode = OpCodes.Ceq;
2551                                 break;
2552
2553                         case Operator.GreaterThanOrEqual:
2554                                 ec.ig.Emit (OpCodes.Clt);
2555                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
2556                                 
2557                                 opcode = OpCodes.Sub;
2558                                 break;
2559
2560                         case Operator.BitwiseOr:
2561                                 opcode = OpCodes.Or;
2562                                 break;
2563
2564                         case Operator.BitwiseAnd:
2565                                 opcode = OpCodes.And;
2566                                 break;
2567
2568                         case Operator.ExclusiveOr:
2569                                 opcode = OpCodes.Xor;
2570                                 break;
2571
2572                         default:
2573                                 throw new Exception ("This should not happen: Operator = "
2574                                                      + oper.ToString ());
2575                         }
2576
2577                         ig.Emit (opcode);
2578                 }
2579
2580                 public bool IsBuiltinOperator {
2581                         get {
2582                                 return method == null;
2583                         }
2584                 }
2585         }
2586
2587         public class PointerArithmetic : Expression {
2588                 Expression left, right;
2589                 bool is_add;
2590
2591                 //
2592                 // We assume that `l' is always a pointer
2593                 //
2594                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
2595                                           Location loc)
2596                 {
2597                         type = t;
2598                         eclass = ExprClass.Variable;
2599                         this.loc = loc;
2600                         left = l;
2601                         right = r;
2602                         is_add = is_addition;
2603                 }
2604
2605                 public override Expression DoResolve (EmitContext ec)
2606                 {
2607                         //
2608                         // We are born fully resolved
2609                         //
2610                         return this;
2611                 }
2612
2613                 public override void Emit (EmitContext ec)
2614                 {
2615                         Type op_type = left.Type;
2616                         ILGenerator ig = ec.ig;
2617                         int size = GetTypeSize (op_type.GetElementType ());
2618                         
2619                         if (right.Type.IsPointer){
2620                                 //
2621                                 // handle (pointer - pointer)
2622                                 //
2623                                 left.Emit (ec);
2624                                 right.Emit (ec);
2625                                 ig.Emit (OpCodes.Sub);
2626
2627                                 if (size != 1){
2628                                         if (size == 0)
2629                                                 ig.Emit (OpCodes.Sizeof, op_type);
2630                                         else 
2631                                                 IntLiteral.EmitInt (ig, size);
2632                                         ig.Emit (OpCodes.Div);
2633                                 }
2634                                 ig.Emit (OpCodes.Conv_I8);
2635                         } else {
2636                                 //
2637                                 // handle + and - on (pointer op int)
2638                                 //
2639                                 left.Emit (ec);
2640                                 ig.Emit (OpCodes.Conv_I);
2641                                 right.Emit (ec);
2642                                 if (size != 1){
2643                                         if (size == 0)
2644                                                 ig.Emit (OpCodes.Sizeof, op_type);
2645                                         else 
2646                                                 IntLiteral.EmitInt (ig, size);
2647                                         ig.Emit (OpCodes.Mul);
2648                                 }
2649                                 if (is_add)
2650                                         ig.Emit (OpCodes.Add);
2651                                 else
2652                                         ig.Emit (OpCodes.Sub);
2653                         }
2654                 }
2655         }
2656         
2657         /// <summary>
2658         ///   Implements the ternary conditional operator (?:)
2659         /// </summary>
2660         public class Conditional : Expression {
2661                 Expression expr, trueExpr, falseExpr;
2662                 
2663                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2664                 {
2665                         this.expr = expr;
2666                         this.trueExpr = trueExpr;
2667                         this.falseExpr = falseExpr;
2668                         this.loc = l;
2669                 }
2670
2671                 public Expression Expr {
2672                         get {
2673                                 return expr;
2674                         }
2675                 }
2676
2677                 public Expression TrueExpr {
2678                         get {
2679                                 return trueExpr;
2680                         }
2681                 }
2682
2683                 public Expression FalseExpr {
2684                         get {
2685                                 return falseExpr;
2686                         }
2687                 }
2688
2689                 public override Expression DoResolve (EmitContext ec)
2690                 {
2691                         expr = expr.Resolve (ec);
2692
2693                         if (expr == null)
2694                                 return null;
2695                         
2696                         if (expr.Type != TypeManager.bool_type)
2697                                 expr = Expression.ConvertImplicitRequired (
2698                                         ec, expr, TypeManager.bool_type, loc);
2699                         
2700                         trueExpr = trueExpr.Resolve (ec);
2701                         falseExpr = falseExpr.Resolve (ec);
2702
2703                         if (trueExpr == null || falseExpr == null)
2704                                 return null;
2705
2706                         eclass = ExprClass.Value;
2707                         if (trueExpr.Type == falseExpr.Type)
2708                                 type = trueExpr.Type;
2709                         else {
2710                                 Expression conv;
2711                                 Type true_type = trueExpr.Type;
2712                                 Type false_type = falseExpr.Type;
2713
2714                                 if (trueExpr is NullLiteral){
2715                                         type = false_type;
2716                                         return this;
2717                                 } else if (falseExpr is NullLiteral){
2718                                         type = true_type;
2719                                         return this;
2720                                 }
2721                                 
2722                                 //
2723                                 // First, if an implicit conversion exists from trueExpr
2724                                 // to falseExpr, then the result type is of type falseExpr.Type
2725                                 //
2726                                 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
2727                                 if (conv != null){
2728                                         //
2729                                         // Check if both can convert implicitl to each other's type
2730                                         //
2731                                         if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
2732                                                 Error (172,
2733                                                        "Can not compute type of conditional expression " +
2734                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
2735                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
2736                                                        "' convert implicitly to each other");
2737                                                 return null;
2738                                         }
2739                                         type = false_type;
2740                                         trueExpr = conv;
2741                                 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
2742                                         type = true_type;
2743                                         falseExpr = conv;
2744                                 } else {
2745                                         Error (173, "The type of the conditional expression can " +
2746                                                "not be computed because there is no implicit conversion" +
2747                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2748                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2749                                         return null;
2750                                 }
2751                         }
2752
2753                         if (expr is BoolConstant){
2754                                 BoolConstant bc = (BoolConstant) expr;
2755
2756                                 if (bc.Value)
2757                                         return trueExpr;
2758                                 else
2759                                         return falseExpr;
2760                         }
2761
2762                         return this;
2763                 }
2764
2765                 public override void Emit (EmitContext ec)
2766                 {
2767                         ILGenerator ig = ec.ig;
2768                         Label false_target = ig.DefineLabel ();
2769                         Label end_target = ig.DefineLabel ();
2770
2771                         Statement.EmitBoolExpression (ec, expr, false_target, false);
2772                         trueExpr.Emit (ec);
2773                         ig.Emit (OpCodes.Br, end_target);
2774                         ig.MarkLabel (false_target);
2775                         falseExpr.Emit (ec);
2776                         ig.MarkLabel (end_target);
2777                 }
2778
2779         }
2780
2781         /// <summary>
2782         ///   Local variables
2783         /// </summary>
2784         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
2785                 public readonly string Name;
2786                 public readonly Block Block;
2787                 VariableInfo variable_info;
2788                 bool is_readonly;
2789                 
2790                 public LocalVariableReference (Block block, string name, Location l)
2791                 {
2792                         Block = block;
2793                         Name = name;
2794                         loc = l;
2795                         eclass = ExprClass.Variable;
2796                 }
2797
2798                 // Setting `is_readonly' to false will allow you to create a writable
2799                 // reference to a read-only variable.  This is used by foreach and using.
2800                 public LocalVariableReference (Block block, string name, Location l,
2801                                                VariableInfo variable_info, bool is_readonly)
2802                         : this (block, name, l)
2803                 {
2804                         this.variable_info = variable_info;
2805                         this.is_readonly = is_readonly;
2806                 }
2807
2808                 public VariableInfo VariableInfo {
2809                         get {
2810                                 if (variable_info == null) {
2811                                         variable_info = Block.GetVariableInfo (Name);
2812                                         is_readonly = variable_info.ReadOnly;
2813                                 }
2814                                 return variable_info;
2815                         }
2816                 }
2817
2818                 public bool IsAssigned (EmitContext ec, Location loc)
2819                 {
2820                         return VariableInfo.IsAssigned (ec, loc);
2821                 }
2822
2823                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
2824                 {
2825                         return VariableInfo.IsFieldAssigned (ec, name, loc);
2826                 }
2827
2828                 public void SetAssigned (EmitContext ec)
2829                 {
2830                         VariableInfo.SetAssigned (ec);
2831                 }
2832
2833                 public void SetFieldAssigned (EmitContext ec, string name)
2834                 {
2835                         VariableInfo.SetFieldAssigned (ec, name);
2836                 }
2837
2838                 public bool IsReadOnly {
2839                         get {
2840                                 if (variable_info == null) {
2841                                         variable_info = Block.GetVariableInfo (Name);
2842                                         is_readonly = variable_info.ReadOnly;
2843                                 }
2844                                 return is_readonly;
2845                         }
2846                 }
2847                 
2848                 public override Expression DoResolve (EmitContext ec)
2849                 {
2850                         VariableInfo vi = VariableInfo;
2851
2852                         if (Block.IsConstant (Name)) {
2853                                 Expression e = Block.GetConstantExpression (Name);
2854
2855                                 vi.Used = true;
2856                                 return e;
2857                         }
2858
2859                         if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
2860                                 return null;
2861
2862                         type = vi.VariableType;
2863                         return this;
2864                 }
2865
2866                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2867                 {
2868                         VariableInfo vi = VariableInfo;
2869
2870                         if (ec.DoFlowAnalysis)
2871                                 ec.SetVariableAssigned (vi);
2872
2873                         Expression e = DoResolve (ec);
2874
2875                         if (e == null)
2876                                 return null;
2877
2878                         if (is_readonly){
2879                                 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
2880                                 return null;
2881                         }
2882                         
2883                         return this;
2884                 }
2885
2886                 public override void Emit (EmitContext ec)
2887                 {
2888                         VariableInfo vi = VariableInfo;
2889                         ILGenerator ig = ec.ig;
2890
2891                         ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
2892                         vi.Used = true;
2893                 }
2894                 
2895                 public void EmitAssign (EmitContext ec, Expression source)
2896                 {
2897                         ILGenerator ig = ec.ig;
2898                         VariableInfo vi = VariableInfo;
2899
2900                         vi.Assigned = true;
2901
2902                         source.Emit (ec);
2903                         
2904                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2905                 }
2906                 
2907                 public void AddressOf (EmitContext ec, AddressOp mode)
2908                 {
2909                         VariableInfo vi = VariableInfo;
2910
2911                         ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
2912                 }
2913         }
2914
2915         /// <summary>
2916         ///   This represents a reference to a parameter in the intermediate
2917         ///   representation.
2918         /// </summary>
2919         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
2920                 Parameters pars;
2921                 String name;
2922                 int idx;
2923                 public Parameter.Modifier mod;
2924                 public bool is_ref, is_out;
2925                 
2926                 public ParameterReference (Parameters pars, int idx, string name, Location loc)
2927                 {
2928                         this.pars = pars;
2929                         this.idx  = idx;
2930                         this.name = name;
2931                         this.loc = loc;
2932                         eclass = ExprClass.Variable;
2933                 }
2934
2935                 public bool IsAssigned (EmitContext ec, Location loc)
2936                 {
2937                         if (!is_out || !ec.DoFlowAnalysis)
2938                                 return true;
2939
2940                         if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
2941                                 Report.Error (165, loc,
2942                                               "Use of unassigned local variable `" + name + "'");
2943                                 return false;
2944                         }
2945
2946                         return true;
2947                 }
2948
2949                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
2950                 {
2951                         if (!is_out || !ec.DoFlowAnalysis)
2952                                 return true;
2953
2954                         if (ec.CurrentBranching.IsParameterAssigned (idx))
2955                                 return true;
2956
2957                         if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
2958                                 Report.Error (170, loc,
2959                                               "Use of possibly unassigned field `" + field_name + "'");
2960                                 return false;
2961                         }
2962
2963                         return true;
2964                 }
2965
2966                 public void SetAssigned (EmitContext ec)
2967                 {
2968                         if (is_out && ec.DoFlowAnalysis)
2969                                 ec.CurrentBranching.SetParameterAssigned (idx);
2970                 }
2971
2972                 public void SetFieldAssigned (EmitContext ec, string field_name)
2973                 {
2974                         if (is_out && ec.DoFlowAnalysis)
2975                                 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
2976                 }
2977
2978                 //
2979                 // Notice that for ref/out parameters, the type exposed is not the
2980                 // same type exposed externally.
2981                 //
2982                 // for "ref int a":
2983                 //   externally we expose "int&"
2984                 //   here we expose       "int".
2985                 //
2986                 // We record this in "is_ref".  This means that the type system can treat
2987                 // the type as it is expected, but when we generate the code, we generate
2988                 // the alternate kind of code.
2989                 //
2990                 public override Expression DoResolve (EmitContext ec)
2991                 {
2992                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
2993                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
2994                         is_out = (mod & Parameter.Modifier.OUT) != 0;
2995                         eclass = ExprClass.Variable;
2996
2997                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
2998                                 return null;
2999
3000                         return this;
3001                 }
3002
3003                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3004                 {
3005                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3006                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3007                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3008                         eclass = ExprClass.Variable;
3009
3010                         if (is_out && ec.DoFlowAnalysis)
3011                                 ec.SetParameterAssigned (idx);
3012
3013                         return this;
3014                 }
3015
3016                 static void EmitLdArg (ILGenerator ig, int x)
3017                 {
3018                         if (x <= 255){
3019                                 switch (x){
3020                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3021                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3022                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3023                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3024                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3025                                 }
3026                         } else
3027                                 ig.Emit (OpCodes.Ldarg, x);
3028                 }
3029                 
3030                 //
3031                 // This method is used by parameters that are references, that are
3032                 // being passed as references:  we only want to pass the pointer (that
3033                 // is already stored in the parameter, not the address of the pointer,
3034                 // and not the value of the variable).
3035                 //
3036                 public void EmitLoad (EmitContext ec)
3037                 {
3038                         ILGenerator ig = ec.ig;
3039                         int arg_idx = idx;
3040
3041                         if (!ec.IsStatic)
3042                                 arg_idx++;
3043
3044                         EmitLdArg (ig, arg_idx);
3045                 }
3046                 
3047                 public override void Emit (EmitContext ec)
3048                 {
3049                         ILGenerator ig = ec.ig;
3050                         int arg_idx = idx;
3051
3052                         if (!ec.IsStatic)
3053                                 arg_idx++;
3054
3055                         EmitLdArg (ig, arg_idx);
3056
3057                         if (!is_ref)
3058                                 return;
3059
3060                         //
3061                         // If we are a reference, we loaded on the stack a pointer
3062                         // Now lets load the real value
3063                         //
3064                         LoadFromPtr (ig, type);
3065                 }
3066
3067                 public void EmitAssign (EmitContext ec, Expression source)
3068                 {
3069                         ILGenerator ig = ec.ig;
3070                         int arg_idx = idx;
3071
3072                         if (!ec.IsStatic)
3073                                 arg_idx++;
3074
3075                         if (is_ref)
3076                                 EmitLdArg (ig, arg_idx);
3077                         
3078                         source.Emit (ec);
3079
3080                         if (is_ref)
3081                                 StoreFromPtr (ig, type);
3082                         else {
3083                                 if (arg_idx <= 255)
3084                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3085                                 else
3086                                         ig.Emit (OpCodes.Starg, arg_idx);
3087                         }
3088                 }
3089
3090                 public void AddressOf (EmitContext ec, AddressOp mode)
3091                 {
3092                         int arg_idx = idx;
3093
3094                         if (!ec.IsStatic)
3095                                 arg_idx++;
3096
3097                         if (is_ref){
3098                                 if (arg_idx <= 255)
3099                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3100                                 else
3101                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3102                         } else {
3103                                 if (arg_idx <= 255)
3104                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3105                                 else
3106                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3107                         }
3108                 }
3109         }
3110         
3111         /// <summary>
3112         ///   Used for arguments to New(), Invocation()
3113         /// </summary>
3114         public class Argument {
3115                 public enum AType : byte {
3116                         Expression,
3117                         Ref,
3118                         Out
3119                 };
3120
3121                 public readonly AType ArgType;
3122                 public Expression Expr;
3123                 
3124                 public Argument (Expression expr, AType type)
3125                 {
3126                         this.Expr = expr;
3127                         this.ArgType = type;
3128                 }
3129
3130                 public Type Type {
3131                         get {
3132                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3133                                         return TypeManager.LookupType (Expr.Type.ToString () + "&");
3134                                 else
3135                                         return Expr.Type;
3136                         }
3137                 }
3138
3139                 public Parameter.Modifier GetParameterModifier ()
3140                 {
3141                         switch (ArgType) {
3142                         case AType.Out:
3143                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
3144
3145                         case AType.Ref:
3146                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
3147
3148                         default:
3149                                 return Parameter.Modifier.NONE;
3150                         }
3151                 }
3152
3153                 public static string FullDesc (Argument a)
3154                 {
3155                         return (a.ArgType == AType.Ref ? "ref " :
3156                                 (a.ArgType == AType.Out ? "out " : "")) +
3157                                 TypeManager.CSharpName (a.Expr.Type);
3158                 }
3159
3160                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
3161                 {
3162                         // FIXME: csc doesn't report any error if you try to use `ref' or
3163                         //        `out' in a delegate creation expression.
3164                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3165                         if (Expr == null)
3166                                 return false;
3167
3168                         return true;
3169                 }
3170                 
3171                 public bool Resolve (EmitContext ec, Location loc)
3172                 {
3173                         if (ArgType == AType.Ref) {
3174                                 Expr = Expr.Resolve (ec);
3175                                 if (Expr == null)
3176                                         return false;
3177
3178                                 Expr = Expr.ResolveLValue (ec, Expr);
3179                         } else if (ArgType == AType.Out)
3180                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
3181                         else
3182                                 Expr = Expr.Resolve (ec);
3183
3184                         if (Expr == null)
3185                                 return false;
3186
3187                         if (ArgType == AType.Expression)
3188                                 return true;
3189
3190                         if (Expr.eclass != ExprClass.Variable){
3191                                 //
3192                                 // We just probe to match the CSC output
3193                                 //
3194                                 if (Expr.eclass == ExprClass.PropertyAccess ||
3195                                     Expr.eclass == ExprClass.IndexerAccess){
3196                                         Report.Error (
3197                                                 206, loc,
3198                                                 "A property or indexer can not be passed as an out or ref " +
3199                                                 "parameter");
3200                                 } else {
3201                                         Report.Error (
3202                                                 1510, loc,
3203                                                 "An lvalue is required as an argument to out or ref");
3204                                 }
3205                                 return false;
3206                         }
3207                                 
3208                         return true;
3209                 }
3210
3211                 public void Emit (EmitContext ec)
3212                 {
3213                         //
3214                         // Ref and Out parameters need to have their addresses taken.
3215                         //
3216                         // ParameterReferences might already be references, so we want
3217                         // to pass just the value
3218                         //
3219                         if (ArgType == AType.Ref || ArgType == AType.Out){
3220                                 AddressOp mode = AddressOp.Store;
3221
3222                                 if (ArgType == AType.Ref)
3223                                         mode |= AddressOp.Load;
3224                                 
3225                                 if (Expr is ParameterReference){
3226                                         ParameterReference pr = (ParameterReference) Expr;
3227
3228                                         if (pr.is_ref)
3229                                                 pr.EmitLoad (ec);
3230                                         else {
3231                                                 
3232                                                 pr.AddressOf (ec, mode);
3233                                         }
3234                                 } else
3235                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
3236                         } else
3237                                 Expr.Emit (ec);
3238                 }
3239         }
3240
3241         /// <summary>
3242         ///   Invocation of methods or delegates.
3243         /// </summary>
3244         public class Invocation : ExpressionStatement {
3245                 public readonly ArrayList Arguments;
3246
3247                 Expression expr;
3248                 MethodBase method = null;
3249                 bool is_base;
3250                 
3251                 static Hashtable method_parameter_cache;
3252
3253                 static Invocation ()
3254                 {
3255                         method_parameter_cache = new PtrHashtable ();
3256                 }
3257                         
3258                 //
3259                 // arguments is an ArrayList, but we do not want to typecast,
3260                 // as it might be null.
3261                 //
3262                 // FIXME: only allow expr to be a method invocation or a
3263                 // delegate invocation (7.5.5)
3264                 //
3265                 public Invocation (Expression expr, ArrayList arguments, Location l)
3266                 {
3267                         this.expr = expr;
3268                         Arguments = arguments;
3269                         loc = l;
3270                 }
3271
3272                 public Expression Expr {
3273                         get {
3274                                 return expr;
3275                         }
3276                 }
3277
3278                 /// <summary>
3279                 ///   Returns the Parameters (a ParameterData interface) for the
3280                 ///   Method `mb'
3281                 /// </summary>
3282                 public static ParameterData GetParameterData (MethodBase mb)
3283                 {
3284                         object pd = method_parameter_cache [mb];
3285                         object ip;
3286                         
3287                         if (pd != null)
3288                                 return (ParameterData) pd;
3289
3290                         
3291                         ip = TypeManager.LookupParametersByBuilder (mb);
3292                         if (ip != null){
3293                                 method_parameter_cache [mb] = ip;
3294
3295                                 return (ParameterData) ip;
3296                         } else {
3297                                 ParameterInfo [] pi = mb.GetParameters ();
3298                                 ReflectionParameters rp = new ReflectionParameters (pi);
3299                                 method_parameter_cache [mb] = rp;
3300
3301                                 return (ParameterData) rp;
3302                         }
3303                 }
3304
3305                 /// <summary>
3306                 ///  Determines "better conversion" as specified in 7.4.2.3
3307                 ///  Returns : 1 if a->p is better
3308                 ///            0 if a->q or neither is better 
3309                 /// </summary>
3310                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
3311                 {
3312                         Type argument_type = a.Type;
3313                         Expression argument_expr = a.Expr;
3314
3315                         if (argument_type == null)
3316                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3317
3318                         //
3319                         // This is a special case since csc behaves this way. I can't find
3320                         // it anywhere in the spec but oh well ...
3321                         //
3322                         if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
3323                                 return 1;
3324                         else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
3325                                 return 0;
3326                         
3327                         if (p == q)
3328                                 return 0;
3329                         
3330                         if (argument_type == p)
3331                                 return 1;
3332
3333                         if (argument_type == q)
3334                                 return 0;
3335
3336                         //
3337                         // Now probe whether an implicit constant expression conversion
3338                         // can be used.
3339                         //
3340                         // An implicit constant expression conversion permits the following
3341                         // conversions:
3342                         //
3343                         //    * A constant-expression of type `int' can be converted to type
3344                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
3345                         //      of the expression is withing the range of the destination type.
3346                         //
3347                         //    * A constant-expression of type long can be converted to type
3348                         //      ulong, provided the value of the constant expression is not negative
3349                         //
3350                         // FIXME: Note that this assumes that constant folding has
3351                         // taken place.  We dont do constant folding yet.
3352                         //
3353
3354                         if (argument_expr is IntConstant){
3355                                 IntConstant ei = (IntConstant) argument_expr;
3356                                 int value = ei.Value;
3357                                 
3358                                 if (p == TypeManager.sbyte_type){
3359                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
3360                                                 return 1;
3361                                 } else if (p == TypeManager.byte_type){
3362                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3363                                                 return 1;
3364                                 } else if (p == TypeManager.short_type){
3365                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
3366                                                 return 1;
3367                                 } else if (p == TypeManager.ushort_type){
3368                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3369                                                 return 1;
3370                                 } else if (p == TypeManager.uint32_type){
3371                                         //
3372                                         // we can optimize this case: a positive int32
3373                                         // always fits on a uint32
3374                                         //
3375                                         if (value >= 0)
3376                                                 return 1;
3377                                 } else if (p == TypeManager.uint64_type){
3378                                         //
3379                                         // we can optimize this case: a positive int32
3380                                         // always fits on a uint64
3381                                         //
3382                                         if (value >= 0)
3383                                                 return 1;
3384                                 }
3385                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
3386                                 LongConstant lc = (LongConstant) argument_expr;
3387                                 
3388                                 if (p == TypeManager.uint64_type){
3389                                         if (lc.Value > 0)
3390                                                 return 1;
3391                                 }
3392                         }
3393
3394                         if (q == null) {
3395                                 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
3396                                 
3397                                 if (tmp != null)
3398                                         return 1;
3399                                 else
3400                                         return 0;
3401                         }
3402
3403                         Expression p_tmp = new EmptyExpression (p);
3404                         Expression q_tmp = new EmptyExpression (q);
3405                         
3406                         if (StandardConversionExists (p_tmp, q) == true &&
3407                             StandardConversionExists (q_tmp, p) == false)
3408                                 return 1;
3409
3410                         if (p == TypeManager.sbyte_type)
3411                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3412                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3413                                         return 1;
3414
3415                         if (p == TypeManager.short_type)
3416                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3417                                     q == TypeManager.uint64_type)
3418                                         return 1;
3419
3420                         if (p == TypeManager.int32_type)
3421                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3422                                         return 1;
3423
3424                         if (p == TypeManager.int64_type)
3425                                 if (q == TypeManager.uint64_type)
3426                                         return 1;
3427
3428                         return 0;
3429                 }
3430                 
3431                 /// <summary>
3432                 ///  Determines "Better function"
3433                 /// </summary>
3434                 /// <remarks>
3435                 ///    and returns an integer indicating :
3436                 ///    0 if candidate ain't better
3437                 ///    1 if candidate is better than the current best match
3438                 /// </remarks>
3439                 static int BetterFunction (EmitContext ec, ArrayList args,
3440                                            MethodBase candidate, MethodBase best,
3441                                            bool expanded_form, Location loc)
3442                 {
3443                         ParameterData candidate_pd = GetParameterData (candidate);
3444                         ParameterData best_pd;
3445                         int argument_count;
3446                 
3447                         if (args == null)
3448                                 argument_count = 0;
3449                         else
3450                                 argument_count = args.Count;
3451
3452                         int cand_count = candidate_pd.Count;
3453
3454                         if (cand_count == 0 && argument_count == 0)
3455                                 return 1;
3456
3457                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3458                                 if (cand_count != argument_count)
3459                                         return 0;
3460                         
3461                         if (best == null) {
3462                                 int x = 0;
3463
3464                                 if (argument_count == 0 && cand_count == 1 &&
3465                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
3466                                         return 1;
3467                                 
3468                                 for (int j = argument_count; j > 0;) {
3469                                         j--;
3470
3471                                         Argument a = (Argument) args [j];
3472                                         Type t = candidate_pd.ParameterType (j);
3473
3474                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3475                                                 if (expanded_form)
3476                                                         t = t.GetElementType ();
3477
3478                                         x = BetterConversion (ec, a, t, null, loc);
3479                                         
3480                                         if (x <= 0)
3481                                                 break;
3482                                 }
3483
3484                                 if (x > 0)
3485                                         return 1;
3486                                 else
3487                                         return 0;
3488                         }
3489
3490                         best_pd = GetParameterData (best);
3491
3492                         int rating1 = 0, rating2 = 0;
3493                         
3494                         for (int j = 0; j < argument_count; ++j) {
3495                                 int x, y;
3496                                 
3497                                 Argument a = (Argument) args [j];
3498
3499                                 Type ct = candidate_pd.ParameterType (j);
3500                                 Type bt = best_pd.ParameterType (j);
3501
3502                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3503                                         if (expanded_form)
3504                                                 ct = ct.GetElementType ();
3505
3506                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3507                                         if (expanded_form)
3508                                                 bt = bt.GetElementType ();
3509                                 
3510                                 x = BetterConversion (ec, a, ct, bt, loc);
3511                                 y = BetterConversion (ec, a, bt, ct, loc);
3512
3513                                 if (x < y)
3514                                         return 0;
3515                                 
3516                                 rating1 += x;
3517                                 rating2 += y;
3518                         }
3519
3520                         if (rating1 > rating2)
3521                                 return 1;
3522                         else
3523                                 return 0;
3524                 }
3525
3526                 public static string FullMethodDesc (MethodBase mb)
3527                 {
3528                         string ret_type = "";
3529
3530                         if (mb is MethodInfo)
3531                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
3532                         
3533                         StringBuilder sb = new StringBuilder (ret_type + " " + mb.Name);
3534                         ParameterData pd = GetParameterData (mb);
3535
3536                         int count = pd.Count;
3537                         sb.Append (" (");
3538                         
3539                         for (int i = count; i > 0; ) {
3540                                 i--;
3541
3542                                 sb.Append (pd.ParameterDesc (count - i - 1));
3543                                 if (i != 0)
3544                                         sb.Append (", ");
3545                         }
3546                         
3547                         sb.Append (")");
3548                         return sb.ToString ();
3549                 }
3550
3551                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3552                 {
3553                         MemberInfo [] miset;
3554                         MethodGroupExpr union;
3555
3556                         if (mg1 == null){
3557                                 if (mg2 == null)
3558                                         return null;
3559                                 return (MethodGroupExpr) mg2;
3560                         } else {
3561                                 if (mg2 == null)
3562                                         return (MethodGroupExpr) mg1;
3563                         }
3564                         
3565                         MethodGroupExpr left_set = null, right_set = null;
3566                         int length1 = 0, length2 = 0;
3567                         
3568                         left_set = (MethodGroupExpr) mg1;
3569                         length1 = left_set.Methods.Length;
3570                         
3571                         right_set = (MethodGroupExpr) mg2;
3572                         length2 = right_set.Methods.Length;
3573                         
3574                         ArrayList common = new ArrayList ();
3575
3576                         foreach (MethodBase l in left_set.Methods){
3577                                 foreach (MethodBase r in right_set.Methods){
3578                                         if (l != r)
3579                                                 continue;
3580                                         common.Add (r);
3581                                         break;
3582                                 }
3583                         }
3584                         
3585                         miset = new MemberInfo [length1 + length2 - common.Count];
3586                         left_set.Methods.CopyTo (miset, 0);
3587                         
3588                         int k = length1;
3589
3590                         foreach (MemberInfo mi in right_set.Methods){
3591                                 if (!common.Contains (mi))
3592                                         miset [k++] = mi;
3593                         }
3594                         
3595                         union = new MethodGroupExpr (miset, loc);
3596                         
3597                         return union;
3598                 }
3599
3600                 /// <summary>
3601                 ///  Determines is the candidate method, if a params method, is applicable
3602                 ///  in its expanded form to the given set of arguments
3603                 /// </summary>
3604                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3605                 {
3606                         int arg_count;
3607                         
3608                         if (arguments == null)
3609                                 arg_count = 0;
3610                         else
3611                                 arg_count = arguments.Count;
3612                         
3613                         ParameterData pd = GetParameterData (candidate);
3614                         
3615                         int pd_count = pd.Count;
3616
3617                         if (pd_count == 0)
3618                                 return false;
3619                         
3620                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
3621                                 return false;
3622                         
3623                         if (pd_count - 1 > arg_count)
3624                                 return false;
3625                         
3626                         if (pd_count == 1 && arg_count == 0)
3627                                 return true;
3628
3629                         //
3630                         // If we have come this far, the case which remains is when the number of parameters
3631                         // is less than or equal to the argument count.
3632                         //
3633                         for (int i = 0; i < pd_count - 1; ++i) {
3634
3635                                 Argument a = (Argument) arguments [i];
3636
3637                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
3638                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3639                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3640                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3641
3642                                 if (a_mod == p_mod) {
3643
3644                                         if (a_mod == Parameter.Modifier.NONE)
3645                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3646                                                         return false;
3647                                                                                 
3648                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3649                                                 Type pt = pd.ParameterType (i);
3650
3651                                                 if (!pt.IsByRef)
3652                                                         pt = TypeManager.LookupType (pt.FullName + "&");
3653                                                 
3654                                                 if (pt != a.Type)
3655                                                         return false;
3656                                         }
3657                                 } else
3658                                         return false;
3659                                 
3660                         }
3661
3662                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
3663
3664                         for (int i = pd_count - 1; i < arg_count; i++) {
3665                                 Argument a = (Argument) arguments [i];
3666                                 
3667                                 if (!StandardConversionExists (a.Expr, element_type))
3668                                         return false;
3669                         }
3670                         
3671                         return true;
3672                 }
3673
3674                 /// <summary>
3675                 ///  Determines if the candidate method is applicable (section 14.4.2.1)
3676                 ///  to the given set of arguments
3677                 /// </summary>
3678                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3679                 {
3680                         int arg_count;
3681
3682                         if (arguments == null)
3683                                 arg_count = 0;
3684                         else
3685                                 arg_count = arguments.Count;
3686
3687                         ParameterData pd = GetParameterData (candidate);
3688
3689                         int pd_count = pd.Count;
3690
3691                         if (arg_count != pd.Count)
3692                                 return false;
3693                         
3694                         for (int i = arg_count; i > 0; ) {
3695                                 i--;
3696
3697                                 Argument a = (Argument) arguments [i];
3698
3699                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
3700                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3701                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3702                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3703
3704                                 if (a_mod == p_mod ||
3705                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3706                                         if (a_mod == Parameter.Modifier.NONE)
3707                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3708                                                         return false;
3709                                         
3710                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3711                                                 Type pt = pd.ParameterType (i);
3712
3713                                                 if (!pt.IsByRef)
3714                                                         pt = TypeManager.LookupType (pt.FullName + "&");
3715
3716                                                 if (pt != a.Type)
3717                                                         return false;
3718                                         }
3719                                 } else
3720                                         return false;
3721                         }
3722
3723                         return true;
3724                 }
3725                 
3726                 
3727
3728                 /// <summary>
3729                 ///   Find the Applicable Function Members (7.4.2.1)
3730                 ///
3731                 ///   me: Method Group expression with the members to select.
3732                 ///       it might contain constructors or methods (or anything
3733                 ///       that maps to a method).
3734                 ///
3735                 ///   Arguments: ArrayList containing resolved Argument objects.
3736                 ///
3737                 ///   loc: The location if we want an error to be reported, or a Null
3738                 ///        location for "probing" purposes.
3739                 ///
3740                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3741                 ///            that is the best match of me on Arguments.
3742                 ///
3743                 /// </summary>
3744                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3745                                                           ArrayList Arguments, Location loc)
3746                 {
3747                         ArrayList afm = new ArrayList ();
3748                         MethodBase method = null;
3749                         Type current_type = null;
3750                         int argument_count;
3751                         ArrayList candidates = new ArrayList ();
3752                         
3753
3754                         foreach (MethodBase candidate in me.Methods){
3755                                 int x;
3756
3757                                 // If we're going one level higher in the class hierarchy, abort if
3758                                 // we already found an applicable method.
3759                                 if (candidate.DeclaringType != current_type) {
3760                                         current_type = candidate.DeclaringType;
3761                                         if (method != null)
3762                                                 break;
3763                                 }
3764
3765                                 // Check if candidate is applicable (section 14.4.2.1)
3766                                 if (!IsApplicable (ec, Arguments, candidate))
3767                                         continue;
3768
3769                                 candidates.Add (candidate);
3770                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
3771                                 
3772                                 if (x == 0)
3773                                         continue;
3774
3775                                 method = candidate;
3776                         }
3777
3778                         if (Arguments == null)
3779                                 argument_count = 0;
3780                         else
3781                                 argument_count = Arguments.Count;
3782                         
3783                         //
3784                         // Now we see if we can find params functions, applicable in their expanded form
3785                         // since if they were applicable in their normal form, they would have been selected
3786                         // above anyways
3787                         //
3788                         bool chose_params_expanded = false;
3789                         
3790                         if (method == null) {
3791                                 candidates = new ArrayList ();
3792                                 foreach (MethodBase candidate in me.Methods){
3793                                         if (!IsParamsMethodApplicable (ec, Arguments, candidate))
3794                                                 continue;
3795
3796                                         candidates.Add (candidate);
3797
3798                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
3799                                         if (x == 0)
3800                                                 continue;
3801
3802                                         method = candidate; 
3803                                         chose_params_expanded = true;
3804                                 }
3805                         }
3806
3807                         if (method == null) {
3808                                 //
3809                                 // Okay so we have failed to find anything so we
3810                                 // return by providing info about the closest match
3811                                 //
3812                                 for (int i = 0; i < me.Methods.Length; ++i) {
3813
3814                                         MethodBase c = (MethodBase) me.Methods [i];
3815                                         ParameterData pd = GetParameterData (c);
3816
3817                                         if (pd.Count != argument_count)
3818                                                 continue;
3819
3820                                         VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
3821                                                                null, loc);
3822                                 }
3823                                 
3824                                 return null;
3825                         }
3826
3827                         //
3828                         // Now check that there are no ambiguities i.e the selected method
3829                         // should be better than all the others
3830                         //
3831
3832                         foreach (MethodBase candidate in candidates){
3833                                 if (candidate == method)
3834                                         continue;
3835
3836                                 //
3837                                 // If a normal method is applicable in the sense that it has the same
3838                                 // number of arguments, then the expanded params method is never applicable
3839                                 // so we debar the params method.
3840                                 //
3841                                 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
3842                                     IsApplicable (ec, Arguments, method))
3843                                         continue;
3844                                         
3845                                 int x = BetterFunction (ec, Arguments, method, candidate,
3846                                                         chose_params_expanded, loc);
3847
3848                                 if (x != 1) {
3849                                         Report.Error (
3850                                                 121, loc,
3851                                                 "Ambiguous call when selecting function due to implicit casts");
3852                                         return null;
3853                                 }
3854                         }
3855
3856                         //
3857                         // And now check if the arguments are all compatible, perform conversions
3858                         // if necessary etc. and return if everything is all right
3859                         //
3860
3861                         if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
3862                                                    chose_params_expanded, null, loc))
3863                                 return method;
3864                         else
3865                                 return null;
3866                 }
3867
3868                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
3869                                                           int argument_count,
3870                                                           MethodBase method, 
3871                                                           bool chose_params_expanded,
3872                                                           Type delegate_type,
3873                                                           Location loc)
3874                 {
3875                         ParameterData pd = GetParameterData (method);
3876                         int pd_count = pd.Count;
3877                         
3878                         for (int j = 0; j < argument_count; j++) {
3879                                 Argument a = (Argument) Arguments [j];
3880                                 Expression a_expr = a.Expr;
3881                                 Type parameter_type = pd.ParameterType (j);
3882
3883                                 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
3884                                     chose_params_expanded)
3885                                         parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
3886
3887                                 if (a.Type != parameter_type){
3888                                         Expression conv;
3889                                         
3890                                         conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
3891
3892                                         if (conv == null) {
3893                                                 if (!Location.IsNull (loc)) {
3894                                                         if (delegate_type == null) 
3895                                                                 Report.Error (1502, loc,
3896                                                                        "The best overloaded match for method '" +
3897                                                                        FullMethodDesc (method) +
3898                                                                        "' has some invalid arguments");
3899                                                         else
3900                                                                 Report.Error (1594, loc,
3901                                                                               "Delegate '" + delegate_type.ToString () +
3902                                                                               "' has some invalid arguments.");
3903                                                         Report.Error (1503, loc,
3904                                                          "Argument " + (j+1) +
3905                                                          ": Cannot convert from '" + Argument.FullDesc (a) 
3906                                                          + "' to '" + pd.ParameterDesc (j) + "'");
3907                                                 }
3908                                                 
3909                                                 return false;
3910                                         }
3911                                         
3912                                         //
3913                                         // Update the argument with the implicit conversion
3914                                         //
3915                                         if (a_expr != conv)
3916                                                 a.Expr = conv;
3917                                 }
3918
3919                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
3920                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3921                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
3922                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
3923
3924                                 
3925                                 if (a_mod != p_mod &&
3926                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
3927                                         if (!Location.IsNull (loc)) {
3928                                                 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
3929                                                 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
3930                                                 Console.WriteLine ("PT:  " + parameter_type.IsByRef);
3931                                                 Report.Error (1502, loc,
3932                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
3933                                                        "' has some invalid arguments");
3934                                                 Report.Error (1503, loc,
3935                                                        "Argument " + (j+1) +
3936                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
3937                                                        + "' to '" + pd.ParameterDesc (j) + "'");
3938                                         }
3939                                         
3940                                         return false;
3941                                 }
3942                         }
3943
3944                         return true;
3945                 }
3946                 
3947                 public override Expression DoResolve (EmitContext ec)
3948                 {
3949                         //
3950                         // First, resolve the expression that is used to
3951                         // trigger the invocation
3952                         //
3953                         if (expr is BaseAccess)
3954                                 is_base = true;
3955
3956                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3957                         if (expr == null)
3958                                 return null;
3959
3960                         if (!(expr is MethodGroupExpr)) {
3961                                 Type expr_type = expr.Type;
3962
3963                                 if (expr_type != null){
3964                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
3965                                         if (IsDelegate)
3966                                                 return (new DelegateInvocation (
3967                                                         this.expr, Arguments, loc)).Resolve (ec);
3968                                 }
3969                         }
3970
3971                         if (!(expr is MethodGroupExpr)){
3972                                 expr.Error118 (ResolveFlags.MethodGroup);
3973                                 return null;
3974                         }
3975
3976                         //
3977                         // Next, evaluate all the expressions in the argument list
3978                         //
3979                         if (Arguments != null){
3980                                 foreach (Argument a in Arguments){
3981                                         if (!a.Resolve (ec, loc))
3982                                                 return null;
3983                                 }
3984                         }
3985
3986                         MethodGroupExpr mg = (MethodGroupExpr) expr;
3987                         method = OverloadResolve (ec, mg, Arguments, loc);
3988
3989                         if (method == null){
3990                                 Error (-6,
3991                                        "Could not find any applicable function for this argument list");
3992                                 return null;
3993                         }
3994
3995                         MethodInfo mi = method as MethodInfo;
3996                         if (mi != null) {
3997                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
3998                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
3999                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4000                         }
4001
4002                         if (type.IsPointer){
4003                                 if (!ec.InUnsafe){
4004                                         UnsafeError (loc);
4005                                         return null;
4006                                 }
4007                         }
4008                         
4009                         eclass = ExprClass.Value;
4010                         return this;
4011                 }
4012
4013                 // <summary>
4014                 //   Emits the list of arguments as an array
4015                 // </summary>
4016                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4017                 {
4018                         ILGenerator ig = ec.ig;
4019                         int count = arguments.Count - idx;
4020                         Argument a = (Argument) arguments [idx];
4021                         Type t = a.Expr.Type;
4022                         string array_type = t.FullName + "[]";
4023                         LocalBuilder array;
4024
4025                         array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4026                         IntConstant.EmitInt (ig, count);
4027                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4028                         ig.Emit (OpCodes.Stloc, array);
4029
4030                         int top = arguments.Count;
4031                         for (int j = idx; j < top; j++){
4032                                 a = (Argument) arguments [j];
4033                                 
4034                                 ig.Emit (OpCodes.Ldloc, array);
4035                                 IntConstant.EmitInt (ig, j - idx);
4036                                 a.Emit (ec);
4037                                 
4038                                 ArrayAccess.EmitStoreOpcode (ig, t);
4039                         }
4040                         ig.Emit (OpCodes.Ldloc, array);
4041                 }
4042                 
4043                 /// <summary>
4044                 ///   Emits a list of resolved Arguments that are in the arguments
4045                 ///   ArrayList.
4046                 /// 
4047                 ///   The MethodBase argument might be null if the
4048                 ///   emission of the arguments is known not to contain
4049                 ///   a `params' field (for example in constructors or other routines
4050                 ///   that keep their arguments in this structure)
4051                 /// </summary>
4052                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4053                 {
4054                         ParameterData pd;
4055                         if (mb != null)
4056                                 pd = GetParameterData (mb);
4057                         else
4058                                 pd = null;
4059
4060                         //
4061                         // If we are calling a params method with no arguments, special case it
4062                         //
4063                         if (arguments == null){
4064                                 if (pd != null && pd.Count > 0 &&
4065                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4066                                         ILGenerator ig = ec.ig;
4067
4068                                         IntConstant.EmitInt (ig, 0);
4069                                         ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4070                                 }
4071
4072                                 return;
4073                         }
4074
4075                         int top = arguments.Count;
4076
4077                         for (int i = 0; i < top; i++){
4078                                 Argument a = (Argument) arguments [i];
4079
4080                                 if (pd != null){
4081                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4082                                                 //
4083                                                 // Special case if we are passing the same data as the
4084                                                 // params argument, do not put it in an array.
4085                                                 //
4086                                                 if (pd.ParameterType (i) == a.Type)
4087                                                         a.Emit (ec);
4088                                                 else
4089                                                         EmitParams (ec, i, arguments);
4090                                                 return;
4091                                         }
4092                                 }
4093                                             
4094                                 a.Emit (ec);
4095                         }
4096
4097                         if (pd != null && pd.Count > top &&
4098                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4099                                 ILGenerator ig = ec.ig;
4100
4101                                 IntConstant.EmitInt (ig, 0);
4102                                 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4103                         }
4104                 }
4105
4106                 /// <remarks>
4107                 ///   is_base tells whether we want to force the use of the `call'
4108                 ///   opcode instead of using callvirt.  Call is required to call
4109                 ///   a specific method, while callvirt will always use the most
4110                 ///   recent method in the vtable.
4111                 ///
4112                 ///   is_static tells whether this is an invocation on a static method
4113                 ///
4114                 ///   instance_expr is an expression that represents the instance
4115                 ///   it must be non-null if is_static is false.
4116                 ///
4117                 ///   method is the method to invoke.
4118                 ///
4119                 ///   Arguments is the list of arguments to pass to the method or constructor.
4120                 /// </remarks>
4121                 public static void EmitCall (EmitContext ec, bool is_base,
4122                                              bool is_static, Expression instance_expr,
4123                                              MethodBase method, ArrayList Arguments, Location loc)
4124                 {
4125                         ILGenerator ig = ec.ig;
4126                         bool struct_call = false;
4127
4128                         Type decl_type = method.DeclaringType;
4129
4130                         if (!RootContext.StdLib) {
4131                                 // Replace any calls to the system's System.Array type with calls to
4132                                 // the newly created one.
4133                                 if (method == TypeManager.system_int_array_get_length)
4134                                         method = TypeManager.int_array_get_length;
4135                                 else if (method == TypeManager.system_int_array_get_rank)
4136                                         method = TypeManager.int_array_get_rank;
4137                                 else if (method == TypeManager.system_object_array_clone)
4138                                         method = TypeManager.object_array_clone;
4139                                 else if (method == TypeManager.system_int_array_get_length_int)
4140                                         method = TypeManager.int_array_get_length_int;
4141                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4142                                         method = TypeManager.int_array_get_lower_bound_int;
4143                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4144                                         method = TypeManager.int_array_get_upper_bound_int;
4145                                 else if (method == TypeManager.system_void_array_copyto_array_int)
4146                                         method = TypeManager.void_array_copyto_array_int;
4147                         }
4148
4149                         //
4150                         // This checks the `ConditionalAttribute' on the method, and the
4151                         // ObsoleteAttribute
4152                         //
4153                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4154                         if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4155                                 return;
4156                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4157                                 return;
4158                         
4159                         if (!is_static){
4160                                 if (decl_type.IsValueType)
4161                                         struct_call = true;
4162                                 //
4163                                 // If this is ourselves, push "this"
4164                                 //
4165                                 if (instance_expr == null){
4166                                         ig.Emit (OpCodes.Ldarg_0);
4167                                 } else {
4168                                         //
4169                                         // Push the instance expression
4170                                         //
4171                                         if (instance_expr.Type.IsValueType){
4172                                                 //
4173                                                 // Special case: calls to a function declared in a 
4174                                                 // reference-type with a value-type argument need
4175                                                 // to have their value boxed.  
4176
4177                                                 struct_call = true;
4178                                                 if (decl_type.IsValueType){
4179                                                         //
4180                                                         // If the expression implements IMemoryLocation, then
4181                                                         // we can optimize and use AddressOf on the
4182                                                         // return.
4183                                                         //
4184                                                         // If not we have to use some temporary storage for
4185                                                         // it.
4186                                                         if (instance_expr is IMemoryLocation){
4187                                                                 ((IMemoryLocation)instance_expr).
4188                                                                         AddressOf (ec, AddressOp.LoadStore);
4189                                                         }
4190                                                         else {
4191                                                                 Type t = instance_expr.Type;
4192                                                                 
4193                                                                 instance_expr.Emit (ec);
4194                                                                 LocalBuilder temp = ig.DeclareLocal (t);
4195                                                                 ig.Emit (OpCodes.Stloc, temp);
4196                                                                 ig.Emit (OpCodes.Ldloca, temp);
4197                                                         }
4198                                                 } else {
4199                                                         instance_expr.Emit (ec);
4200                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
4201                                                 } 
4202                                         } else
4203                                                 instance_expr.Emit (ec);
4204                                 }
4205                         }
4206
4207                         EmitArguments (ec, method, Arguments);
4208
4209                         if (is_static || struct_call || is_base){
4210                                 if (method is MethodInfo) {
4211                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
4212                                 } else
4213                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4214                         } else {
4215                                 if (method is MethodInfo)
4216                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4217                                 else
4218                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4219                         }
4220                 }
4221                 
4222                 public override void Emit (EmitContext ec)
4223                 {
4224                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4225
4226                         EmitCall (
4227                                 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4228                 }
4229                 
4230                 public override void EmitStatement (EmitContext ec)
4231                 {
4232                         Emit (ec);
4233
4234                         // 
4235                         // Pop the return value if there is one
4236                         //
4237                         if (method is MethodInfo){
4238                                 Type ret = ((MethodInfo)method).ReturnType;
4239                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4240                                         ec.ig.Emit (OpCodes.Pop);
4241                         }
4242                 }
4243         }
4244
4245         //
4246         // This class is used to "disable" the code generation for the
4247         // temporary variable when initializing value types.
4248         //
4249         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4250                 public void AddressOf (EmitContext ec, AddressOp Mode)
4251                 {
4252                         // nothing
4253                 }
4254         }
4255         
4256         /// <summary>
4257         ///    Implements the new expression 
4258         /// </summary>
4259         public class New : ExpressionStatement {
4260                 public readonly ArrayList Arguments;
4261                 public readonly Expression RequestedType;
4262
4263                 MethodBase method = null;
4264
4265                 //
4266                 // If set, the new expression is for a value_target, and
4267                 // we will not leave anything on the stack.
4268                 //
4269                 Expression value_target;
4270                 bool value_target_set = false;
4271                 
4272                 public New (Expression requested_type, ArrayList arguments, Location l)
4273                 {
4274                         RequestedType = requested_type;
4275                         Arguments = arguments;
4276                         loc = l;
4277                 }
4278
4279                 public Expression ValueTypeVariable {
4280                         get {
4281                                 return value_target;
4282                         }
4283
4284                         set {
4285                                 value_target = value;
4286                                 value_target_set = true;
4287                         }
4288                 }
4289
4290                 //
4291                 // This function is used to disable the following code sequence for
4292                 // value type initialization:
4293                 //
4294                 // AddressOf (temporary)
4295                 // Construct/Init
4296                 // LoadTemporary
4297                 //
4298                 // Instead the provide will have provided us with the address on the
4299                 // stack to store the results.
4300                 //
4301                 static Expression MyEmptyExpression;
4302                 
4303                 public void DisableTemporaryValueType ()
4304                 {
4305                         if (MyEmptyExpression == null)
4306                                 MyEmptyExpression = new EmptyAddressOf ();
4307
4308                         //
4309                         // To enable this, look into:
4310                         // test-34 and test-89 and self bootstrapping.
4311                         //
4312                         // For instance, we can avoid a copy by using `newobj'
4313                         // instead of Call + Push-temp on value types.
4314 //                      value_target = MyEmptyExpression;
4315                 }
4316                 
4317                 public override Expression DoResolve (EmitContext ec)
4318                 {
4319                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
4320                         
4321                         if (type == null)
4322                                 return null;
4323                         
4324                         bool IsDelegate = TypeManager.IsDelegateType (type);
4325                         
4326                         if (IsDelegate)
4327                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4328
4329                         if (type.IsInterface || type.IsAbstract){
4330                                 Error (
4331                                         144, "It is not possible to create instances of interfaces " +
4332                                         "or abstract classes");
4333                                 return null;
4334                         }
4335                         
4336                         bool is_struct = false;
4337                         is_struct = type.IsValueType;
4338                         eclass = ExprClass.Value;
4339
4340                         //
4341                         // SRE returns a match for .ctor () on structs (the object constructor), 
4342                         // so we have to manually ignore it.
4343                         //
4344                         if (is_struct && Arguments == null)
4345                                 return this;
4346                         
4347                         Expression ml;
4348                         ml = MemberLookupFinal (ec, type, ".ctor",
4349                                                 MemberTypes.Constructor,
4350                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4351
4352                         if (ml == null)
4353                                 return null;
4354                         
4355                         if (! (ml is MethodGroupExpr)){
4356                                 if (!is_struct){
4357                                         ml.Error118 ("method group");
4358                                         return null;
4359                                 }
4360                         }
4361
4362                         if (ml != null) {
4363                                 if (Arguments != null){
4364                                         foreach (Argument a in Arguments){
4365                                                 if (!a.Resolve (ec, loc))
4366                                                         return null;
4367                                         }
4368                                 }
4369
4370                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
4371                                                                      Arguments, loc);
4372                                 
4373                         }
4374
4375                         if (method == null) { 
4376                                 if (!is_struct || Arguments.Count > 0) {
4377                                         Error (1501,
4378                                                "New invocation: Can not find a constructor for " +
4379                                                "this argument list");
4380                                         return null;
4381                                 }
4382                         }
4383                         return this;
4384                 }
4385
4386                 //
4387                 // This DoEmit can be invoked in two contexts:
4388                 //    * As a mechanism that will leave a value on the stack (new object)
4389                 //    * As one that wont (init struct)
4390                 //
4391                 // You can control whether a value is required on the stack by passing
4392                 // need_value_on_stack.  The code *might* leave a value on the stack
4393                 // so it must be popped manually
4394                 //
4395                 // If we are dealing with a ValueType, we have a few
4396                 // situations to deal with:
4397                 //
4398                 //    * The target is a ValueType, and we have been provided
4399                 //      the instance (this is easy, we are being assigned).
4400                 //
4401                 //    * The target of New is being passed as an argument,
4402                 //      to a boxing operation or a function that takes a
4403                 //      ValueType.
4404                 //
4405                 //      In this case, we need to create a temporary variable
4406                 //      that is the argument of New.
4407                 //
4408                 // Returns whether a value is left on the stack
4409                 //
4410                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
4411                 {
4412                         bool is_value_type = type.IsValueType;
4413                         ILGenerator ig = ec.ig;
4414
4415                         if (is_value_type){
4416                                 IMemoryLocation ml;
4417
4418                                 // Allow DoEmit() to be called multiple times.
4419                                 // We need to create a new LocalTemporary each time since
4420                                 // you can't share LocalBuilders among ILGeneators.
4421                                 if (!value_target_set)
4422                                         value_target = new LocalTemporary (ec, type);
4423                                         
4424                                 ml = (IMemoryLocation) value_target;
4425                                 ml.AddressOf (ec, AddressOp.Store);
4426                         }
4427
4428                         if (method != null)
4429                                 Invocation.EmitArguments (ec, method, Arguments);
4430
4431                         if (is_value_type){
4432                                 if (method == null)
4433                                         ig.Emit (OpCodes.Initobj, type);
4434                                 else 
4435                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4436                                 if (need_value_on_stack){
4437                                         value_target.Emit (ec);
4438                                         return true;
4439                                 }
4440                                 return false;
4441                         } else {
4442                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4443                                 return true;
4444                         }
4445                 }
4446
4447                 public override void Emit (EmitContext ec)
4448                 {
4449                         DoEmit (ec, true);
4450                 }
4451                 
4452                 public override void EmitStatement (EmitContext ec)
4453                 {
4454                         if (DoEmit (ec, false))
4455                                 ec.ig.Emit (OpCodes.Pop);
4456                 }
4457         }
4458
4459         /// <summary>
4460         ///   14.5.10.2: Represents an array creation expression.
4461         /// </summary>
4462         ///
4463         /// <remarks>
4464         ///   There are two possible scenarios here: one is an array creation
4465         ///   expression that specifies the dimensions and optionally the
4466         ///   initialization data and the other which does not need dimensions
4467         ///   specified but where initialization data is mandatory.
4468         /// </remarks>
4469         public class ArrayCreation : ExpressionStatement {
4470                 Expression requested_base_type;
4471                 ArrayList initializers;
4472
4473                 //
4474                 // The list of Argument types.
4475                 // This is used to construct the `newarray' or constructor signature
4476                 //
4477                 ArrayList arguments;
4478
4479                 //
4480                 // Method used to create the array object.
4481                 //
4482                 MethodBase new_method = null;
4483                 
4484                 Type array_element_type;
4485                 Type underlying_type;
4486                 bool is_one_dimensional = false;
4487                 bool is_builtin_type = false;
4488                 bool expect_initializers = false;
4489                 int num_arguments = 0;
4490                 int dimensions = 0;
4491                 string rank;
4492
4493                 ArrayList array_data;
4494
4495                 Hashtable bounds;
4496
4497                 //
4498                 // The number of array initializers that we can handle
4499                 // via the InitializeArray method - through EmitStaticInitializers
4500                 //
4501                 int num_automatic_initializers;
4502                 
4503                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
4504                 {
4505                         this.requested_base_type = requested_base_type;
4506                         this.initializers = initializers;
4507                         this.rank = rank;
4508                         loc = l;
4509
4510                         arguments = new ArrayList ();
4511
4512                         foreach (Expression e in exprs) {
4513                                 arguments.Add (new Argument (e, Argument.AType.Expression));
4514                                 num_arguments++;
4515                         }
4516                 }
4517
4518                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
4519                 {
4520                         this.requested_base_type = requested_base_type;
4521                         this.initializers = initializers;
4522                         this.rank = rank;
4523                         loc = l;
4524
4525                         //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
4526                         //
4527                         //string tmp = rank.Substring (rank.LastIndexOf ("["));
4528                         //
4529                         //dimensions = tmp.Length - 1;
4530                         expect_initializers = true;
4531                 }
4532
4533                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
4534                 {
4535                         StringBuilder sb = new StringBuilder (rank);
4536                         
4537                         sb.Append ("[");
4538                         for (int i = 1; i < idx_count; i++)
4539                                 sb.Append (",");
4540                         
4541                         sb.Append ("]");
4542
4543                         return new ComposedCast (base_type, sb.ToString (), loc);
4544                 }
4545
4546                 void Error_IncorrectArrayInitializer ()
4547                 {
4548                         Error (178, "Incorrectly structured array initializer");
4549                 }
4550                 
4551                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
4552                 {
4553                         if (specified_dims) { 
4554                                 Argument a = (Argument) arguments [idx];
4555                                 
4556                                 if (!a.Resolve (ec, loc))
4557                                         return false;
4558                                 
4559                                 if (!(a.Expr is Constant)) {
4560                                         Error (150, "A constant value is expected");
4561                                         return false;
4562                                 }
4563                                 
4564                                 int value = (int) ((Constant) a.Expr).GetValue ();
4565                                 
4566                                 if (value != probe.Count) {
4567                                         Error_IncorrectArrayInitializer ();
4568                                         return false;
4569                                 }
4570                                 
4571                                 bounds [idx] = value;
4572                         }
4573
4574                         int child_bounds = -1;
4575                         foreach (object o in probe) {
4576                                 if (o is ArrayList) {
4577                                         int current_bounds = ((ArrayList) o).Count;
4578                                         
4579                                         if (child_bounds == -1) 
4580                                                 child_bounds = current_bounds;
4581
4582                                         else if (child_bounds != current_bounds){
4583                                                 Error_IncorrectArrayInitializer ();
4584                                                 return false;
4585                                         }
4586                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
4587                                         if (!ret)
4588                                                 return false;
4589                                 } else {
4590                                         if (child_bounds != -1){
4591                                                 Error_IncorrectArrayInitializer ();
4592                                                 return false;
4593                                         }
4594                                         
4595                                         Expression tmp = (Expression) o;
4596                                         tmp = tmp.Resolve (ec);
4597                                         if (tmp == null)
4598                                                 continue;
4599
4600                                         // Console.WriteLine ("I got: " + tmp);
4601                                         // Handle initialization from vars, fields etc.
4602
4603                                         Expression conv = ConvertImplicitRequired (
4604                                                 ec, tmp, underlying_type, loc);
4605                                         
4606                                         if (conv == null) 
4607                                                 return false;
4608
4609                                         if (conv is StringConstant)
4610                                                 array_data.Add (conv);
4611                                         else if (conv is Constant) {
4612                                                 array_data.Add (conv);
4613                                                 num_automatic_initializers++;
4614                                         } else
4615                                                 array_data.Add (conv);
4616                                 }
4617                         }
4618
4619                         return true;
4620                 }
4621                 
4622                 public void UpdateIndices (EmitContext ec)
4623                 {
4624                         int i = 0;
4625                         for (ArrayList probe = initializers; probe != null;) {
4626                                 if (probe.Count > 0 && probe [0] is ArrayList) {
4627                                         Expression e = new IntConstant (probe.Count);
4628                                         arguments.Add (new Argument (e, Argument.AType.Expression));
4629
4630                                         bounds [i++] =  probe.Count;
4631                                         
4632                                         probe = (ArrayList) probe [0];
4633                                         
4634                                 } else {
4635                                         Expression e = new IntConstant (probe.Count);
4636                                         arguments.Add (new Argument (e, Argument.AType.Expression));
4637
4638                                         bounds [i++] = probe.Count;
4639                                         probe = null;
4640                                 }
4641                         }
4642
4643                 }
4644                 
4645                 public bool ValidateInitializers (EmitContext ec, Type array_type)
4646                 {
4647                         if (initializers == null) {
4648                                 if (expect_initializers)
4649                                         return false;
4650                                 else
4651                                         return true;
4652                         }
4653                         
4654                         if (underlying_type == null)
4655                                 return false;
4656                         
4657                         //
4658                         // We use this to store all the date values in the order in which we
4659                         // will need to store them in the byte blob later
4660                         //
4661                         array_data = new ArrayList ();
4662                         bounds = new Hashtable ();
4663                         
4664                         bool ret;
4665
4666                         if (arguments != null) {
4667                                 ret = CheckIndices (ec, initializers, 0, true);
4668                                 return ret;
4669                         } else {
4670                                 arguments = new ArrayList ();
4671
4672                                 ret = CheckIndices (ec, initializers, 0, false);
4673                                 
4674                                 if (!ret)
4675                                         return false;
4676                                 
4677                                 UpdateIndices (ec);
4678                                 
4679                                 if (arguments.Count != dimensions) {
4680                                         Error_IncorrectArrayInitializer ();
4681                                         return false;
4682                                 }
4683
4684                                 return ret;
4685                         }
4686                 }
4687
4688                 void Error_NegativeArrayIndex ()
4689                 {
4690                         Error (284, "Can not create array with a negative size");
4691                 }
4692                 
4693                 //
4694                 // Converts `source' to an int, uint, long or ulong.
4695                 //
4696                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
4697                 {
4698                         Expression target;
4699                         
4700                         bool old_checked = ec.CheckState;
4701                         ec.CheckState = true;
4702                         
4703                         target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
4704                         if (target == null){
4705                                 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
4706                                 if (target == null){
4707                                         target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
4708                                         if (target == null){
4709                                                 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
4710                                                 if (target == null)
4711                                                         Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
4712                                         }
4713                                 }
4714                         } 
4715                         ec.CheckState = old_checked;
4716
4717                         //
4718                         // Only positive constants are allowed at compile time
4719                         //
4720                         if (target is Constant){
4721                                 if (target is IntConstant){
4722                                         if (((IntConstant) target).Value < 0){
4723                                                 Error_NegativeArrayIndex ();
4724                                                 return null;
4725                                         }
4726                                 }
4727
4728                                 if (target is LongConstant){
4729                                         if (((LongConstant) target).Value < 0){
4730                                                 Error_NegativeArrayIndex ();
4731                                                 return null;
4732                                         }
4733                                 }
4734                                 
4735                         }
4736
4737                         return target;
4738                 }
4739
4740                 //
4741                 // Creates the type of the array
4742                 //
4743                 bool LookupType (EmitContext ec)
4744                 {
4745                         StringBuilder array_qualifier = new StringBuilder (rank);
4746
4747                         //
4748                         // `In the first form allocates an array instace of the type that results
4749                         // from deleting each of the individual expression from the expression list'
4750                         //
4751                         if (num_arguments > 0) {
4752                                 array_qualifier.Append ("[");
4753                                 for (int i = num_arguments-1; i > 0; i--)
4754                                         array_qualifier.Append (",");
4755                                 array_qualifier.Append ("]");                           
4756                         }
4757
4758                         //
4759                         // Lookup the type
4760                         //
4761                         Expression array_type_expr;
4762                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
4763                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
4764
4765                         if (type == null)
4766                                 return false;
4767
4768                         underlying_type = type;
4769                         if (underlying_type.IsArray)
4770                                 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
4771                         dimensions = type.GetArrayRank ();
4772
4773                         return true;
4774                 }
4775                 
4776                 public override Expression DoResolve (EmitContext ec)
4777                 {
4778                         int arg_count;
4779
4780                         if (!LookupType (ec))
4781                                 return null;
4782                         
4783                         //
4784                         // First step is to validate the initializers and fill
4785                         // in any missing bits
4786                         //
4787                         if (!ValidateInitializers (ec, type))
4788                                 return null;
4789
4790                         if (arguments == null)
4791                                 arg_count = 0;
4792                         else {
4793                                 arg_count = arguments.Count;
4794                                 foreach (Argument a in arguments){
4795                                         if (!a.Resolve (ec, loc))
4796                                                 return null;
4797
4798                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
4799                                         if (real_arg == null)
4800                                                 return null;
4801
4802                                         a.Expr = real_arg;
4803                                 }
4804                         }
4805                         
4806                         array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
4807
4808                         if (arg_count == 1) {
4809                                 is_one_dimensional = true;
4810                                 eclass = ExprClass.Value;
4811                                 return this;
4812                         }
4813
4814                         is_builtin_type = TypeManager.IsBuiltinType (type);
4815
4816                         if (is_builtin_type) {
4817                                 Expression ml;
4818                                 
4819                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
4820                                                    AllBindingFlags, loc);
4821                                 
4822                                 if (!(ml is MethodGroupExpr)) {
4823                                         ml.Error118 ("method group");
4824                                         return null;
4825                                 }
4826                                 
4827                                 if (ml == null) {
4828                                         Error (-6, "New invocation: Can not find a constructor for " +
4829                                                       "this argument list");
4830                                         return null;
4831                                 }
4832                                 
4833                                 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
4834
4835                                 if (new_method == null) {
4836                                         Error (-6, "New invocation: Can not find a constructor for " +
4837                                                       "this argument list");
4838                                         return null;
4839                                 }
4840                                 
4841                                 eclass = ExprClass.Value;
4842                                 return this;
4843                         } else {
4844                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
4845                                 ArrayList args = new ArrayList ();
4846                                 
4847                                 if (arguments != null) {
4848                                         for (int i = 0; i < arg_count; i++)
4849                                                 args.Add (TypeManager.int32_type);
4850                                 }
4851                                 
4852                                 Type [] arg_types = null;
4853
4854                                 if (args.Count > 0)
4855                                         arg_types = new Type [args.Count];
4856                                 
4857                                 args.CopyTo (arg_types, 0);
4858                                 
4859                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
4860                                                             arg_types);
4861
4862                                 if (new_method == null) {
4863                                         Error (-6, "New invocation: Can not find a constructor for " +
4864                                                       "this argument list");
4865                                         return null;
4866                                 }
4867                                 
4868                                 eclass = ExprClass.Value;
4869                                 return this;
4870                         }
4871                 }
4872
4873                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
4874                 {
4875                         int factor;
4876                         byte [] data;
4877                         byte [] element;
4878                         int count = array_data.Count;
4879
4880                         if (underlying_type.IsEnum)
4881                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
4882                         
4883                         factor = GetTypeSize (underlying_type);
4884                         if (factor == 0)
4885                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
4886
4887                         data = new byte [(count * factor + 4) & ~3];
4888                         int idx = 0;
4889                         
4890                         for (int i = 0; i < count; ++i) {
4891                                 object v = array_data [i];
4892
4893                                 if (v is EnumConstant)
4894                                         v = ((EnumConstant) v).Child;
4895                                 
4896                                 if (v is Constant && !(v is StringConstant))
4897                                         v = ((Constant) v).GetValue ();
4898                                 else {
4899                                         idx += factor;
4900                                         continue;
4901                                 }
4902                                 
4903                                 if (underlying_type == TypeManager.int64_type){
4904                                         if (!(v is Expression)){
4905                                                 long val = (long) v;
4906                                                 
4907                                                 for (int j = 0; j < factor; ++j) {
4908                                                         data [idx + j] = (byte) (val & 0xFF);
4909                                                         val = (val >> 8);
4910                                                 }
4911                                         }
4912                                 } else if (underlying_type == TypeManager.uint64_type){
4913                                         if (!(v is Expression)){
4914                                                 ulong val = (ulong) v;
4915
4916                                                 for (int j = 0; j < factor; ++j) {
4917                                                         data [idx + j] = (byte) (val & 0xFF);
4918                                                         val = (val >> 8);
4919                                                 }
4920                                         }
4921                                 } else if (underlying_type == TypeManager.float_type) {
4922                                         if (!(v is Expression)){
4923                                                 element = BitConverter.GetBytes ((float) v);
4924                                                         
4925                                                 for (int j = 0; j < factor; ++j)
4926                                                         data [idx + j] = element [j];
4927                                         }
4928                                 } else if (underlying_type == TypeManager.double_type) {
4929                                         if (!(v is Expression)){
4930                                                 element = BitConverter.GetBytes ((double) v);
4931
4932                                                 for (int j = 0; j < factor; ++j)
4933                                                         data [idx + j] = element [j];
4934                                         }
4935                                 } else if (underlying_type == TypeManager.char_type){
4936                                         if (!(v is Expression)){
4937                                                 int val = (int) ((char) v);
4938                                                 
4939                                                 data [idx] = (byte) (val & 0xff);
4940                                                 data [idx+1] = (byte) (val >> 8);
4941                                         }
4942                                 } else if (underlying_type == TypeManager.short_type){
4943                                         if (!(v is Expression)){
4944                                                 int val = (int) ((short) v);
4945                                         
4946                                                 data [idx] = (byte) (val & 0xff);
4947                                                 data [idx+1] = (byte) (val >> 8);
4948                                         }
4949                                 } else if (underlying_type == TypeManager.ushort_type){
4950                                         if (!(v is Expression)){
4951                                                 int val = (int) ((ushort) v);
4952                                         
4953                                                 data [idx] = (byte) (val & 0xff);
4954                                                 data [idx+1] = (byte) (val >> 8);
4955                                         }
4956                                 } else if (underlying_type == TypeManager.int32_type) {
4957                                         if (!(v is Expression)){
4958                                                 int val = (int) v;
4959                                         
4960                                                 data [idx]   = (byte) (val & 0xff);
4961                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4962                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4963                                                 data [idx+3] = (byte) (val >> 24);
4964                                         }
4965                                 } else if (underlying_type == TypeManager.uint32_type) {
4966                                         if (!(v is Expression)){
4967                                                 uint val = (uint) v;
4968                                         
4969                                                 data [idx]   = (byte) (val & 0xff);
4970                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
4971                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
4972                                                 data [idx+3] = (byte) (val >> 24);
4973                                         }
4974                                 } else if (underlying_type == TypeManager.sbyte_type) {
4975                                         if (!(v is Expression)){
4976                                                 sbyte val = (sbyte) v;
4977                                                 data [idx] = (byte) val;
4978                                         }
4979                                 } else if (underlying_type == TypeManager.byte_type) {
4980                                         if (!(v is Expression)){
4981                                                 byte val = (byte) v;
4982                                                 data [idx] = (byte) val;
4983                                         }
4984                                 } else if (underlying_type == TypeManager.bool_type) {
4985                                         if (!(v is Expression)){
4986                                                 bool val = (bool) v;
4987                                                 data [idx] = (byte) (val ? 1 : 0);
4988                                         }
4989                                 } else if (underlying_type == TypeManager.decimal_type){
4990                                         if (!(v is Expression)){
4991                                                 int [] bits = Decimal.GetBits ((decimal) v);
4992                                                 int p = idx;
4993                                                 
4994                                                 for (int j = 0; j < 4; j++){
4995                                                         data [p++] = (byte) (bits [j] & 0xff);
4996                                                         data [p++] = (byte) ((bits [j] >> 8) & 0xff);
4997                                                         data [p++] = (byte) ((bits [j] >> 16) & 0xff);
4998                                                         data [p++] = (byte) (bits [j] >> 24);
4999                                                 }
5000                                         }
5001                                 } else
5002                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5003
5004                                 idx += factor;
5005                         }
5006
5007                         return data;
5008                 }
5009
5010                 //
5011                 // Emits the initializers for the array
5012                 //
5013                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5014                 {
5015                         //
5016                         // First, the static data
5017                         //
5018                         FieldBuilder fb;
5019                         ILGenerator ig = ec.ig;
5020                         
5021                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5022
5023                         fb = RootContext.MakeStaticData (data);
5024
5025                         if (is_expression)
5026                                 ig.Emit (OpCodes.Dup);
5027                         ig.Emit (OpCodes.Ldtoken, fb);
5028                         ig.Emit (OpCodes.Call,
5029                                  TypeManager.void_initializearray_array_fieldhandle);
5030                 }
5031                 
5032                 //
5033                 // Emits pieces of the array that can not be computed at compile
5034                 // time (variables and string locations).
5035                 //
5036                 // This always expect the top value on the stack to be the array
5037                 //
5038                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5039                 {
5040                         ILGenerator ig = ec.ig;
5041                         int dims = bounds.Count;
5042                         int [] current_pos = new int [dims];
5043                         int top = array_data.Count;
5044                         LocalBuilder temp = ig.DeclareLocal (type);
5045
5046                         ig.Emit (OpCodes.Stloc, temp);
5047
5048                         MethodInfo set = null;
5049
5050                         if (dims != 1){
5051                                 Type [] args;
5052                                 ModuleBuilder mb = null;
5053                                 mb = CodeGen.ModuleBuilder;
5054                                 args = new Type [dims + 1];
5055
5056                                 int j;
5057                                 for (j = 0; j < dims; j++)
5058                                         args [j] = TypeManager.int32_type;
5059
5060                                 args [j] = array_element_type;
5061                                 
5062                                 set = mb.GetArrayMethod (
5063                                         type, "Set",
5064                                         CallingConventions.HasThis | CallingConventions.Standard,
5065                                         TypeManager.void_type, args);
5066                         }
5067                         
5068                         for (int i = 0; i < top; i++){
5069
5070                                 Expression e = null;
5071
5072                                 if (array_data [i] is Expression)
5073                                         e = (Expression) array_data [i];
5074
5075                                 if (e != null) {
5076                                         //
5077                                         // Basically we do this for string literals and
5078                                         // other non-literal expressions
5079                                         //
5080                                         if (e is StringConstant || !(e is Constant) ||
5081                                             num_automatic_initializers <= 2) {
5082                                                 Type etype = e.Type;
5083                                                 
5084                                                 ig.Emit (OpCodes.Ldloc, temp);
5085
5086                                                 for (int idx = 0; idx < dims; idx++) 
5087                                                         IntConstant.EmitInt (ig, current_pos [idx]);
5088
5089                                                 //
5090                                                 // If we are dealing with a struct, get the
5091                                                 // address of it, so we can store it.
5092                                                 //
5093                                                 if ((dims == 1) &&
5094                                                     etype.IsSubclassOf (TypeManager.value_type) &&
5095                                                     (!TypeManager.IsBuiltinType (etype) ||
5096                                                      etype == TypeManager.decimal_type)) {
5097                                                         if (e is New){
5098                                                                 New n = (New) e;
5099
5100                                                                 //
5101                                                                 // Let new know that we are providing
5102                                                                 // the address where to store the results
5103                                                                 //
5104                                                                 n.DisableTemporaryValueType ();
5105                                                         }
5106                                                                              
5107                                                         ig.Emit (OpCodes.Ldelema, etype);
5108                                                 }
5109
5110                                                 e.Emit (ec);
5111                                                 
5112                                                 if (dims == 1)
5113                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
5114                                                 else 
5115                                                         ig.Emit (OpCodes.Call, set);
5116                                         }
5117                                 }
5118                                 
5119                                 //
5120                                 // Advance counter
5121                                 //
5122                                 for (int j = dims - 1; j >= 0; j--){
5123                                         current_pos [j]++;
5124                                         if (current_pos [j] < (int) bounds [j])
5125                                                 break;
5126                                         current_pos [j] = 0;
5127                                 }
5128                         }
5129
5130                         if (is_expression)
5131                                 ig.Emit (OpCodes.Ldloc, temp);
5132                 }
5133
5134                 void EmitArrayArguments (EmitContext ec)
5135                 {
5136                         ILGenerator ig = ec.ig;
5137                         
5138                         foreach (Argument a in arguments) {
5139                                 Type atype = a.Type;
5140                                 a.Emit (ec);
5141
5142                                 if (atype == TypeManager.uint64_type)
5143                                         ig.Emit (OpCodes.Conv_Ovf_U4);
5144                                 else if (atype == TypeManager.int64_type)
5145                                         ig.Emit (OpCodes.Conv_Ovf_I4);
5146                         }
5147                 }
5148                 
5149                 void DoEmit (EmitContext ec, bool is_statement)
5150                 {
5151                         ILGenerator ig = ec.ig;
5152                         
5153                         EmitArrayArguments (ec);
5154                         if (is_one_dimensional)
5155                                 ig.Emit (OpCodes.Newarr, array_element_type);
5156                         else {
5157                                 if (is_builtin_type) 
5158                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
5159                                 else 
5160                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
5161                         }
5162                         
5163                         if (initializers != null){
5164                                 //
5165                                 // FIXME: Set this variable correctly.
5166                                 // 
5167                                 bool dynamic_initializers = true;
5168
5169                                 if (underlying_type != TypeManager.string_type &&
5170                                     underlying_type != TypeManager.object_type) {
5171                                         if (num_automatic_initializers > 2)
5172                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
5173                                 }
5174                                 
5175                                 if (dynamic_initializers)
5176                                         EmitDynamicInitializers (ec, !is_statement);
5177                         }
5178                 }
5179                 
5180                 public override void Emit (EmitContext ec)
5181                 {
5182                         DoEmit (ec, false);
5183                 }
5184
5185                 public override void EmitStatement (EmitContext ec)
5186                 {
5187                         DoEmit (ec, true);
5188                 }
5189                 
5190         }
5191         
5192         /// <summary>
5193         ///   Represents the `this' construct
5194         /// </summary>
5195         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
5196
5197                 Block block;
5198                 VariableInfo vi;
5199                 
5200                 public This (Block block, Location loc)
5201                 {
5202                         this.loc = loc;
5203                         this.block = block;
5204                 }
5205
5206                 public This (Location loc)
5207                 {
5208                         this.loc = loc;
5209                 }
5210
5211                 public bool IsAssigned (EmitContext ec, Location loc)
5212                 {
5213                         if (vi == null)
5214                                 return true;
5215
5216                         return vi.IsAssigned (ec, loc);
5217                 }
5218
5219                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
5220                 {
5221                         if (vi == null)
5222                                 return true;
5223
5224                         return vi.IsFieldAssigned (ec, field_name, loc);
5225                 }
5226
5227                 public void SetAssigned (EmitContext ec)
5228                 {
5229                         if (vi != null)
5230                                 vi.SetAssigned (ec);
5231                 }
5232
5233                 public void SetFieldAssigned (EmitContext ec, string field_name)
5234                 {       
5235                         if (vi != null)
5236                                 vi.SetFieldAssigned (ec, field_name);
5237                 }
5238
5239                 public override Expression DoResolve (EmitContext ec)
5240                 {
5241                         eclass = ExprClass.Variable;
5242                         type = ec.ContainerType;
5243
5244                         if (ec.IsStatic){
5245                                 Error (26, "Keyword this not valid in static code");
5246                                 return null;
5247                         }
5248
5249                         if (block != null)
5250                                 vi = block.ThisVariable;
5251
5252                         return this;
5253                 }
5254
5255                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5256                 {
5257                         DoResolve (ec);
5258
5259                         VariableInfo vi = ec.CurrentBlock.ThisVariable;
5260                         if (vi != null)
5261                                 vi.SetAssigned (ec);
5262                         
5263                         if (ec.TypeContainer is Class){
5264                                 Error (1604, "Cannot assign to `this'");
5265                                 return null;
5266                         }
5267
5268                         return this;
5269                 }
5270
5271                 public override void Emit (EmitContext ec)
5272                 {
5273                         ILGenerator ig = ec.ig;
5274                         
5275                         ig.Emit (OpCodes.Ldarg_0);
5276                         if (ec.TypeContainer is Struct)
5277                                 ig.Emit (OpCodes.Ldobj, type);
5278                 }
5279
5280                 public void EmitAssign (EmitContext ec, Expression source)
5281                 {
5282                         ILGenerator ig = ec.ig;
5283                         
5284                         if (ec.TypeContainer is Struct){
5285                                 ig.Emit (OpCodes.Ldarg_0);
5286                                 source.Emit (ec);
5287                                 ig.Emit (OpCodes.Stobj, type);
5288                         } else {
5289                                 source.Emit (ec);
5290                                 ig.Emit (OpCodes.Starg, 0);
5291                         }
5292                 }
5293
5294                 public void AddressOf (EmitContext ec, AddressOp mode)
5295                 {
5296                         ec.ig.Emit (OpCodes.Ldarg_0);
5297
5298                         // FIMXE
5299                         // FIGURE OUT WHY LDARG_S does not work
5300                         //
5301                         // consider: struct X { int val; int P { set { val = value; }}}
5302                         //
5303                         // Yes, this looks very bad. Look at `NOTAS' for
5304                         // an explanation.
5305                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
5306                 }
5307         }
5308
5309         /// <summary>
5310         ///   Implements the typeof operator
5311         /// </summary>
5312         public class TypeOf : Expression {
5313                 public readonly Expression QueriedType;
5314                 Type typearg;
5315                 
5316                 public TypeOf (Expression queried_type, Location l)
5317                 {
5318                         QueriedType = queried_type;
5319                         loc = l;
5320                 }
5321
5322                 public override Expression DoResolve (EmitContext ec)
5323                 {
5324                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
5325
5326                         if (typearg == null)
5327                                 return null;
5328
5329                         type = TypeManager.type_type;
5330                         eclass = ExprClass.Type;
5331                         return this;
5332                 }
5333
5334                 public override void Emit (EmitContext ec)
5335                 {
5336                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
5337                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5338                 }
5339
5340                 public Type TypeArg { 
5341                         get { return typearg; }
5342                 }
5343         }
5344
5345         /// <summary>
5346         ///   Implements the sizeof expression
5347         /// </summary>
5348         public class SizeOf : Expression {
5349                 public readonly Expression QueriedType;
5350                 Type type_queried;
5351                 
5352                 public SizeOf (Expression queried_type, Location l)
5353                 {
5354                         this.QueriedType = queried_type;
5355                         loc = l;
5356                 }
5357
5358                 public override Expression DoResolve (EmitContext ec)
5359                 {
5360                         if (!ec.InUnsafe) {
5361                                 Error (233, "Sizeof may only be used in an unsafe context " +
5362                                        "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
5363                                 return null;
5364                         }
5365                                 
5366                         type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
5367                         if (type_queried == null)
5368                                 return null;
5369
5370                         if (!TypeManager.IsUnmanagedType (type_queried)){
5371                                 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
5372                                 return null;
5373                         }
5374                         
5375                         type = TypeManager.int32_type;
5376                         eclass = ExprClass.Value;
5377                         return this;
5378                 }
5379
5380                 public override void Emit (EmitContext ec)
5381                 {
5382                         int size = GetTypeSize (type_queried);
5383
5384                         if (size == 0)
5385                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
5386                         else
5387                                 IntConstant.EmitInt (ec.ig, size);
5388                 }
5389         }
5390
5391         /// <summary>
5392         ///   Implements the member access expression
5393         /// </summary>
5394         public class MemberAccess : Expression, ITypeExpression {
5395                 public readonly string Identifier;
5396                 Expression expr;
5397                 Expression member_lookup;
5398                 
5399                 public MemberAccess (Expression expr, string id, Location l)
5400                 {
5401                         this.expr = expr;
5402                         Identifier = id;
5403                         loc = l;
5404                 }
5405
5406                 public Expression Expr {
5407                         get {
5408                                 return expr;
5409                         }
5410                 }
5411
5412                 static void error176 (Location loc, string name)
5413                 {
5414                         Report.Error (176, loc, "Static member `" +
5415                                       name + "' cannot be accessed " +
5416                                       "with an instance reference, qualify with a " +
5417                                       "type name instead");
5418                 }
5419
5420                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
5421                 {
5422                         if (left_original == null)
5423                                 return false;
5424
5425                         if (!(left_original is SimpleName))
5426                                 return false;
5427
5428                         SimpleName sn = (SimpleName) left_original;
5429
5430                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
5431                         if (t != null)
5432                                 return true;
5433
5434                         return false;
5435                 }
5436                 
5437                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
5438                                                               Expression left, Location loc,
5439                                                               Expression left_original)
5440                 {
5441                         bool left_is_type, left_is_explicit;
5442
5443                         // If `left' is null, then we're called from SimpleNameResolve and this is
5444                         // a member in the currently defining class.
5445                         if (left == null) {
5446                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
5447                                 left_is_explicit = false;
5448
5449                                 // Implicitly default to `this' unless we're static.
5450                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
5451                                         left = ec.This;
5452                         } else {
5453                                 left_is_type = left is TypeExpr;
5454                                 left_is_explicit = true;
5455                         }
5456
5457                         if (member_lookup is FieldExpr){
5458                                 FieldExpr fe = (FieldExpr) member_lookup;
5459                                 FieldInfo fi = fe.FieldInfo;
5460                                 Type decl_type = fi.DeclaringType;
5461                                 
5462                                 if (fi is FieldBuilder) {
5463                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
5464                                         
5465                                         if (c != null) {
5466                                                 object o = c.LookupConstantValue (ec);
5467                                                 object real_value = ((Constant) c.Expr).GetValue ();
5468
5469                                                 return Constantify (real_value, fi.FieldType);
5470                                         }
5471                                 }
5472
5473                                 if (fi.IsLiteral) {
5474                                         Type t = fi.FieldType;
5475                                         
5476                                         object o;
5477
5478                                         if (fi is FieldBuilder)
5479                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
5480                                         else
5481                                                 o = fi.GetValue (fi);
5482                                         
5483                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
5484                                                 if (left_is_explicit && !left_is_type &&
5485                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {
5486                                                         error176 (loc, fe.FieldInfo.Name);
5487                                                         return null;
5488                                                 }                                       
5489                                                 
5490                                                 Expression enum_member = MemberLookup (
5491                                                         ec, decl_type, "value__", MemberTypes.Field,
5492                                                         AllBindingFlags, loc); 
5493
5494                                                 Enum en = TypeManager.LookupEnum (decl_type);
5495
5496                                                 Constant c;
5497                                                 if (en != null)
5498                                                         c = Constantify (o, en.UnderlyingType);
5499                                                 else 
5500                                                         c = Constantify (o, enum_member.Type);
5501                                                 
5502                                                 return new EnumConstant (c, decl_type);
5503                                         }
5504                                         
5505                                         Expression exp = Constantify (o, t);
5506
5507                                         if (left_is_explicit && !left_is_type) {
5508                                                 error176 (loc, fe.FieldInfo.Name);
5509                                                 return null;
5510                                         }
5511                                         
5512                                         return exp;
5513                                 }
5514
5515                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
5516                                         UnsafeError (loc);
5517                                         return null;
5518                                 }
5519                         }
5520
5521                         if (member_lookup is EventExpr) {
5522
5523                                 EventExpr ee = (EventExpr) member_lookup;
5524                                 
5525                                 //
5526                                 // If the event is local to this class, we transform ourselves into
5527                                 // a FieldExpr
5528                                 //
5529
5530                                 if (ee.EventInfo.DeclaringType == ec.ContainerType) {
5531                                         MemberInfo mi = GetFieldFromEvent (ee);
5532
5533                                         if (mi == null) {
5534                                                 //
5535                                                 // If this happens, then we have an event with its own
5536                                                 // accessors and private field etc so there's no need
5537                                                 // to transform ourselves : we should instead flag an error
5538                                                 //
5539                                                 Assign.error70 (ee.EventInfo, loc);
5540                                                 return null;
5541                                         }
5542
5543                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
5544                                         
5545                                         if (ml == null) {
5546                                                 Report.Error (-200, loc, "Internal error!!");
5547                                                 return null;
5548                                         }
5549                                         
5550                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
5551                                 }
5552                         }
5553                         
5554                         if (member_lookup is IMemberExpr) {
5555                                 IMemberExpr me = (IMemberExpr) member_lookup;
5556
5557                                 if (left_is_type){
5558                                         MethodGroupExpr mg = me as MethodGroupExpr;
5559                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
5560                                                 mg.IsExplicitImpl = left_is_explicit;
5561
5562                                         if (!me.IsStatic){
5563                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5564                                                         return member_lookup;
5565
5566                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
5567                                                 return null;
5568                                         }
5569
5570                                 } else {
5571                                         if (!me.IsInstance){
5572                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
5573                                                         return member_lookup;
5574
5575                                                 if (left_is_explicit) {
5576                                                         error176 (loc, me.Name);
5577                                                         return null;
5578                                                 }
5579                                         }
5580
5581                                         //
5582                                         // Since we can not check for instance objects in SimpleName,
5583                                         // becaue of the rule that allows types and variables to share
5584                                         // the name (as long as they can be de-ambiguated later, see 
5585                                         // IdenticalNameAndTypeName), we have to check whether left 
5586                                         // is an instance variable in a static context
5587                                         //
5588                                         // However, if the left-hand value is explicitly given, then
5589                                         // it is already our instance expression, so we aren't in
5590                                         // static context.
5591                                         //
5592
5593                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
5594                                                 IMemberExpr mexp = (IMemberExpr) left;
5595
5596                                                 if (!mexp.IsStatic){
5597                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
5598                                                         return null;
5599                                                 }
5600                                         }
5601
5602                                         me.InstanceExpression = left;
5603                                 }
5604
5605                                 return member_lookup;
5606                         }
5607
5608                         if (member_lookup is TypeExpr){
5609                                 member_lookup.Resolve (ec, ResolveFlags.Type);
5610                                 return member_lookup;
5611                         }
5612                         
5613                         Console.WriteLine ("Left is: " + left);
5614                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
5615                         Environment.Exit (0);
5616                         return null;
5617                 }
5618                 
5619                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
5620                 {
5621                         if (type != null)
5622                                 throw new Exception ();
5623                         //
5624                         // Resolve the expression with flow analysis turned off, we'll do the definite
5625                         // assignment checks later.  This is because we don't know yet what the expression
5626                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
5627                         // definite assignment check on the actual field and not on the whole struct.
5628                         //
5629
5630                         Expression original = expr;
5631                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
5632
5633                         if (expr == null)
5634                                 return null;
5635
5636                         if (expr is SimpleName){
5637                                 SimpleName child_expr = (SimpleName) expr;
5638                                 
5639                                 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
5640
5641                                 return new_expr.Resolve (ec, flags);
5642                         }
5643                                         
5644                         //
5645                         // TODO: I mailed Ravi about this, and apparently we can get rid
5646                         // of this and put it in the right place.
5647                         // 
5648                         // Handle enums here when they are in transit.
5649                         // Note that we cannot afford to hit MemberLookup in this case because
5650                         // it will fail to find any members at all
5651                         //
5652
5653                         int errors = Report.Errors;
5654                         
5655                         Type expr_type = expr.Type;
5656                         if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
5657                                 
5658                                 Enum en = TypeManager.LookupEnum (expr_type);
5659                                 
5660                                 if (en != null) {
5661                                         object value = en.LookupEnumValue (ec, Identifier, loc);
5662
5663                                         if (value != null){
5664                                                 Constant c = Constantify (value, en.UnderlyingType);
5665                                                 return new EnumConstant (c, expr_type);
5666                                         }
5667                                 }
5668                         }
5669
5670                         if (expr_type.IsPointer){
5671                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
5672                                        TypeManager.CSharpName (expr_type) + ")");
5673                                 return null;
5674                         }
5675
5676                         member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
5677
5678                         if (member_lookup == null){
5679                                 // Error has already been reported.
5680                                 if (errors < Report.Errors)
5681                                         return null;
5682
5683                                 //
5684                                 // Try looking the member up from the same type, if we find
5685                                 // it, we know that the error was due to limited visibility
5686                                 //
5687                                 object lookup = TypeManager.MemberLookup (
5688                                         expr_type, expr_type, AllMemberTypes, AllBindingFlags |
5689                                         BindingFlags.NonPublic, Identifier);
5690                                 if (lookup == null)
5691                                         Error (117, "`" + expr_type + "' does not contain a " +
5692                                                "definition for `" + Identifier + "'");
5693                                 else if ((expr_type != ec.ContainerType) &&
5694                                          ec.ContainerType.IsSubclassOf (expr_type)){
5695
5696                                         // Although a derived class can access protected members of
5697                                         // its base class it cannot do so through an instance of the
5698                                         // base class (CS1540).  If the expr_type is a parent of the
5699                                         // ec.ContainerType and the lookup succeeds with the latter one,
5700                                         // then we are in this situation.
5701
5702                                         lookup = TypeManager.MemberLookup (
5703                                                 ec.ContainerType, ec.ContainerType, AllMemberTypes,
5704                                                 AllBindingFlags, Identifier);
5705
5706                                         if (lookup != null)
5707                                                 Error (1540, "Cannot access protected member `" +
5708                                                        expr_type + "." + Identifier + "' " +
5709                                                        "via a qualifier of type `" +
5710                                                        TypeManager.CSharpName (expr_type) + "'; the " +
5711                                                        "qualifier must be of type `" +
5712                                                        TypeManager.CSharpName (ec.ContainerType) + "' " +
5713                                                        "(or derived from it)");
5714                                         else
5715                                                 Error (122, "`" + expr_type + "." + Identifier + "' " +
5716                                                        "is inaccessible because of its protection level");
5717                                 } else
5718                                         Error (122, "`" + expr_type + "." + Identifier + "' " +
5719                                                "is inaccessible because of its protection level");
5720                                               
5721                                 return null;
5722                         }
5723
5724                         if (member_lookup is TypeExpr){
5725                                 member_lookup.Resolve (ec, ResolveFlags.Type);
5726                                 return member_lookup;
5727                         } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
5728                                 return null;
5729                         
5730                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
5731                         if (member_lookup == null)
5732                                 return null;
5733
5734                         // The following DoResolve/DoResolveLValue will do the definite assignment
5735                         // check.
5736
5737                         if (right_side != null)
5738                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
5739                         else
5740                                 member_lookup = member_lookup.DoResolve (ec);
5741
5742                         return member_lookup;
5743                 }
5744
5745                 public override Expression DoResolve (EmitContext ec)
5746                 {
5747                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
5748                                           ResolveFlags.SimpleName | ResolveFlags.Type);
5749                 }
5750
5751                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5752                 {
5753                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
5754                                           ResolveFlags.SimpleName | ResolveFlags.Type);
5755                 }
5756
5757                 public Expression DoResolveType (EmitContext ec)
5758                 {
5759                         return DoResolve (ec, null, ResolveFlags.Type);
5760                 }
5761
5762                 public override void Emit (EmitContext ec)
5763                 {
5764                         throw new Exception ("Should not happen");
5765                 }
5766
5767                 public override string ToString ()
5768                 {
5769                         return expr + "." + Identifier;
5770                 }
5771         }
5772
5773         /// <summary>
5774         ///   Implements checked expressions
5775         /// </summary>
5776         public class CheckedExpr : Expression {
5777
5778                 public Expression Expr;
5779
5780                 public CheckedExpr (Expression e, Location l)
5781                 {
5782                         Expr = e;
5783                         loc = l;
5784                 }
5785
5786                 public override Expression DoResolve (EmitContext ec)
5787                 {
5788                         bool last_const_check = ec.ConstantCheckState;
5789
5790                         ec.ConstantCheckState = true;
5791                         Expr = Expr.Resolve (ec);
5792                         ec.ConstantCheckState = last_const_check;
5793                         
5794                         if (Expr == null)
5795                                 return null;
5796
5797                         if (Expr is Constant)
5798                                 return Expr;
5799                         
5800                         eclass = Expr.eclass;
5801                         type = Expr.Type;
5802                         return this;
5803                 }
5804
5805                 public override void Emit (EmitContext ec)
5806                 {
5807                         bool last_check = ec.CheckState;
5808                         bool last_const_check = ec.ConstantCheckState;
5809                         
5810                         ec.CheckState = true;
5811                         ec.ConstantCheckState = true;
5812                         Expr.Emit (ec);
5813                         ec.CheckState = last_check;
5814                         ec.ConstantCheckState = last_const_check;
5815                 }
5816                 
5817         }
5818
5819         /// <summary>
5820         ///   Implements the unchecked expression
5821         /// </summary>
5822         public class UnCheckedExpr : Expression {
5823
5824                 public Expression Expr;
5825
5826                 public UnCheckedExpr (Expression e, Location l)
5827                 {
5828                         Expr = e;
5829                         loc = l;
5830                 }
5831
5832                 public override Expression DoResolve (EmitContext ec)
5833                 {
5834                         bool last_const_check = ec.ConstantCheckState;
5835
5836                         ec.ConstantCheckState = false;
5837                         Expr = Expr.Resolve (ec);
5838                         ec.ConstantCheckState = last_const_check;
5839
5840                         if (Expr == null)
5841                                 return null;
5842
5843                         if (Expr is Constant)
5844                                 return Expr;
5845                         
5846                         eclass = Expr.eclass;
5847                         type = Expr.Type;
5848                         return this;
5849                 }
5850
5851                 public override void Emit (EmitContext ec)
5852                 {
5853                         bool last_check = ec.CheckState;
5854                         bool last_const_check = ec.ConstantCheckState;
5855                         
5856                         ec.CheckState = false;
5857                         ec.ConstantCheckState = false;
5858                         Expr.Emit (ec);
5859                         ec.CheckState = last_check;
5860                         ec.ConstantCheckState = last_const_check;
5861                 }
5862                 
5863         }
5864
5865         /// <summary>
5866         ///   An Element Access expression.
5867         ///
5868         ///   During semantic analysis these are transformed into 
5869         ///   IndexerAccess or ArrayAccess 
5870         /// </summary>
5871         public class ElementAccess : Expression {
5872                 public ArrayList  Arguments;
5873                 public Expression Expr;
5874                 
5875                 public ElementAccess (Expression e, ArrayList e_list, Location l)
5876                 {
5877                         Expr = e;
5878
5879                         loc  = l;
5880                         
5881                         if (e_list == null)
5882                                 return;
5883                         
5884                         Arguments = new ArrayList ();
5885                         foreach (Expression tmp in e_list)
5886                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
5887                         
5888                 }
5889
5890                 bool CommonResolve (EmitContext ec)
5891                 {
5892                         Expr = Expr.Resolve (ec);
5893
5894                         if (Expr == null) 
5895                                 return false;
5896
5897                         if (Arguments == null)
5898                                 return false;
5899
5900                         foreach (Argument a in Arguments){
5901                                 if (!a.Resolve (ec, loc))
5902                                         return false;
5903                         }
5904
5905                         return true;
5906                 }
5907
5908                 Expression MakePointerAccess ()
5909                 {
5910                         Type t = Expr.Type;
5911
5912                         if (t == TypeManager.void_ptr_type){
5913                                 Error (
5914                                         242,
5915                                         "The array index operation is not valid for void pointers");
5916                                 return null;
5917                         }
5918                         if (Arguments.Count != 1){
5919                                 Error (
5920                                         196,
5921                                         "A pointer must be indexed by a single value");
5922                                 return null;
5923                         }
5924                         Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
5925                                                               t, loc);
5926                         return new Indirection (p, loc);
5927                 }
5928                 
5929                 public override Expression DoResolve (EmitContext ec)
5930                 {
5931                         if (!CommonResolve (ec))
5932                                 return null;
5933
5934                         //
5935                         // We perform some simple tests, and then to "split" the emit and store
5936                         // code we create an instance of a different class, and return that.
5937                         //
5938                         // I am experimenting with this pattern.
5939                         //
5940                         Type t = Expr.Type;
5941
5942                         if (t.IsArray)
5943                                 return (new ArrayAccess (this, loc)).Resolve (ec);
5944                         else if (t.IsPointer)
5945                                 return MakePointerAccess ();
5946                         else
5947                                 return (new IndexerAccess (this, loc)).Resolve (ec);
5948                 }
5949
5950                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5951                 {
5952                         if (!CommonResolve (ec))
5953                                 return null;
5954
5955                         Type t = Expr.Type;
5956                         if (t.IsArray)
5957                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
5958                         else if (t.IsPointer)
5959                                 return MakePointerAccess ();
5960                         else
5961                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
5962                 }
5963                 
5964                 public override void Emit (EmitContext ec)
5965                 {
5966                         throw new Exception ("Should never be reached");
5967                 }
5968         }
5969
5970         /// <summary>
5971         ///   Implements array access 
5972         /// </summary>
5973         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
5974                 //
5975                 // Points to our "data" repository
5976                 //
5977                 ElementAccess ea;
5978
5979                 LocalTemporary [] cached_locations;
5980                 
5981                 public ArrayAccess (ElementAccess ea_data, Location l)
5982                 {
5983                         ea = ea_data;
5984                         eclass = ExprClass.Variable;
5985                         loc = l;
5986                 }
5987
5988                 public override Expression DoResolve (EmitContext ec)
5989                 {
5990                         ExprClass eclass = ea.Expr.eclass;
5991
5992 #if false
5993                         // As long as the type is valid
5994                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
5995                               eclass == ExprClass.Value)) {
5996                                 ea.Expr.Error118 ("variable or value");
5997                                 return null;
5998                         }
5999 #endif
6000
6001                         Type t = ea.Expr.Type;
6002                         if (t.GetArrayRank () != ea.Arguments.Count){
6003                                 ea.Error (22,
6004                                           "Incorrect number of indexes for array " +
6005                                           " expected: " + t.GetArrayRank () + " got: " +
6006                                           ea.Arguments.Count);
6007                                 return null;
6008                         }
6009                         type = TypeManager.TypeToCoreType (t.GetElementType ());
6010                         if (type.IsPointer && !ec.InUnsafe){
6011                                 UnsafeError (ea.Location);
6012                                 return null;
6013                         }
6014
6015                         foreach (Argument a in ea.Arguments){
6016                                 Type argtype = a.Type;
6017
6018                                 if (argtype == TypeManager.int32_type ||
6019                                     argtype == TypeManager.uint32_type ||
6020                                     argtype == TypeManager.int64_type ||
6021                                     argtype == TypeManager.uint64_type)
6022                                         continue;
6023
6024                                 //
6025                                 // Mhm.  This is strage, because the Argument.Type is not the same as
6026                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
6027                                 //
6028                                 // Wonder if I will run into trouble for this.
6029                                 //
6030                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
6031                                 if (a.Expr == null)
6032                                         return null;
6033                         }
6034                         
6035                         eclass = ExprClass.Variable;
6036
6037                         return this;
6038                 }
6039
6040                 /// <summary>
6041                 ///    Emits the right opcode to load an object of Type `t'
6042                 ///    from an array of T
6043                 /// </summary>
6044                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
6045                 {
6046                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
6047                                 ig.Emit (OpCodes.Ldelem_U1);
6048                         else if (type == TypeManager.sbyte_type)
6049                                 ig.Emit (OpCodes.Ldelem_I1);
6050                         else if (type == TypeManager.short_type)
6051                                 ig.Emit (OpCodes.Ldelem_I2);
6052                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
6053                                 ig.Emit (OpCodes.Ldelem_U2);
6054                         else if (type == TypeManager.int32_type)
6055                                 ig.Emit (OpCodes.Ldelem_I4);
6056                         else if (type == TypeManager.uint32_type)
6057                                 ig.Emit (OpCodes.Ldelem_U4);
6058                         else if (type == TypeManager.uint64_type)
6059                                 ig.Emit (OpCodes.Ldelem_I8);
6060                         else if (type == TypeManager.int64_type)
6061                                 ig.Emit (OpCodes.Ldelem_I8);
6062                         else if (type == TypeManager.float_type)
6063                                 ig.Emit (OpCodes.Ldelem_R4);
6064                         else if (type == TypeManager.double_type)
6065                                 ig.Emit (OpCodes.Ldelem_R8);
6066                         else if (type == TypeManager.intptr_type)
6067                                 ig.Emit (OpCodes.Ldelem_I);
6068                         else if (type.IsValueType){
6069                                 ig.Emit (OpCodes.Ldelema, type);
6070                                 ig.Emit (OpCodes.Ldobj, type);
6071                         } else 
6072                                 ig.Emit (OpCodes.Ldelem_Ref);
6073                 }
6074
6075                 /// <summary>
6076                 ///    Emits the right opcode to store an object of Type `t'
6077                 ///    from an array of T.  
6078                 /// </summary>
6079                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
6080                 {
6081                         t = TypeManager.TypeToCoreType (t);
6082                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
6083                                 t = TypeManager.EnumToUnderlying (t);
6084                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
6085                             t == TypeManager.bool_type)
6086                                 ig.Emit (OpCodes.Stelem_I1);
6087                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
6088                                 ig.Emit (OpCodes.Stelem_I2);
6089                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
6090                                 ig.Emit (OpCodes.Stelem_I4);
6091                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
6092                                 ig.Emit (OpCodes.Stelem_I8);
6093                         else if (t == TypeManager.float_type)
6094                                 ig.Emit (OpCodes.Stelem_R4);
6095                         else if (t == TypeManager.double_type)
6096                                 ig.Emit (OpCodes.Stelem_R8);
6097                         else if (t == TypeManager.intptr_type)
6098                                 ig.Emit (OpCodes.Stelem_I);
6099                         else if (t.IsValueType){
6100                                 ig.Emit (OpCodes.Stobj, t);
6101                         } else
6102                                 ig.Emit (OpCodes.Stelem_Ref);
6103                 }
6104
6105                 MethodInfo FetchGetMethod ()
6106                 {
6107                         ModuleBuilder mb = CodeGen.ModuleBuilder;
6108                         int arg_count = ea.Arguments.Count;
6109                         Type [] args = new Type [arg_count];
6110                         MethodInfo get;
6111                         
6112                         for (int i = 0; i < arg_count; i++){
6113                                 //args [i++] = a.Type;
6114                                 args [i] = TypeManager.int32_type;
6115                         }
6116                         
6117                         get = mb.GetArrayMethod (
6118                                 ea.Expr.Type, "Get",
6119                                 CallingConventions.HasThis |
6120                                 CallingConventions.Standard,
6121                                 type, args);
6122                         return get;
6123                 }
6124                                 
6125
6126                 MethodInfo FetchAddressMethod ()
6127                 {
6128                         ModuleBuilder mb = CodeGen.ModuleBuilder;
6129                         int arg_count = ea.Arguments.Count;
6130                         Type [] args = new Type [arg_count];
6131                         MethodInfo address;
6132                         string ptr_type_name;
6133                         Type ret_type;
6134                         
6135                         ptr_type_name = type.FullName + "&";
6136                         ret_type = Type.GetType (ptr_type_name);
6137                         
6138                         //
6139                         // It is a type defined by the source code we are compiling
6140                         //
6141                         if (ret_type == null){
6142                                 ret_type = mb.GetType (ptr_type_name);
6143                         }
6144
6145                         for (int i = 0; i < arg_count; i++){
6146                                 //args [i++] = a.Type;
6147                                 args [i] = TypeManager.int32_type;
6148                         }
6149                         
6150                         address = mb.GetArrayMethod (
6151                                 ea.Expr.Type, "Address",
6152                                 CallingConventions.HasThis |
6153                                 CallingConventions.Standard,
6154                                 ret_type, args);
6155
6156                         return address;
6157                 }
6158
6159                 //
6160                 // Load the array arguments into the stack.
6161                 //
6162                 // If we have been requested to cache the values (cached_locations array
6163                 // initialized), then load the arguments the first time and store them
6164                 // in locals.  otherwise load from local variables.
6165                 //
6166                 void LoadArrayAndArguments (EmitContext ec)
6167                 {
6168                         ILGenerator ig = ec.ig;
6169                         
6170                         if (cached_locations == null){
6171                                 ea.Expr.Emit (ec);
6172                                 foreach (Argument a in ea.Arguments){
6173                                         Type argtype = a.Expr.Type;
6174                                         
6175                                         a.Expr.Emit (ec);
6176                                         
6177                                         if (argtype == TypeManager.int64_type)
6178                                                 ig.Emit (OpCodes.Conv_Ovf_I);
6179                                         else if (argtype == TypeManager.uint64_type)
6180                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6181                                 }
6182                                 return;
6183                         }
6184
6185                         if (cached_locations [0] == null){
6186                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
6187                                 ea.Expr.Emit (ec);
6188                                 ig.Emit (OpCodes.Dup);
6189                                 cached_locations [0].Store (ec);
6190                                 
6191                                 int j = 1;
6192                                 
6193                                 foreach (Argument a in ea.Arguments){
6194                                         Type argtype = a.Expr.Type;
6195                                         
6196                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
6197                                         a.Expr.Emit (ec);
6198                                         if (argtype == TypeManager.int64_type)
6199                                                 ig.Emit (OpCodes.Conv_Ovf_I);
6200                                         else if (argtype == TypeManager.uint64_type)
6201                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6202
6203                                         ig.Emit (OpCodes.Dup);
6204                                         cached_locations [j].Store (ec);
6205                                         j++;
6206                                 }
6207                                 return;
6208                         }
6209
6210                         foreach (LocalTemporary lt in cached_locations)
6211                                 lt.Emit (ec);
6212                 }
6213
6214                 public new void CacheTemporaries (EmitContext ec)
6215                 {
6216                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
6217                 }
6218                 
6219                 public override void Emit (EmitContext ec)
6220                 {
6221                         int rank = ea.Expr.Type.GetArrayRank ();
6222                         ILGenerator ig = ec.ig;
6223
6224                         LoadArrayAndArguments (ec);
6225                         
6226                         if (rank == 1)
6227                                 EmitLoadOpcode (ig, type);
6228                         else {
6229                                 MethodInfo method;
6230                                 
6231                                 method = FetchGetMethod ();
6232                                 ig.Emit (OpCodes.Call, method);
6233                         }
6234                 }
6235
6236                 public void EmitAssign (EmitContext ec, Expression source)
6237                 {
6238                         int rank = ea.Expr.Type.GetArrayRank ();
6239                         ILGenerator ig = ec.ig;
6240                         Type t = source.Type;
6241
6242                         LoadArrayAndArguments (ec);
6243
6244                         //
6245                         // The stobj opcode used by value types will need
6246                         // an address on the stack, not really an array/array
6247                         // pair
6248                         //
6249                         if (rank == 1){
6250                                 if (t.IsSubclassOf (TypeManager.value_type) && (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
6251                                         ig.Emit (OpCodes.Ldelema, t);
6252                         }
6253                         
6254                         source.Emit (ec);
6255
6256                         if (rank == 1)
6257                                 EmitStoreOpcode (ig, t);
6258                         else {
6259                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6260                                 int arg_count = ea.Arguments.Count;
6261                                 Type [] args = new Type [arg_count + 1];
6262                                 MethodInfo set;
6263                                 
6264                                 for (int i = 0; i < arg_count; i++){
6265                                         //args [i++] = a.Type;
6266                                         args [i] = TypeManager.int32_type;
6267                                 }
6268
6269                                 args [arg_count] = type;
6270                                 
6271                                 set = mb.GetArrayMethod (
6272                                         ea.Expr.Type, "Set",
6273                                         CallingConventions.HasThis |
6274                                         CallingConventions.Standard,
6275                                         TypeManager.void_type, args);
6276                                 
6277                                 ig.Emit (OpCodes.Call, set);
6278                         }
6279                 }
6280
6281                 public void AddressOf (EmitContext ec, AddressOp mode)
6282                 {
6283                         int rank = ea.Expr.Type.GetArrayRank ();
6284                         ILGenerator ig = ec.ig;
6285
6286                         LoadArrayAndArguments (ec);
6287
6288                         if (rank == 1){
6289                                 ig.Emit (OpCodes.Ldelema, type);
6290                         } else {
6291                                 MethodInfo address = FetchAddressMethod ();
6292                                 ig.Emit (OpCodes.Call, address);
6293                         }
6294                 }
6295         }
6296
6297         
6298         class Indexers {
6299                 public ArrayList getters, setters;
6300                 static Hashtable map;
6301
6302                 static Indexers ()
6303                 {
6304                         map = new Hashtable ();
6305                 }
6306
6307                 Indexers (MemberInfo [] mi)
6308                 {
6309                         foreach (PropertyInfo property in mi){
6310                                 MethodInfo get, set;
6311                                 
6312                                 get = property.GetGetMethod (true);
6313                                 if (get != null){
6314                                         if (getters == null)
6315                                                 getters = new ArrayList ();
6316
6317                                         getters.Add (get);
6318                                 }
6319                                 
6320                                 set = property.GetSetMethod (true);
6321                                 if (set != null){
6322                                         if (setters == null)
6323                                                 setters = new ArrayList ();
6324                                         setters.Add (set);
6325                                 }
6326                         }
6327                 }
6328
6329                 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
6330                 {
6331                         Indexers ix = (Indexers) map [lookup_type];
6332                         
6333                         if (ix != null)
6334                                 return ix;
6335
6336                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
6337
6338                         MemberInfo [] mi = TypeManager.MemberLookup (
6339                                 caller_type, lookup_type, MemberTypes.Property,
6340                                 BindingFlags.Public | BindingFlags.Instance, p_name);
6341
6342                         if (mi == null || mi.Length == 0)
6343                                 return null;
6344
6345                         ix = new Indexers (mi);
6346                         map [lookup_type] = ix;
6347
6348                         return ix;
6349                 }
6350                 
6351                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
6352                 {
6353                         Indexers ix = (Indexers) map [lookup_type];
6354                         
6355                         if (ix != null)
6356                                 return ix;
6357
6358                         ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
6359                         if (ix != null)
6360                                 return ix;
6361
6362                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
6363                         if (ifaces != null) {
6364                                 foreach (Type itype in ifaces) {
6365                                         ix = GetIndexersForTypeOrInterface (caller_type, itype);
6366                                         if (ix != null)
6367                                                 return ix;
6368                                 }
6369                         }
6370
6371                         Report.Error (21, loc,
6372                                       "Type `" + TypeManager.CSharpName (lookup_type) +
6373                                       "' does not have any indexers defined");
6374                         return null;
6375                 }
6376         }
6377
6378         /// <summary>
6379         ///   Expressions that represent an indexer call.
6380         /// </summary>
6381         public class IndexerAccess : Expression, IAssignMethod {
6382                 //
6383                 // Points to our "data" repository
6384                 //
6385                 MethodInfo get, set;
6386                 Indexers ilist;
6387                 ArrayList set_arguments;
6388                 bool is_base_indexer;
6389
6390                 protected Type indexer_type;
6391                 protected Type current_type;
6392                 protected Expression instance_expr;
6393                 protected ArrayList arguments;
6394                 
6395                 public IndexerAccess (ElementAccess ea, Location loc)
6396                         : this (ea.Expr, false, loc)
6397                 {
6398                         this.arguments = ea.Arguments;
6399                 }
6400
6401                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
6402                                          Location loc)
6403                 {
6404                         this.instance_expr = instance_expr;
6405                         this.is_base_indexer = is_base_indexer;
6406                         this.eclass = ExprClass.Value;
6407                         this.loc = loc;
6408                 }
6409
6410                 protected virtual bool CommonResolve (EmitContext ec)
6411                 {
6412                         indexer_type = instance_expr.Type;
6413                         current_type = ec.ContainerType;
6414
6415                         return true;
6416                 }
6417
6418                 public override Expression DoResolve (EmitContext ec)
6419                 {
6420                         if (!CommonResolve (ec))
6421                                 return null;
6422
6423                         //
6424                         // Step 1: Query for all `Item' *properties*.  Notice
6425                         // that the actual methods are pointed from here.
6426                         //
6427                         // This is a group of properties, piles of them.  
6428
6429                         if (ilist == null)
6430                                 ilist = Indexers.GetIndexersForType (
6431                                         current_type, indexer_type, loc);
6432
6433                         //
6434                         // Step 2: find the proper match
6435                         //
6436                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
6437                                 get = (MethodInfo) Invocation.OverloadResolve (
6438                                         ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
6439
6440                         if (get == null){
6441                                 Error (154, "indexer can not be used in this context, because " +
6442                                        "it lacks a `get' accessor");
6443                                 return null;
6444                         }
6445
6446                         type = get.ReturnType;
6447                         if (type.IsPointer && !ec.InUnsafe){
6448                                 UnsafeError (loc);
6449                                 return null;
6450                         }
6451                         
6452                         eclass = ExprClass.IndexerAccess;
6453                         return this;
6454                 }
6455
6456                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6457                 {
6458                         if (!CommonResolve (ec))
6459                                 return null;
6460
6461                         Type right_type = right_side.Type;
6462
6463                         if (ilist == null)
6464                                 ilist = Indexers.GetIndexersForType (
6465                                         current_type, indexer_type, loc);
6466
6467                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
6468                                 set_arguments = (ArrayList) arguments.Clone ();
6469                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
6470
6471                                 set = (MethodInfo) Invocation.OverloadResolve (
6472                                         ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
6473                         }
6474                         
6475                         if (set == null){
6476                                 Error (200, "indexer X.this [" + TypeManager.CSharpName (right_type) +
6477                                        "] lacks a `set' accessor");
6478                                 return null;
6479                         }
6480
6481                         type = TypeManager.void_type;
6482                         eclass = ExprClass.IndexerAccess;
6483                         return this;
6484                 }
6485                 
6486                 public override void Emit (EmitContext ec)
6487                 {
6488                         Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
6489                 }
6490
6491                 //
6492                 // source is ignored, because we already have a copy of it from the
6493                 // LValue resolution and we have already constructed a pre-cached
6494                 // version of the arguments (ea.set_arguments);
6495                 //
6496                 public void EmitAssign (EmitContext ec, Expression source)
6497                 {
6498                         Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
6499                 }
6500         }
6501
6502         /// <summary>
6503         ///   The base operator for method names
6504         /// </summary>
6505         public class BaseAccess : Expression {
6506                 string member;
6507                 
6508                 public BaseAccess (string member, Location l)
6509                 {
6510                         this.member = member;
6511                         loc = l;
6512                 }
6513
6514                 public override Expression DoResolve (EmitContext ec)
6515                 {
6516                         Expression member_lookup;
6517                         Type current_type = ec.ContainerType;
6518                         Type base_type = current_type.BaseType;
6519                         Expression e;
6520
6521                         if (ec.IsStatic){
6522                                 Error (1511,
6523                                               "Keyword base is not allowed in static method");
6524                                 return null;
6525                         }
6526                         
6527                         member_lookup = MemberLookup (ec, base_type, base_type, member,
6528                                                       AllMemberTypes, AllBindingFlags, loc);
6529                         if (member_lookup == null) {
6530                                 Error (117,
6531                                               TypeManager.CSharpName (base_type) + " does not " +
6532                                               "contain a definition for `" + member + "'");
6533                                 return null;
6534                         }
6535
6536                         Expression left;
6537                         
6538                         if (ec.IsStatic)
6539                                 left = new TypeExpr (base_type, loc);
6540                         else
6541                                 left = ec.This;
6542                         
6543                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
6544
6545                         if (e is PropertyExpr){
6546                                 PropertyExpr pe = (PropertyExpr) e;
6547
6548                                 pe.IsBase = true;
6549                         }
6550
6551                         return e;
6552                 }
6553
6554                 public override void Emit (EmitContext ec)
6555                 {
6556                         throw new Exception ("Should never be called"); 
6557                 }
6558         }
6559
6560         /// <summary>
6561         ///   The base indexer operator
6562         /// </summary>
6563         public class BaseIndexerAccess : IndexerAccess {
6564                 public BaseIndexerAccess (ArrayList args, Location loc)
6565                         : base (null, true, loc)
6566                 {
6567                         arguments = new ArrayList ();
6568                         foreach (Expression tmp in args)
6569                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
6570                 }
6571
6572                 protected override bool CommonResolve (EmitContext ec)
6573                 {
6574                         instance_expr = ec.This;
6575
6576                         current_type = ec.ContainerType.BaseType;
6577                         indexer_type = current_type;
6578
6579                         foreach (Argument a in arguments){
6580                                 if (!a.Resolve (ec, loc))
6581                                         return false;
6582                         }
6583
6584                         return true;
6585                 }
6586         }
6587         
6588         /// <summary>
6589         ///   This class exists solely to pass the Type around and to be a dummy
6590         ///   that can be passed to the conversion functions (this is used by
6591         ///   foreach implementation to typecast the object return value from
6592         ///   get_Current into the proper type.  All code has been generated and
6593         ///   we only care about the side effect conversions to be performed
6594         ///
6595         ///   This is also now used as a placeholder where a no-action expression
6596         ///   is needed (the `New' class).
6597         /// </summary>
6598         public class EmptyExpression : Expression {
6599                 public EmptyExpression ()
6600                 {
6601                         type = TypeManager.object_type;
6602                         eclass = ExprClass.Value;
6603                         loc = Location.Null;
6604                 }
6605
6606                 public EmptyExpression (Type t)
6607                 {
6608                         type = t;
6609                         eclass = ExprClass.Value;
6610                         loc = Location.Null;
6611                 }
6612                 
6613                 public override Expression DoResolve (EmitContext ec)
6614                 {
6615                         return this;
6616                 }
6617
6618                 public override void Emit (EmitContext ec)
6619                 {
6620                         // nothing, as we only exist to not do anything.
6621                 }
6622
6623                 //
6624                 // This is just because we might want to reuse this bad boy
6625                 // instead of creating gazillions of EmptyExpressions.
6626                 // (CanConvertImplicit uses it)
6627                 //
6628                 public void SetType (Type t)
6629                 {
6630                         type = t;
6631                 }
6632         }
6633
6634         public class UserCast : Expression {
6635                 MethodBase method;
6636                 Expression source;
6637                 
6638                 public UserCast (MethodInfo method, Expression source, Location l)
6639                 {
6640                         this.method = method;
6641                         this.source = source;
6642                         type = method.ReturnType;
6643                         eclass = ExprClass.Value;
6644                         loc = l;
6645                 }
6646
6647                 public override Expression DoResolve (EmitContext ec)
6648                 {
6649                         //
6650                         // We are born fully resolved
6651                         //
6652                         return this;
6653                 }
6654
6655                 public override void Emit (EmitContext ec)
6656                 {
6657                         ILGenerator ig = ec.ig;
6658
6659                         source.Emit (ec);
6660                         
6661                         if (method is MethodInfo)
6662                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
6663                         else
6664                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6665
6666                 }
6667         }
6668
6669         // <summary>
6670         //   This class is used to "construct" the type during a typecast
6671         //   operation.  Since the Type.GetType class in .NET can parse
6672         //   the type specification, we just use this to construct the type
6673         //   one bit at a time.
6674         // </summary>
6675         public class ComposedCast : Expression, ITypeExpression {
6676                 Expression left;
6677                 string dim;
6678                 
6679                 public ComposedCast (Expression left, string dim, Location l)
6680                 {
6681                         this.left = left;
6682                         this.dim = dim;
6683                         loc = l;
6684                 }
6685
6686                 public Expression DoResolveType (EmitContext ec)
6687                 {
6688                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
6689                         if (ltype == null)
6690                                 return null;
6691
6692                         //
6693                         // ltype.Fullname is already fully qualified, so we can skip
6694                         // a lot of probes, and go directly to TypeManager.LookupType
6695                         //
6696                         string cname = ltype.FullName + dim;
6697                         type = TypeManager.LookupTypeDirect (cname);
6698                         if (type == null){
6699                                 //
6700                                 // For arrays of enumerations we are having a problem
6701                                 // with the direct lookup.  Need to investigate.
6702                                 //
6703                                 // For now, fall back to the full lookup in that case.
6704                                 //
6705                                 type = RootContext.LookupType (
6706                                         ec.DeclSpace, cname, false, loc);
6707
6708                                 if (type == null)
6709                                         return null;
6710                         }
6711
6712                         if (!ec.ResolvingTypeTree){
6713                                 //
6714                                 // If the above flag is set, this is being invoked from the ResolveType function.
6715                                 // Upper layers take care of the type validity in this context.
6716                                 //
6717                         if (!ec.InUnsafe && type.IsPointer){
6718                                 UnsafeError (loc);
6719                                 return null;
6720                         }
6721                         }
6722                         
6723                         eclass = ExprClass.Type;
6724                         return this;
6725                 }
6726
6727                 public override Expression DoResolve (EmitContext ec)
6728                 {
6729                         return DoResolveType (ec);
6730                 }
6731
6732                 public override void Emit (EmitContext ec)
6733                 {
6734                         throw new Exception ("This should never be called");
6735                 }
6736
6737                 public override string ToString ()
6738                 {
6739                         return left + dim;
6740                 }
6741         }
6742
6743         //
6744         // This class is used to represent the address of an array, used
6745         // only by the Fixed statement, this is like the C "&a [0]" construct.
6746         //
6747         public class ArrayPtr : Expression {
6748                 Expression array;
6749                 
6750                 public ArrayPtr (Expression array, Location l)
6751                 {
6752                         Type array_type = array.Type.GetElementType ();
6753
6754                         this.array = array;
6755                         
6756                         string array_ptr_type_name = array_type.FullName + "*";
6757                         
6758                         type = Type.GetType (array_ptr_type_name);
6759                         if (type == null){
6760                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6761                                 
6762                                 type = mb.GetType (array_ptr_type_name);
6763                         }
6764
6765                         eclass = ExprClass.Value;
6766                         loc = l;
6767                 }
6768
6769                 public override void Emit (EmitContext ec)
6770                 {
6771                         ILGenerator ig = ec.ig;
6772                         
6773                         array.Emit (ec);
6774                         IntLiteral.EmitInt (ig, 0);
6775                         ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
6776                 }
6777
6778                 public override Expression DoResolve (EmitContext ec)
6779                 {
6780                         //
6781                         // We are born fully resolved
6782                         //
6783                         return this;
6784                 }
6785         }
6786
6787         //
6788         // Used by the fixed statement
6789         //
6790         public class StringPtr : Expression {
6791                 LocalBuilder b;
6792                 
6793                 public StringPtr (LocalBuilder b, Location l)
6794                 {
6795                         this.b = b;
6796                         eclass = ExprClass.Value;
6797                         type = TypeManager.char_ptr_type;
6798                         loc = l;
6799                 }
6800
6801                 public override Expression DoResolve (EmitContext ec)
6802                 {
6803                         // This should never be invoked, we are born in fully
6804                         // initialized state.
6805
6806                         return this;
6807                 }
6808
6809                 public override void Emit (EmitContext ec)
6810                 {
6811                         ILGenerator ig = ec.ig;
6812
6813                         ig.Emit (OpCodes.Ldloc, b);
6814                         ig.Emit (OpCodes.Conv_I);
6815                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
6816                         ig.Emit (OpCodes.Add);
6817                 }
6818         }
6819         
6820         //
6821         // Implements the `stackalloc' keyword
6822         //
6823         public class StackAlloc : Expression {
6824                 Type otype;
6825                 Expression t;
6826                 Expression count;
6827                 
6828                 public StackAlloc (Expression type, Expression count, Location l)
6829                 {
6830                         t = type;
6831                         this.count = count;
6832                         loc = l;
6833                 }
6834
6835                 public override Expression DoResolve (EmitContext ec)
6836                 {
6837                         count = count.Resolve (ec);
6838                         if (count == null)
6839                                 return null;
6840                         
6841                         if (count.Type != TypeManager.int32_type){
6842                                 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
6843                                 if (count == null)
6844                                         return null;
6845                         }
6846
6847                         if (ec.InCatch || ec.InFinally){
6848                                 Error (255,
6849                                               "stackalloc can not be used in a catch or finally block");
6850                                 return null;
6851                         }
6852
6853                         otype = ec.DeclSpace.ResolveType (t, false, loc);
6854
6855                         if (otype == null)
6856                                 return null;
6857
6858                         if (!TypeManager.VerifyUnManaged (otype, loc))
6859                                 return null;
6860
6861                         string ptr_name = otype.FullName + "*";
6862                         type = Type.GetType (ptr_name);
6863                         if (type == null){
6864                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6865                                 
6866                                 type = mb.GetType (ptr_name);
6867                         }
6868                         eclass = ExprClass.Value;
6869
6870                         return this;
6871                 }
6872
6873                 public override void Emit (EmitContext ec)
6874                 {
6875                         int size = GetTypeSize (otype);
6876                         ILGenerator ig = ec.ig;
6877                                 
6878                         if (size == 0)
6879                                 ig.Emit (OpCodes.Sizeof, otype);
6880                         else
6881                                 IntConstant.EmitInt (ig, size);
6882                         count.Emit (ec);
6883                         ig.Emit (OpCodes.Mul);
6884                         ig.Emit (OpCodes.Localloc);
6885                 }
6886         }
6887 }