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