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