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