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