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